【源碼解讀】js原生消息提示插件

效果以下:css

關閉message後先後message的銜接很是絲滑,這部分是我比較感興趣的。帶着這個問題先了解下DOM結構,順便整理下做者的思路。react

 

 

從DOM裏咱們能夠看到全部的message都在一個容器裏,而這個容器作了絕對定位實現了可視窗口的水平居中,新增的message只要在容器裏append對應的元素就會在頁面上顯示出來。jquery

接下來咱們看下每一個message元素的祕密~數組

 

 

 

咱們能夠看到這裏設置了height和padding屬性的動畫,那上文中的動畫大機率是在關閉時設置height和padding爲0,由於bfc的規則在動畫期間先後的message也會擠佔其空間,因此看起來比較絲滑。動畫執行完成後再將元素remove掉。瀏覽器

這裏注意到一個不太經常使用的css屬性:will-change,援引MDN上的表述,這個屬性會根據開發者指定的要改變的值提早作優化準備。will-change服務器

其餘內部的元素是常見的根據彈框類型和消息進行渲染,再也不進行細究。接下來關注點放到js上。app

引入方式很簡單,只有一個js文件svg

代碼示例以下:函數

 1 // 配置全局默認參數
 2 cocoMessage.config({
 3    duration: 10000,
 4 });
 5 // 普通消息,可傳入自動關閉時間、提示信息、關閉回調
 6 cocoMessage.info(3000, "請先登陸!", function () {
 7     console.log("close");
 8 });
 9 // 成功消息,可傳入element元素
10 var div1 = document.createElement("div");
11 div1.innerText = "修改爲功!";
12 cocoMessage.success(div1);
13 // 警告消息,時間設置0不會自動關閉
14 cocoMessage.warning("須要手動關閉", 0);
15 // 失敗消息
16 cocoMessage.error("修改失敗!", 3000);
17 // loading消息
18 var closeMsg = cocoMessage.loading(true);
19 setTimeout(function () {
20     closeMsg();
21 }, 4000);
22 // 關閉全部消息
23 cocoMessage.destroyAll();

 這裏咱們可看到支持的類型有info、success、warning、error、loading五種,基本場景都覆蓋到了。傳參比較靈活,能夠一個兩個三個,並且類型也不固定。帶着這些疑問開始了真正的代碼走讀,解開它神祕的面紗:性能

首先看下代碼結構:

 

 定義了一個兼容的_typeof方法(原諒我沒看懂這個兼容邏輯,有明白的兄弟能夠在評論區留言);而後是一個常見的當即執行函數,函數前的!和用括號包裹起來的效果同樣,常見的還有+-。

傳進去兩個參數,第一個是void 0(也就是undefined,我的感受用this也沒問題,感興趣的能夠了解下),另外一個參數是主體函數,後面會作詳細介紹,咱們先看下這個當即執行函數都作了什麼:

先檢查環境中是否有module.exports再檢查define.amd,最後才用全局變量。顯然這個是兼容CommonJs規範、AMD/CMD規範和直接引用的寫法。其中用global = global || self 的寫法而不是window由於能夠兼容服務器端(global全局變量)和瀏覽器端(window全局變量)。這樣會在瀏覽器window變量下暴露cocoMessage變量。另外提一下使用當即執行函數是能夠避免污染全局變量的。在進入方法內部前,建議把這部分代碼收藏一波

1 !function (global, factory) {
2   (typeof exports === "undefined" ? "undefined" : _typeof(exports)) === "object" && typeof module !== "undefined" ? 
3   module.exports = factory() : 
4   typeof define === "function" && define.amd ? 
5   define(factory) : 
6   (global = global || self, global.cocoMessage = factory());
7 }(void 0, function () {
8   // code here
9 });

 

剛進入方法會建立msgWrapper變量保存消息父元素,定義默認配置initArgs,暴露cocoMessage變量並在頁面元素加載完畢後添加style標籤。上圖中白色備註是比較通用的方法,下文會將重點放在紅色備註的方法上。

首先關注下建立msgWrapper元素的c方法

第一個參數傳輸對象,key能夠是className來給元素添加class屬性,另外一種能夠是以_開頭能夠給元素綁定相應的事件。

第二個參數能夠傳輸文本、元素、包含多個元素的數組(或者僞數組)。

