Vue自定义指令-虚加载

2022-08-26  本文已影响0人  欢西西西

指令文件:

// 有可能list的el和绑定scroll的el并不是一个,把paddingTop和paddingBottom传出去自己设置到list上
const toUpdateData = function ({ maxDrawCount, itemHeight, updateRealDrawList: fnUpt }, el) {
    const allData = el.__allData__ || [];
    let dataCount = allData.length;
    if (dataCount <= maxDrawCount) {
        el.dataset.startindex = 0;
        return fnUpt({
            data: allData,
            paddingTop: 0,
            paddingBottom: 0
        });
    }
    const start = el.dataset.startindex * 1;
    let drawEndIndex = Math.min(start + maxDrawCount, dataCount);
    let paddingTop = start * itemHeight + "px";
    let paddingBottom = (dataCount - drawEndIndex) * itemHeight + "px";
    let realDrawList = allData.slice(start, drawEndIndex);
    fnUpt({
        data: realDrawList,
        paddingTop,
        paddingBottom
    });
};


/**
 * 指令的binding对象接收:
 * {Array} data 列表的总数据
 * {Number} maxDrawCount 实际在页面上最多渲染多少条数据
 * {Number} itemHeight 每条数据的高度
 * {Function} updateRealDrawList 自动计算出要渲染的数据时会将(data, paddingTop, paddingBottom)作为入参调用此更新方法
 * 在使用此指令的页面将data更新为要渲染的列表,将paddingTop, paddingBottom绑定在列表上
 */
export default {
    bind: function (el, binding) {
        // 当滚动时updateRealDrawList
        el.addEventListener('scroll', (function () {
            let scrollTimer = null;
            return function () {
                if (scrollTimer) {
                    return;
                }
                scrollTimer = setTimeout(() => {
                    let { itemHeight } = binding.value;
                    let v = parseInt(el.scrollTop / itemHeight),
                        startIndex = v > 4 ? v - 4 : 0; // 在上方不可见范围内再渲染4个
                    el.dataset.startindex = startIndex;
                    toUpdateData(binding.value, el);
                    clearTimeout(scrollTimer);
                    scrollTimer = null;
                }, 250);
            };
        })());
    },
    update: function (el, binding) { // 当总列表改变时updateRealDrawList
        let { data } = binding.value;
        if (data === el.__allData__) {
            return;
        }

        // 因为各个页面都有可能要用这个指令,数据不能存在全局变量,会造成各页面都公用这份数据。所以现在挂在el上
        el.__allData__ = data;
        toUpdateData(binding.value, el);
    },
};

使用指令

<div v-virtualscroll="{
        data: allData,
        maxDrawCount: 20,
        itemHeight: 100,
        updateRealDrawList: onUptDrawList,
      }">
<!-- 渲染drawList列表,并将paddingTop ,paddingBottom 设置到style  -->
</div>
import VirtualScroll from "@/utils/VirtualScroll.js";
export default {
  directives: {
    "virtualscroll": VirtualScroll,
  },
  methods: {
     onUptDrawList({ data, paddingTop, paddingBottom }) {
        this.drawList = data;
        this.paddingTop = paddingTop;
        this.paddingBottom = paddingBottom;
    },
  }
}

自定义指令一个重要的问题:如何传值

1、指令的这些钩子函数里面如何拿到组件中的数据?

2、在哪里监控入参的更新?

image.png
<template>
  <div>
    <div v-mycopy="userName">复制</div>
    <div>{{ billSn }}</div>
  </div>
</template>

当billSn改变时,依然会调mycopy指令的update,但userName并没有变

3、指令的钩子中能改变组件中的数据吗?

image.png
上一篇 下一篇

猜你喜欢

热点阅读