vue2 directive指令实现表格懒加载功能(适配el-table 不分页)

v3的同学可自行根据代码片段修改 改动不会很多

先上效果

1704854233093

1.lazyList js文件

let make = null
class LazyList {
  constructor(el, binding,
    { total = 0, size = 0, iTime = null, oldInitData = null, type = null }
  ) {
    // setEl 自己传的父级dom
    this.el = el; this.binding = binding; this.bindingValue = binding.value
    oldInitData = this.bindingValue.initData
    this._data = {
      total, size, iTime, oldInitData, type
    }
    // 分发_data中的数据到this
    Object.keys(this._data).forEach((prop) => { this[prop] = this._data[prop] })
    this.iTime = setTimeout(() => { this.init(el, binding, { type: type }) }, 50)
  }
  async init(el, binding, vn) {
    const type = vn.type
    const { setFn, pageSize = 3, currentPage = 20 } = binding.value
    const initData = binding.value.initData
    if (this.oldInitData !== initData) {
      console.log('重置所有数据项,销毁之前的监听')
      clearTimeout(this.iTime)
      this.intersectionObserver?.unobserve(this.children)
      make = new LazyList(el, binding, { type })
      return
    } // 旧的数据不匹配了 翻倒全部东西重新构造
    const _size = pageSize + this.size
    if (this.total === _size * currentPage) { return }// 页数和总数一样的情况不能更新 因为这里重新调用init的时候会触发update 必须拦截掉
    this.total = _size * currentPage
    this.oldInitData = initData // 存储一下初始化时候的数据 用来判定数据是否被更新了
    if (!initData) { return }
    const value = initData.slice(0, this.total)
    await setFn(value)
    const options = {
      root: this.el, // 相对于某个元素进行遮挡计算
      rootMargin: binding.value.rootMargin || '100px', // 进行计算的边界范围,通过rootMargin可以实现提前计算或延迟计算(相对于root原本尺寸)的效果
      threshold: 0.1 // 触发callback时的遮挡比例,0.5代表元素被遮挡50%时触发callback。由于浏览器事件循环机制的影响,callback触发时遮挡比例通常不会是精确的50%。
    }
    const _target = this.el.querySelectorAll('.el-table__row') || this.el.childNodes // el-table__row是用来适配el-table的
    this.children = _target[_target.length - 1]
     if (!this.children) { return }
    this.intersectionObserver = new IntersectionObserver((entries, observer) => {
      // 和MutationObserver相同,也是产生一个array
      entries.forEach(entry => {
        // isIntersecting属性也可判断目标元素当前是否可见
        if (entry.intersectionRatio > 0) { // 通过entry.intersectionRatio属性
          const remainingQuantity = binding.value.initData.length - (pageSize + this.size) * currentPage
          console.log('剩余待加载数量:', remainingQuantity + pageSize)
          if (remainingQuantity <= 0) {
            console.log('剩余数量小于0 unobserve', type)
            observer.unobserve(this.children)
          } else {
            observer.unobserve(this.children)
            this.size++
            this.init(el, binding, { type })
          }
        }
      })
    }, options)
     if (remainingQuantity > 0) {
      console.log('进行observe', type, '剩余待加载数量:', remainingQuantity)
      this.intersectionObserver.observe(this.children)
      this.iTime = null
    }
  }
}
export default {
  install(Vue, options) {
    Vue.directive('lazyList', {
      // 初始化触发 只执行一次
      bind: function(el, binding, vnode, oldVnode) {
        make = new LazyList(el, binding, { type: 'bind' }) // 构造的时候会默认初始化init
      }, // 更新了数据就会触发
      update: function(el, binding) {
        clearTimeout(make.iTime)
        make.init(el, binding, { type: 'update' })
      },
      unbind: function() { }
    })
  }
}

2.全局注册:在main.js中全局引入,用Vue.use()使用指令;

import lazyList from './lazyList'
Vue.use(lazyList)

3. DOM片段和配置项

使用 v-lazyList=“lazyList” 设置默认传参和父级盒子 会自动获取父级的childNodes

<div style="height: calc(100vh - 375px);margin-top: 10px">
    <el-table
      ref="tableData"
      v-lazyList="lazyList"
      height="100%"
      :data="dataList"
    >
      <el-table-column type="index" width="50" label="序号" align="center" />
      <el-table-column prop="name" label="所属单位" />
      <el-table-column prop="name" label="月度用户人数" />
      <el-table-column prop="name" label="月度新增人数" />
      <el-table-column prop="name" label="月度活跃用户数" />
    </el-table>
 </div>
computed: {
   lazyList() {
      return {
	    initData: [], // 初始化的所有数据(必传) 会根据这里的数据来慢慢加载
        setFn: this._set, // 懒载的数据返回 自行赋值 
        pageSize: 3, // 初始页数 可不传 默认为3
        currentPage: 20, // 一页翻多少条 可不传 默认为20
        rootMargin:'100px' 距离多少间距触发(用来提前触发加载数据) 默认100px
      }
   }
 },
data() {
    return {
    	dataList: []
	}
}
methods:{
	 _set(val) {
		 this.dataList = val //	dataList 为渲染的懒数据
	 }, 
 }
  • 6
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
el-table是Element UI库中的一个表格组件,用于展示数据。要实现el-table的二级,可以通过以下步骤: 1. 首先,在el-table中设置一个列(column)为可展开的列,通过设置`type`属性为`expand`,并且设置`expandable`属性为`true`。例如: ```html <el-table :data="tableData" style="width: 100%"> <el-table-column type="expand" :expandable="true"> <!-- 这里放置展开内容的模板 --> </el-table-column> <!-- 其他列的定义 --> </el-table> ``` 2. 接下来,在展开内容的模板中,可以使用`template`标签或者自定义组件来定义展开的内容。在展开内容中,可以使用异步请求获取二级数据,并将其绑定到展开内容的模板中。例如: ```html <template slot-scope="props"> <div> <!-- 这里放置展开内容的具体内容 --> <el-table :data="props.row.subData" style="width: 100%"> <!-- 定义二级表格的列 --> </el-table> </div> </template> `` 3. 在获取二级数据的时候,可以使用Vue的异步请求库(如axios)发送请求,并将获取到的数据绑定到展开内容的模板中。例如: ```javascript // 在展开内容的模板中,通过异步请求获取二级数据 methods: { async fetchData(row) { // 发送异步请求获取二级数据 const response = await axios.get('your_api_url'); // 将获取到的数据绑定到展开内容的模板中 row.subData = response.data; } } ``` 这样,当用户点击展开按钮时,会触发`fetchData`方法,异步请求获取二级数据,并将其绑定到展开内容的模板中,实现二级

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值