DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> JavaScript入門知識 >> 關於JavaScript >> JavaScript教程:網頁浮動定位提示效果
JavaScript教程:網頁浮動定位提示效果
編輯:關於JavaScript     

網頁制作poluoluo文章簡介:本來想做一個集合浮動定位和鼠標跟隨的tooltips效果,但發現定位和鼠標跟隨在一些關鍵的地方還是不同的,還是分開來吧。

本來想做一個集合浮動定位和鼠標跟隨的tooltips效果,但發現定位和鼠標跟隨在一些關鍵的地方還是不同的,還是分開來吧。
這個效果本身難度不大,主要在程序結構和擴展中下了些功夫,務求用起來更方便,能用在更多的地方。

程序特點

  1. 同一個提示框用在多個觸發元素時,只需一個實例;
  2. 顯示和隱藏分別有點擊方式和觸發方式選擇;
  3. 能設置延時顯示和隱藏;
  4. 有25種預設定位位置;
  5. 可在預設定位基礎上,再自定義定位;
  6. 可設置自適應窗口定位;

完整實例下載(點擊下載)

運行代碼框

[Ctrl+A 全部選擇 提示:你可先修改部分代碼,再按運行]

JavaScript,定位,浮動,提示,tooltips,FixedTips,Tip
程序說明

Tip對象

Tip對象就是用來顯示提示信息的容器,程序用Tip屬性表示。這個沒什麼要求,程序初始化時會對它進行一些設置。
首先進行下面設置:

this._cssTip.margin = 0;
this._cssTip.position = "absolute";
this._cssTip.visibility = "hidden";
this._cssTip.display = "block";
this._cssTip.zIndex = 99;
this._cssTip.left = this._cssTip.top = "-9999px";

其中margin設為0是為了避免一些定位問題,用visibility來隱藏而不是display是因為程序需要獲取Tip的offsetWidth、offsetHeight,還需要設置left和top是避免因Tip占位出現的滾動條。
因為Tip可能會在其他定位元素裡面,所以還要設兩個offset修正參數:

var iLeft = iTop = 0, p = this.Tip.offsetParent;
while (!(p === document.body || p === document.documentElement)) {
    iLeft += p.offsetLeft; iTop += p.offsetTop; p = p.offsetParent;
};
this._offsetleft = iLeft;
this._offsettop = iTop;

最後給Tip的mouseover加一個事件,具體後面再說明。

網頁制作poluoluo文章簡介:本來想做一個集合浮動定位和鼠標跟隨的tooltips效果,但發現定位和鼠標跟隨在一些關鍵的地方還是不同的,還是分開來吧。

 

觸發對象

由於很多情況下都是一個Tip對應多個地方的提示,所以程序參考了 Table排序 的方式,添加了一個Add方法。
一個Tip實例化後,再用Add方法就可以對多個觸發元素分別添加觸發對象,程序中用_trigger屬性表示當前的觸發對象。
Add方法的一個必要參數是觸發元素,就是觸發顯示Tip的元素。
需要的話還可以用options參數,來自定義觸發對象的屬性,包括:

屬性:  默認值//說明
ClickShow:  true,//是否點擊方式顯示
ClickShowDelay: false,//是否點擊顯示延時
ClickHide:  true,//是否點擊方式隱藏
ClickHideDelay: false,//是否點擊隱藏延時
TouchShow:  true,//是否觸發方式顯示
TouchShowDelay: true,//是否觸發顯示延時
TouchHide:  true,//是否觸發方式隱藏
TouchHideDelay: true,//是否觸發隱藏延時
ShowDelay:  300,//顯示延時時間
HideDelay:  300,//隱藏延時時間
vAlign:  "clienttop",//垂直方向定位
Align:  "left",//水平方向定位
Custom:  { left: 0, top: 0 },//自定義定位
Percent:  { left: 0, top: 0 },//自定義百分比定位
Adaptive:  true,//是否自適應定位
onShow:  function(){},//顯示時執行
onHide:  function(){}//隱藏時執行

具體作用後面再說明,可以在程序初始化時修改這些默認值。
一個經典應用是在onShow中把Tip修改為各個觸發對象對應的內容。
此外還有Elem屬性保存觸發元素。

顯示和隱藏

