All files / src/components/u-table-view.vue f-virtual-table.vue

100% Statements 4/4
50% Branches 1/2
100% Functions 0/0
100% Lines 4/4

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129      7x   7x     7x                                                                                                                                                                                                                                                
<script>
import FVirtualList from '../f-virtual-list.vue';
 
export default {
    name: 'f-virtual-table',
    extends: FVirtualList,
    computed: {
        virtualList() {
            const list = this[this.listKey];
            if (!this.virtual)
                return list;
            else {
                let count = 0;
                for (let i = this.virtualIndex; i < list.length; i++) {
                    const item = list[i];
                    if (item.display !== 'none') {
                        count++;
                    }
                    if (count >= this.virtualCount || i === list.length - 1) {
                        return list.slice(this.virtualIndex, i + 1);
                    }
                }
                return [];
            }
        },
    },
    methods: {
        handleVirtualScroll(e) {
            if (!this.virtual)
                return;
            const listEl = e.target;
            let virtualEl = this.$refs.virtual;
            if (Array.isArray(virtualEl)) {
                virtualEl = virtualEl[0];
            }
            let tablebodyEl = this.$refs.body;
            if (Array.isArray(tablebodyEl)) {
                tablebodyEl = tablebodyEl[0];
            }
            const list = this[this.listKey];
            const showList = (list || []).filter((item) => item.display !== 'none');
            if (!virtualEl || !list)
                return; // 缓存当前可见 DOM 节点的高度
            if (this.itemHeight === undefined) {
                const children = Array.from(virtualEl.children);
                children.forEach((childEl, index) => {
                    const item = list[this.virtualIndex + index];
                    if (
                        item
                        && item.height === undefined
                        && item._cacheHeight === undefined
                    )
                        item._cacheHeight = item.height || childEl.offsetHeight;
                });
            }
            const getHeight = (item) => {
                if (item.display === 'none')
                    return 0;
                else if (this.itemHeight !== undefined)
                    return this.itemHeight;
                else if (item.height !== undefined)
                    return item.height;
                else if (item._cacheHeight !== undefined)
                    return item._cacheHeight;
                else
                    return 0;
            };
            const scrollTop = listEl.scrollTop;
            let accHeight = 0;
            let virtualIndex = this.virtualIndex;
            let currentIndex = 0;
            for (currentIndex = 0; currentIndex < list.length; currentIndex++) {
                const item = list[currentIndex];
                if (accHeight > scrollTop)
                    break;
                accHeight += getHeight(item);
            }
            let showCount = 0;
            if (getHeight(list[0])) {
                showCount = Math.ceil(tablebodyEl.clientHeight / getHeight(list[0]));
            }
            virtualIndex = Math.max(
                0,
                currentIndex - Math.ceil((this.virtualCount - showCount) / 2),
            ); // eslint-disable-next-line yoda
            // table 树形展示里不能这么处理,暂时注释掉
            // 该方法容易出现白屏。有截流了问题不大。
            // if (
            //     this.virtualCount / 3 <= currentIndex - this.virtualIndex
            //     && currentIndex - this.virtualIndex < (this.virtualCount * 2) / 3
            // )
            //     return;
            let virtualTop = 0;
            let virtualBottom = 0;
            let noDisplayCount = 0;
            for (let i = 0; i < list.length; i++) {
                const item = list[i];
                if (i < virtualIndex) {
                    virtualTop += getHeight(item);
                } else if (i >= virtualIndex + this.virtualCount) {
                    virtualBottom += getHeight(item);
                }
                if (i > virtualIndex && i <= virtualIndex + this.virtualCount) {
                    if (item.display === 'none') {
                        noDisplayCount++;
                    }
                }
            }
            this.virtualIndex = virtualIndex;
            this.virtualTop = virtualTop;
            this.virtualBottom = virtualBottom; // Vue 应该是对渲染做了优化,为了减少在高频滚动时出现白屏的问题,需要强制更新
            this.$nextTick(() => {
                this.$forceUpdate();
                this.$emit(
                    'virtual-scroll',
                    {
                        virtualIndex,
                        virtualCount: this.virtualCount,
                        virtualTop,
                        virtualBottom,
                    },
                    this,
                );
            });
        },
    },
};
</script>