美文网首页前端性能优化
vue项目封装并发布无限滚动指令优化渲染性能的npm模块

vue项目封装并发布无限滚动指令优化渲染性能的npm模块

作者: MsgSS | 来源:发表于2019-04-11 10:00 被阅读20次

    曾经在前端之巅看过这么一篇文章,标题是《网站性能优化实战——从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

    相关文章

      网友评论

        本文标题:vue项目封装并发布无限滚动指令优化渲染性能的npm模块

        本文链接:https://www.haomeiwen.com/subject/gduziqtx.html