提示效果的一個重點就是顯示和隱藏提示信息。程序是通過設置Tip的visibility是否hidden來顯示和隱藏Tip的。
具體的顯示和隱藏程序分別在Show和Hide程序中,還有ReadyShow和ReadyHide程序,主要用來處理延時。

這種提示效果的一個特點是鼠標移動到Tip上時,會保持顯示狀態。
為了實現這個效果,給Tip的mouseover寫入程序:

this.Check(e.relatedTarget) && clearTimeout(this._timer);

其中Check程序是用來判斷relatedTarget是不外部元素,即鼠標離開的元素是不是外部元素。
如果是外部元素,就說明當前是隱藏延時階段,那麼只要清除定時器來取消隱藏就可以了。

這裡的外部元素是指觸發元素和Tip對象本身及其內部元素以外的元素。
這個有點拗口,那再看看Check程序是怎麼判斷的就明白了:

return !this._trigger ||
    !(
        this.Tip === elem || this._trigger.Elem === elem ||
        Contains(this.Tip, elem) || Contains(this._trigger.Elem, elem)
    );

首先判斷_trigger是否存在,不存在的話說明是剛開始觸發,也看成是外部觸發。
存在的話再判斷傳遞過來的元素是不是Tip或觸發元素本身,最後再用Contains判斷判斷是不是在Tip或觸發元素內部。
ps:關於Contains請參考這裡的比較文檔位置。
這樣得到的是判斷是否內部元素,最後取反就是判斷是否外部元素了。

網頁制作poluoluo文章簡介:本來想做一個集合浮動定位和鼠標跟隨的tooltips效果,但發現定位和鼠標跟隨在一些關鍵的地方還是不同的,還是分開來吧。

點擊方式

點擊方式顯示是指點擊觸發元素的時候顯示Tip。
在Add程序中會給觸發元素的click事件綁定以下程序:

addEvent(elem, "click", BindAsEventListener(this, function(e){
    if (trigger.ClickShow) {
        if (this.CheckShow(trigger)) {
            this.ReadyShow(trigger.ClickShowDelay);
        } else {
            clearTimeout(this._timer);
        };
    };
}));

首先根據ClickShow判斷是否進行點擊顯示,再用CheckShow檢測是否同一個觸發對象。

CheckShow程序是這樣的:

if (trigger !== this._trigger) {
    this.Hide(); this._trigger = trigger; return true;
} else { return false; };

如果不是同一個觸發對象,就先執行Hide清理前一個觸發對象,防止沖突,再執行ReadyShow來顯示。
如果是同一個觸發對象,就說明當前是延時隱藏階段,清除定時器保持顯示狀態就行了。

對應的,點擊方式隱藏是指點擊外部元素的時候隱藏Tip。
在ReadyShow裡,當ClickHide為true時,就會把_fCH綁定到document的click事件裡:

trigger.ClickHide && addEvent(document, "click", this._fCH);

注意這裡要把隱藏綁定事件放到ReadyShow,而不是Show裡面,因為延時的時候有可能還沒有顯示就觸發了隱藏事件。

其中_fCH是在初始化時定義的一個屬性,用於添加和移除點擊隱藏事件:

this._fCH = BindAsEventListener(this, function(e) {
    if (this.Check(e.target) && this.CheckHide()) {
        this.ReadyHide(this._trigger.ClickHideDelay);
    }
});

注意不同於點擊顯示,由於綁定的是document,隱藏前要先確定e.target是不是外部元素。

其中CheckHide是作用是檢查Tip當前是不是隱藏狀態:

if (this._cssTip.visibility === "hidden") {
    clearTimeout(this._timer);
    removeEvent(this._trigger.Elem, "mouseout", this._fTH);
    this._trigger = null;
    removeEvent(document, "click", this._fCH);
    return false;
} else { return true; };

如果本來就是隱藏狀態,清除定時器移除事件就行,不需要再執行Hide了。

網頁制作poluoluo文章簡介:本來想做一個集合浮動定位和鼠標跟隨的tooltips效果,但發現定位和鼠標跟隨在一些關鍵的地方還是不同的,還是分開來吧。

 

觸發方式

觸發方式針對的是mouseover和mouseout,它的流程跟點擊方式是差不多的。

