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阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容

  • 每至岁末,人们通常都会感叹一番:时间飞逝!我自己也是如此。我对于时间的印象,大约缘于初一时学习论语,论语记载,子...
    吉祥Nick阅读 609评论 0 3
  • 今天继续来复习刘友龙老师语录:1、关注正向与坚持规则并行。2、教育的极致是行为影响。3、有接纳才有沟通,有沟通...
    尤占芳阅读 179评论 0 0
  • 2017.11.24 星期五 天晴 今天特种兵内训第5天,依然忙碌有序的进行着,大家的速度也越来越快,签到时间一个...
    橙子33阅读 220评论 0 0