el-transfer 数据量大时使用虚拟列表

前言

el-transfer 加载几千个数据已经卡得不行了,毕竟页面上存在了 几千多份 dom
由于时间紧急,打算直接拿源码出来修改。

开始

为了代码不混淆,这里使用 mixins

有三个文件
在这里插入图片描述
virtual-list-mixins.js

export default {
  computed: {
    contentHeight () {
      // 计算滚动条高度
      return this.data.length * this.itemHeight
    }
  },

  watch: {
    filteredData () {
      this.handleScroll()
    }
  },

  mounted () {
    this.update()
  },

  data () {
    return {
      itemHeight: 30, // 单个高度
      virtualList: [] // 渲染数据
    }
  },

  methods: {
    update (scrollTop = 0) {
      // 获取当前可展示数量
      const count = Math.ceil(this.$el.clientHeight / this.itemHeight)
      // 取得可见区域的起始数据索引
      const start = Math.floor(scrollTop / this.itemHeight)
      // 取得可见区域的结束数据索引
      const end = start + count

      // 计算出可见区域对应的数据,让 Vue.js 更新
      this.virtualList = this.filteredData.slice(start, end)

      // 把可见区域的 top 设置为起始元素在整个列表中的位置(使用 transform 是为了更好的性能)
      this.$refs.content.style.webkitTransform = `translate3d(0, ${start * this.itemHeight}px, 0)`
    },
    handleScroll (e) {
      // 获取当前滚动条滚动位置
      const scrollTop = this.$refs.container.scrollTop
      this.update(scrollTop)
    }
  }
}

transfer-panel.vue

...
  <div class="list-view"
        :class="{ 'is-filterable': filterable }"
        ref="container"
        @scroll="handleScroll">
        <div class="list-view-phantom"
          ref="clientHeight"
          :style="{ height: contentHeight + 'px' }"></div>
        <div ref="content"
          class="list-view-content">
          <div class="list-view-item">
            <el-checkbox-group v-model="checked"
              v-show="!hasNoMatch && data.length > 0"
              class="el-transfer-panel__list">
              <el-checkbox class="el-transfer-panel__item list-view-item"
                :style="{ height: itemHeight + 'px' }"
                :label="item[keyProp]"
                :disabled="item[disabledProp]"
                :key="item[keyProp]"
                v-for="item in virtualList">
                <option-content :option="item"></option-content>
              </el-checkbox>
            </el-checkbox-group>
          </div>
        </div>
      </div>
     ...

在这里插入图片描述
然后配合一下 css

.list-view {
  width: 100%;
  height: 100%;
  overflow: auto;
  position: relative;

  &.is-filterable {
    height: calc(100% - 62px);
  }
}

.list-view-phantom {
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  z-index: -1;
}

.list-view-content {
  left: 0;
  right: 0;
  top: 0;
  position: relative;
}

.list-view-item {
  padding: 6px;
  line-height: 30px;
}

/deep/ .el-transfer-panel__list {
  height: unset;
}

/deep/.el-transfer-panel__item.el-checkbox .el-checkbox__label {
  line-height: 19px;
}

最后

import virtualListMixins from './virtual-list-mixins'
export default {
  mixins: [Locale, virtualListMixins]
  ...
}

完成

然后依旧像往常一样使用它

<template>
  <div>
    <ElTransfer v-model="value"
      filterable
      :data="data" />
  </div>
</template>

<script>
import ElTransfer from './main.vue'
export default {
  components: { ElTransfer },
  data () {
    const generateData = _ => {
      const data = []
      for (let i = 1; i <= 10000; i++) {
        data.push({
          key: i,
          label: `备选项 ${i}`
        })
      }
      return data
    }
    return {
      data: generateData(),
      value: []
    }
  }
}
</script>

在这里插入图片描述

其他

源代码: Github

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_pengliang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值