觸發方式顯示是指鼠標從外部元素進入觸發元素(觸發mouseover)的時候顯示Tip。

在Add程序中會給觸發元素的mouseover事件綁定以下程序:

addEvent(elem, "mouseover", BindAsEventListener(this, function(e){
    if (trigger.TouchShow) {
        if (this.CheckShow(trigger)) {
            this.ReadyShow(trigger.TouchShowDelay);
        } else if (this.Check(e.relatedTarget)) {
            clearTimeout(this._timer);
        };
    };
}));

跟點擊方式類似,也需要執行一次CheckShow,但不同的是,還會用Check判斷e.relatedTarget是不是外部對象。
這是因為mouseover可能是從觸發元素的內部元素(包括Tip)進入或內部元素冒泡觸發的,而這些情況不需要任何操作。

對應的,觸發方式隱藏是指鼠標從觸發元素或Tip離開時隱藏Tip。
當TouchHide為true時,在ReadyShow的時候會把_fTH綁定到觸發元素的mouseout事件裡:

trigger.TouchHide && addEvent(this._trigger.Elem, "mouseout", this._fTH);

在Show的時候,再綁定到Tip的mouseout:

trigger.TouchHide && addEvent(this.Tip, "mouseout", this._fTH);

在ReadyShow綁定的原因同上,而Tip只需顯示時綁定。

其中_fTH跟_fCH類似,也是在初始化時定義的一個屬性,用於添加和移除觸發隱藏事件:

this._fTH = BindAsEventListener(this, function(e) {
    if (this.Check(e.relatedTarget) && this.CheckHide()) {
        this.ReadyHide(this._trigger.TouchHideDelay);
    }
});

不同的是mouseout在Check的時候是用e.relatedTarget。

觸發原理

上面是從程序的角度說明了觸發顯示和隱藏的過程,但要真正理解的話還需要做一次細致的分析。
下面是以觸發方式的顯示隱藏為例做的流程圖:

下面是文字說明:

  1. 等待觸發顯示;
  2. 進入觸發元素,如果設置延時,跳到3,如果沒有設置延時,跳到4;
  3. 延時時間內,離開到外部元素,清除定時器,返回1,超過延時時間,跳到4;
  4. 執行顯示程序;
  5. 顯示Tip狀態;
  6. 離開觸發元素,如果是進入到Tip,跳到7,如果是離開到外部元素,跳到9;
  7. 保持顯示狀態;
  8. 離開Tip,如果是進入觸發元素,返回5,如果是離開到外部元素,跳到9;
  9. 如果設置延時,跳到10,如果沒有設置延時,跳到11;
  10. 延時時間內,如果進入Tip,清除定時器,返回7,如果進入觸發元素,清除定時器,返回5,超過延時時間,跳到11;
  11. 執行隱藏程序,返回1;

再對照程序,應該就能理解整個流程了,當然可能還不是那麼好理解。
這個流程也只是單例的情況,多例的時候還要多加一些判斷。
可以說這個流程看似不難,但如果想做一個最優化的流程,那要考慮的細節地方可能會讓人受不了。
點擊方式跟觸發方式的流程是差不多的,而且更簡單,這裡就不重復了。

網頁制作poluoluo文章簡介:本來想做一個集合浮動定位和鼠標跟隨的tooltips效果,但發現定位和鼠標跟隨在一些關鍵的地方還是不同的,還是分開來吧。

 

元素定位

完成了顯示隱藏,就到本程序另一個重點,元素定位。
程序包括這幾個定位:預設定位,自定義定位,自適應定位。
而定位的最終效果是結合了這幾個定位設置的效果,下面再一一分析。

預設定位和自定義定位

預設定位的意思是使用程序25個預設位置來定位。
25個位置是怎麼來的呢?看下面的演示

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25

 

其中黑色框代表觸發元素,紅色框代表Tip。
一眼望去,要實現這麼多的位置好像很復雜,這時要想找到最好的方法就要細心分析找出規律。
這25個位置其實都是由5個水平坐標和5個垂直坐標組合而來的,只要計算好這10個坐標,就能組合出這25個位置來了。
其中1,2,3,4,5代表的水平坐標,程序分別用left,clientleft,center,clientright,right來標識。
而1,6,11,16,21代表的垂直坐標,程序分別用top,clienttop,center,clientbottom,bottom來標識。
ps:詞窮,只好加個client來充數。

