vue2自定义指令+ 表格虚拟滚动

使用的ui组件库是element-ui

以下代码只是我的一种优化思路,我目前没法解决虚拟滚动的同时实现表格的合并行操作,不过可以通过这种思路解决简单的表格数据结构,但是数据量多造成的渲染dom太耗时,其他,探讨一下我实现的时候遇到的问题: 

整个思路都是通过 paddingBottom 属性 和 paddingTop属性值修改进行数据的显示,以及计算 scrollTop属性值 与行的高度尺寸 还有 数组截取slice方法使用时的下表起始位置 之间的关系实现的一个简陋的虚拟滚动的代码封装在一个局部的自定义指令里

import * as Mock from 'mockjs'
const { Random } = Mock

export default {
  name: 'App',

  data () {
    return {
      list: [],
      columns: [],
      start: 0,
      over: 5
    }
  },
  mounted () {
    function g (num) {
      return Array.from({ length: num }).reduce((res, _, id) => {
        return res.concat({
          id,
          name: Random.cname(),
          score: Random.natural(10, 10000)
        })
      }, [])
    }
    setTimeout(() => {
      this.list = g(11)
    })
  },

  components: {},

  methods: {},
  // 局部的指令
  directives: {
    myScrollbar: {
      bind: function (dom = document.documentElement, _, vnode) {
        setTimeout(() => {
          /* 获取当前使用指令的组件this引用 */
          const self = vnode.context
          const headerWrapper = dom.querySelector('.el-table__header-wrapper')
          const scrollView = dom.querySelector('.el-table__body-wrapper')
          const content = scrollView.querySelector('.el-table__body')
          /* 如果有固定列的业务 取出fixedView获取高度 */

          const fixedView = dom.querySelector('.el-table__fixed-body-wrapper')

          const fixedContent = fixedView.querySelector(
            '.el-table__fixed .el-table__body'
          )

          // 表头高度
          const HEADER_HEIGHT = headerWrapper.clientHeight
          // 表内容区域高度

          let table_body_height = scrollView.clientHeight

          // 判断是否有固定列
          const IS_FIXED = Boolean(fixedView && fixedContent)

          const row = scrollView.querySelector('tr.el-table__row')
          const row_height = row?.clientHeight ?? 52

          /* 始终渲染的行数 */
          let row_count = 5

          const SAFE_AREA_HEIGHT = 1 // 预留区域使滚轮呈现

          /* 核心步骤 数组的元素显示在区域内部 */
          function scrollHandler () {
            const totalHeight = self.list.length * row_height

            content.style.paddingTop = `${Math.min(
              scrollView.scrollTop,
              totalHeight - scrollView.clientHeight
            )}px`

            content.style.paddingBottom = `${Math.max(
              totalHeight - scrollView.clientHeight - scrollView.scrollTop,
              0
            )}px`

            if (IS_FIXED) {
              fixedView.style.height = `${scrollView.clientHeight}px`
              fixedContent.style.paddingTop = `${Math.min(
                scrollView.scrollTop,
                totalHeight - scrollView.clientHeight
              )}px`
              fixedContent.style.paddingBottom = `${Math.max(
                totalHeight - scrollView.clientHeight - scrollView.scrollTop,
                0
              )}px`
            }

            self.start = Math.min(
              Math.ceil(scrollView.scrollTop / row_height),
              self.list.length - row_count
            )
            self.over = row_count + self.start
          }

          /* 获取传入的默认总高度 max-height height 行内样式*/
          /* 初始化高度 el-table 以及根据原有的逻辑计算得出标题高度,内容区域高度 */
          function setSize () {
            const reg = /(\d+)(\w+)$/i
            const DOM_HEIGHT = ['max-height', 'maxHeight', 'height'].reduce(
              (res, key) => {
                let h = dom.style[key]
                h = h ? h.match(reg)[1] : res
                return Number(h)
              },
              500
            )
            table_body_height = DOM_HEIGHT - HEADER_HEIGHT

            scrollView.style.height = `${table_body_height}px`

            content.style.paddingBottom = `${SAFE_AREA_HEIGHT}px`

            if (!IS_FIXED) return

            fixedView.style.height = `${table_body_height}px`
            fixedContent.style.paddingBottom = `${SAFE_AREA_HEIGHT}px`
          }

          /* 根据row_count 计算得出 start over响应式数据  */
          function setData () {
            row_count = Math.ceil(table_body_height / row_height)
            self.start = 0
            self.over = self.start + row_count
          }

          function _init () {
            setSize()
            setData()
            scrollView.addEventListener('scroll', scrollHandler)
          }
          _init()
        })
      }
    }
  }
}

template 代码片段 

 <div >
    <el-table :data="list.slice(start, over)" v-my-scrollbar :height="500">
      <el-table-column
        label="编号"
        fixed
        prop="id"
        width="200"
      ></el-table-column>
      <el-table-column
        label="姓名"
        fixed
        prop="name"
        width="500"
      ></el-table-column>
      <el-table-column label="成绩" prop="score" width="200"></el-table-column>
      <el-table-column label="操作" width="500">
        <el-button size="mini">编辑</el-button>
        <el-button size="mini" type="danger">删除</el-button>
      </el-table-column>
    </el-table>
  </div>

效果图: 

 问题1: 固定列的遮罩层内容无法与表格内容对其

我的解决方法:将固定列的遮罩层高度与内容区域的高度保持一直

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值