// 建立class爲coco-msg-stage的div元素
var msgWrapper = c({
   className: "coco-msg-stage"
}, "默認消息");
// 建立class爲coco-msg-wait並在元素上綁定click事件
c({
    className: "coco-msg-wait " ,
    _click: function _click () {
      if (closable) {
        closeMsg(el, onClose);
      }
    }
}
// 屢次調用建立複雜元素
c({
   className: "coco-msg-stage"
}, c({
   className: "coco-msg-loading",
   _click: function(){
       console.log("loading")
   }
})
);
而後看下initArgs和cocoMessage這兩個變量

 

共有info、success、warning、error、loading、destoryAll、config這七個方法,這也正是這個插件想要暴露給用戶的。默認參數中消息是空字符串,關閉時間是2s,不會顯示關閉按鈕,固然這些均可以經過config方法修改全局的默認配置,從中也能夠看到隨時能夠修改配置,即時生效。除去destoryAll方法咱們先關注下消息的5中類型,建立方法大同小異:都是經過initConfig方法建立的。其中arguments是僞數組,也就是咱們調用info等方法傳遞的全部參數,能夠經過通數組同樣角標方式取值。loading方法是特殊的,把initConfig方法的結果返回了,經過demo咱們知道返回值是個方法,執行後會關閉loading,下文咱們再關注下loading類型的消息有什麼特殊處理,開始進入initConfig方法

 

 

 這裏僅是對參數進行統一,上文中有個疑問,爲何參數能夠隨便傳,並且順序不一致也不影響?答案就在這個方法裏,以前傳的參數有提示信息:字符串(string類型)或元素(Element或object類型)、延遲時間:數字(number類型)、關閉後的回調:方法(function類型)、是否顯示關閉按鈕(boolean類型)。到這裏應該發現這裏的玄機了,每一個參數都有惟一的類型並且還不會衝突,這樣就能夠根據傳參類型的不一樣識別傳的值了。封裝後的對象大體以下:

{
   msg: "提示消息",
   type: "info",
   showClose: false,
   duration: 2000,
   onClose: function(){
       console.log("closed")  
   }
}

雖然以上方法設計得很巧妙,可是健壯性要差一些,若是要擴展設置文字是否居中、自定義類名、自定義圖標等功能時難免會要進行重構。因此調用方法改爲這樣會便於擴展:

cocoMessage.info({
    msg: '請先登陸',
    duracion: '2000',
    showClose: true,
    onClose: function(){
        console.log('closed')
    }
});

到這一步須要的參數封裝完成了,接下來會調用createMsgEl方法建立消息元素。

 方法較長分爲兩個部分,完成了根據傳入的參數建立元素並添加到body中顯示出來,並綁定關閉按鈕的點擊事件和觸發自動關閉的條件。圖中畫問好的正是上文中咱們存疑的問題,正由於這裏返回了關閉消息的方法就能夠實現執行後關閉loading。

到這裏還剩closeMsg方法destoryAll方法,咱們先看closeMsg:

 

 首先會設置padding和height爲0,進而實現開頭說的動畫效果,而後執行自定義的關閉回調方法。最後再刪除消息元素,若是沒有消息也會把父元素一併刪除。須要注意的是這裏還會判斷消息元素是否存在,這並非冗餘的代碼,而是考慮到點擊按鈕關閉和執行所有關閉一塊兒執行時後觸發的會報錯的問題,由於這裏有300ms的延遲。

最後是destoryAll方法,關閉全部消息。

 

 獲取父元素全部的消息元素再循環調用closeMsg方法進行刪除。

 到這裏原生的消息提示插件已經解讀完畢,這是款很輕量和優秀的插件。
 
總結:
首先經過當即執行函數避免全局變量污染,只對外暴露七個方法。經過變量檢測實現對CommonJs規範、AMD/CMD規範和直接引用的兼容。經過巧妙的參數設計,實現了對參數前後順序沒有要求,經過設置padding和height值來實現動畫效果。
亮點:
設置will-change的css屬性提升性能和用戶體驗;
經過兼容監聽元素animationEnd事件來執行回調,解決了setTimeout不許確和性能問題;
經過c方法能夠很方便得建立元素,有點react的味道;
給svg內元素設置動畫;
 
插件預覽地址:https://www.jq22.com/jquery-info23645
相關文章
相關標籤/搜索