下面說說如何獲取這些坐標的值,首先通過getBoundingClientRect要獲取觸發元素的坐標對象。
ps:關於getBoundingClientRect的介紹請看 這裡的元素位置。
再利用這個坐標對像,通過GetLeft和GetTop來獲取水平和垂直坐標。
GetLeft和GetTop裡面都是些簡單的獲取坐標算法,具體請參考代碼。

使用時,把水平坐標和垂直坐標的標識值(字符)分別賦給觸發對象的Align和vAlign屬性,系統就會自動設置對應的位置。
例如要設置位置14,那麼Align設為"clientright",vAlign設為"center"就可以了。

至於自定義定位就是在預設定位得到的坐標基礎上,根據Custom(形式如{ left: 50, top: -10 })的設置再進行left和top的修正。
自定義百分比定位是以觸發元素的寬和高為基准,取百分比:

if (trigger.Percent.left) { iLeft += .01 * trigger.Percent.left * trigger.Elem.offsetWidth; };
if (trigger.Percent.top) { iTop += .01 * trigger.Percent.top * trigger.Elem.offsetHeight; };

注意數值單位是0.01。

網頁制作poluoluo文章簡介:本來想做一個集合浮動定位和鼠標跟隨的tooltips效果,但發現定位和鼠標跟隨在一些關鍵的地方還是不同的,還是分開來吧。

 

自適應定位

自適應定位的作用是當Tip顯示的范圍超過浏覽器可視范圍的時候,自動修正到可視范圍裡面。
因為上面通過getBoundingClientRect獲取的定位是以視窗為准的,所以可以直接通過clientWidth/clientHeight來判斷是否超過視窗范圍。
首先獲取最大left和top值:

var maxLeft = this._doc.clientWidth - this.Tip.offsetWidth,
    maxTop = this._doc.clientHeight - this.Tip.offsetHeight;

最小值是0就不用計算了。

如果Reset屬性是true會使用重新定位的方法。
理想的效果是能自動從25個預設定位中找到適合的定位位置。
但這個需求實在變化太多,要全部實現估計要長長的代碼,程序僅僅做了簡單的修正:

if (iLeft > maxLeft || iLeft < 0) {
    iLeft = this.GetLeft(rect, 2 * iLeft > maxLeft ? "left" : "right") + customLeft;
};   
if (iTop > maxTop || iTop < 0) {
    iTop = this.GetTop(rect, 2 * iTop > maxTop ? "top" : "bottom") + customTop;
};

實際應用的話估計要按需求重寫這部分才行。

如果不是用Reset重新定位,只需要根據這幾個值獲取適合的值就行了:

iLeft = Math.max(Math.min(iLeft, maxLeft), 0);
iTop = Math.max(Math.min(iTop, maxTop), 0);

隱藏select

又是ie6的隱藏select問題,這裡用的是iframe遮蓋法。

首先初始化時插入iframe:

this._iframe = document.createElement(" <iframe style='position:absolute;filter:alpha(opacity=0);display:none;'>");
document.body.insertBefore(this._iframe, document.body.childNodes[0]);

在Show的時候,參照Tip設置好樣式,再顯示:

this._iframe.style.left = iLeft + this._docScroll.scrollLeft + "px";
this._iframe.style.top = iTop + this._docScroll.scrollTop + "px";
this._iframe.style.width = this.Tip.offsetWidth + "px";
this._iframe.style.height = this.Tip.offsetHeight + "px";
this._iframe.style.display = "";

其實就是要墊在Tip的下面。

在Hidde時隱藏就可以了。

使用說明

實例化時,第一個必要參數是Tip對象:

var ft = new FixedTips("idTip");

第二個可選參數用來設置觸發對象屬性的統一默認值。

然後用Add方法添加觸發對象:

var trigger1 = ft.Add("idTrigger1");

第二個可選參數用來設置該觸發對象屬性。

要添加多個觸發對象時只需繼續用Add添加就行了。

程序源碼

代碼拷貝框

[Ctrl+A 全部選擇 然後拷貝]

XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved