技术栈

  • Vue.js
  • ElementUi 

无限滚动优点

解决dom一次性渲染开销大, 导致浏览器卡顿, 或者内存不足崩溃

无限滚动缺点:

理论上无限滚动数据量达到w级也会逐步开始卡顿, 暂时还没尝试过

针对vue框架做了directive(自定义指令 — Vue.js)的形式开发, 代码如下

// src/directive/lazyLoading.js
function debounce(fn, delay) {
  //  防抖
  var timeout = null; // 创建一个标记用来存放定时器的返回值
  return (e) => {
    clearTimeout(timeout); // 每当用户输入的时候把前一个 setTimeout clear 掉
    // 然后又创建一个新的 setTimeout, 这样就能保证interval 间隔内如果时间持续触发,就不会执行 fn 函数
    timeout = setTimeout(() => {
      fn.apply(this, arguments);
    }, delay);
  };
}

export default {
  install(Vue) {
    Vue.directive("lazyLoading", {
      bind(el, binding) {
        const { value } = binding;
        let elementClass = null;
        let lazyFun = null;
        if (typeof value == "object") {
          const { elementClass: _elementClass, lazyFun: _lazyFun } = value; //   elementClass 滚动盒子的class,   lazyFun 调用的函数
          elementClass = _elementClass;
          lazyFun = _lazyFun;
        } else if (typeof value == "function") {
          lazyFun = value;
        } else {
          console.err("传参错误");
          return;
        }
        // 获取element-ui定义好的scroll盒子
        const SELECTWRAP_DOM = el.querySelector("." + elementClass);
        SELECTWRAP_DOM.addEventListener("scroll", function () {
          let { clientHeight, scrollTop, scrollHeight } = this;
          // 当用户的滚动距离大于等于滚动条的总高度, 就执行lazyFun方法
          const CONDITION = Math.ceil(clientHeight + scrollTop) >= scrollHeight;
          if (CONDITION) {
            debounce(lazyFun(), 300);
          }
        });
      },
    });
  },
};
// src/main.js 在入口文件引入, vue实例生成前调用
import lazyLoading from "@/directive/lazyLoading";
Vue.use(lazyLoading);

new Vue({
  el: "#app",
  ...
});
// 页面使用
  <el-scrollbar
    v-lazy-loading="{
      lazyFun: lazyFun,
      elementClass: 'el-scrollbar__wrap',
    }"
  >
    ...
  </el-scrollbar>

<script>
export default {
  data() {
    return {
      renderNum: 0, //渲染次数
      renderList: [], //渲染的数据
    };
  },
  methods: {
    // 初始化懒加载数据 从0开始
    initLazyFun() {
      let count = 5;
      this.renderList = this.upList.slice(0, count);
      this.renderNum += count;
    },
    // 更新当前懒加载数据 仅更新renderNum数量, 不继续+count
    updateLazyFun() {
      this.renderList = this.upList.slice(0, this.renderNum);
    },
    // 懒加载数据
    lazyFun() {
      let count = 5;
      this.renderList = this.upList.slice(0, this.renderNum + count);
      this.renderNum += count;
    },
};
</script>

自定义指令拓展

指令钩子函数会被传入以下参数:

  • el:指令所绑定的元素,可以用来直接操作 DOM。
  • binding:一个对象,包含以下 property:
    • name:指令名,不包括 v- 前缀。
    • value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2
    • oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
    • expression:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"
    • arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"
    • modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }
  • vnode:Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。
  • oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。

文章参考

vue2.0 自定义指令 ++ element-ui 自定义el-select的下拉懒加载指令 - 灰信网(软件开发博客聚合)

Logo

前往低代码交流专区

更多推荐