vue項目封裝并發布無限滾動指令優化渲染性能的npm模塊

曾經在前端之巔看過這么一篇文章,標題是《網站性能優化實戰——從12.67s到1.06s的故事》,當時我就納悶了,哪來的網站首屏需要加載12秒,而且怎么做到這么極致的優化的?

果然過了幾天,接手了一份祖傳代碼,運行后發現項目奇卡,渲染也不是一般的慢,除了谷歌和火狐,其他瀏覽器一律崩潰。

亞馬遜的工程師形容說他們的祖傳代碼:“一座很大的屎山,你見過的最大的山,每次你想修正一個bug,你的工作就是爬到屎山的正中心去

原項目是混合在php項目中的,我的任務是抽離并優化它,瞬間覺得很有挑戰了。

當我嘗試修復一個bug時

略過具體的抽離過程,直接其中一個優化關鍵點,就是有多個頁面都使用element-uiel-table組件進行數據渲染,發現當需要渲染超過1K+的數據的時候頁面渲染需要很久,查看控制臺發現渲染時間占用10S之久。

查看el-table源碼發現內部使用的div來實現table布局,導致產生了大量的dom節點,又由于業務需要無法采用分頁,所以當務之急是開發一個無限滾動、滾動加載的組件,而該組件的核心的無限滾動實現邏輯,而且在下拉框中也需要滾動加載,所以干脆抽離出一個無限滾動指令

主要思路是創建三個指令

無限滾動指令 參數 描述
v-infinite-scroll callback:function 滾動到指定底部后觸發的事件
v-infinite-scroll-distance px:number 距離底部多遠觸發事件
v-infinite-scroll-disabled busy:bool 當前是否為忙碌狀態
<div v-infinite-scroll="scrollLoad" v-infinite-scroll-disabled="busy" v-infinite-scroll-distance="250">
    ...
</div>

infinite-scroll-distanceinfinite-scroll-disabled指令分別設置目標標簽的data-infiniteScrollDistancedata-infiniteScrollDisabled屬性。

infinite-scroll指令在目標標簽上注冊滾動事件,但達到data-infiniteScrollDistance高度和data-infiniteScrollDisabled為true時,觸發回調。(回調中應該填充目標標簽內容,使得高度變化,觸發下一輪滾動事件)

下面是具體實現
InfiniteScrollDisabled.js

// directives/InfiniteScrollDisabled.js
export default {
  bind(el, binding) {
    el.setAttribute('data-infiniteScrollDisabled', binding.value);
  },
  update(el, binding) {
    el.setAttribute('data-infiniteScrollDisabled', binding.value);
  },
};

InfiniteScrollDistance.js

// directives/InfiniteScrollDistance.js
export default {
  bind(el, binding) {
    el.setAttribute('data-infiniteScrollDistance', binding.value);
  },
  update(el, binding) {
    el.setAttribute('data-infiniteScrollDistance', binding.value);
  },
};

InfiniteScroll.js

// directives/InfiniteScroll.js
export default {
  bind(el, binding) {
    let target = el;
    if (el.getAttribute('data-scrollTarget')) {
      target = el.querySelector(el.getAttribute('data-scrollTarget'));
    }
    target.addEventListener('scroll', e => {
      const busy = el.getAttribute('data-infiniteScrollDisabled') ? false : true;
      const distance = el.getAttribute('data-infiniteScrollDistance')
        ? Number.parseInt(el.getAttribute('data-infiniteScrollDistance'), 10)
        : 100;
      if (!busy && e.target.scrollHeight - (e.target.scrollTop + e.target.clientHeight) < distance) {
        el.setAttribute('data-infiniteScrollDisabled', true);
        binding.value(e);
      }
    });
  },
};

這里有一個點需要注意,這里接受一個data-scrollTarget屬性,代表綁定滾動事件的元素,默認是當前元素,如果需要指定為內部的某個元素可以使用該屬性。


到這里無限滾動指令邏輯已經結束了,我們再創建一個文件,用于統一導出指令,并讓vue項目通過vue.use(...)的形式使用。

// index.js
import InfiniteScroll from './directives/InfiniteScroll';
import InfiniteScrollDisabled from './directives/InfiniteScrollDisabled';
import InfiniteScrollDistance from './directives/InfiniteScrollDistance';

export default {
  install(Vue, options) {
    const directives = {
      InfiniteScroll,
      InfiniteScrollDisabled,
      InfiniteScrollDistance
    };
    Object.keys(directives).forEach(key => {
      directives[key].$options = options;
      Vue.directive(key, directives[key]);
    });
  },
};

導致index.js后,直接用vue.use(...),將會觸發導出的install方法,并傳入vue實例和相關參數。
當然也可以發布到npm上,具體發布流程這里暫不介紹。


細心的朋友可能已經發現了,這里寫的是es6代碼,在不兼容的瀏覽器上將無法使用,我們可以全部改回es5,但是,我建議使用babel進行轉譯。

首先我們先安裝babel-clibabel-preset-es2015

$ npm install  babel-cli  babel-preset-es2015 --save-dev

然后添加一個轉譯命令

// package.json
"scripts": {
  "build": "babel ./src --presets babel-preset-es2015 --out-dir ./lib"
},

把./src下的全部文件轉譯成es5到./lib文件夾下。

執行打包轉譯

$ npm run build

后面的任務就是通過該無限滾動指令指令封裝無限滾動組件,請看后續文章。

最后奉上git地址:https://gitee.com/zhkumsg/common-directive

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,321評論 6 543
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,559評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,442評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,835評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,581評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,922評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,931評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,096評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,639評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,374評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,591評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,104評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,789評論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,196評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,524評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,322評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,554評論 2 379

推薦閱讀更多精彩內容

  • 每至歲末,人們通常都會感嘆一番:時間飛逝!我自己也是如此。我對于時間的印象,大約緣于初一時學習論語,論語記載,子...
    吉祥Nick閱讀 714評論 0 3
  • 今天繼續來復習劉友龍老師語錄:1、關注正向與堅持規則并行。2、教育的極致是行為影響。3、有接納才有溝通,有溝通...
    尤占芳閱讀 190評論 0 0
  • 2017.11.24 星期五 天晴 今天特種兵內訓第5天,依然忙碌有序的進行著,大家的速度也越來越快,簽到時間一個...
    橙子33閱讀 250評論 0 0