vue实现滚动加载的表格

实现效果

vue实现滚动加载的表格

码云地址

滚动加载知识储备

参考ant-design-vue中list滚动加载的思路,使用vue-infinite-scroll加上vue-virtual-scroller作为解决方案。

组件封装

因为整个系统使用的框架是ant-dsign-vue,所以组件封装的变量命名风格尽可能的与a-table保持一致。

1. 组件命名

XScrollTable.vue

2. 提供的props

必填字段:

dataSource — 数据源

columns — 表格展示的列信息,插槽用法和a-table不完全一样,下面会提到。

itemSize — 每行数据的高度

选填字段:

rowKey — 数据主键标识,默认为\’key\’

height — 表格展示区域的高度,默认为500

pageSize — 表格滚动每次滚动加载的数据量,默认为30

infiniteScrollDistance — 表格触发加载的距离条件,默认为10

rowSelection — 表格多选配置,已处理的属性有selectedRowKeys、onChange、width。默认为null,不展示多选。

3.使用举例

首先初始化10000条数据,放在表格中进行显示。

let data = new Array(10000).fill(1);

data = data.map((item1, index) => {
    let item = {};
    item.id = index;
    item.age = \"姓名\";
    item.address = \"地址\";
    return item;
});
export default data;

注意:这里之所以加了fill(1),是因为通过Array构造函数产生的数据全是empty,没有数组索引,无法进行map循环。

加载表格

<x-scroll-table
                style=\"margin-top: 10px\"
                row-key=\"id\"
                :itemSize=\"22\"
                :rowSelection=\"{selectedRowKeys: selectedRowKeys, onChange: onSelectChange,width:50}\"
                :columns=\"columns\"
                :dataSource=\"data\">
            <template slot=\"action\" slot-scope=\"{record,text}\">
                <a @click=\"handleDetail(record)\">详情</a>
            </template>
        </x-scroll-table>

组件封装总结

1.尽可能地使用computed计算属性

虽然只是简单地封装了表格,但还是需要定义了很多的属性,使用计算属性代替在data里定义变量,可以减少变量的维护工作量。

整个组件只定义了一个page变量,其它都是使用计算属性的方式。

  data() {
    return {
      // 当前展示页数
      page: 1,
    };
  },

举个栗子:

通过page属性定义一个计算属性来表示当前已经加载的数据量

 // 展示的最大下标数量,存在比总数据条数多的情况,使用slice解决这个问题
    lastIndex() {
      return this.pageSize * this.page;
    },

通过这个计算属性同时衍生出其他的计算属性

// 表示表格数据是否已经加载完毕  
busy() {
      return this.lastIndex >= this.dataSource.length;
    },
 // 当前已经加载到RecycleScroller滚动组件的数据
    tableData() {
      return this.dataSource.slice(0, this.lastIndex);
    },

通过一个page属性衍生出一系列的计算属性,我只需要维护page属性,其他都是自动计算的。

2.给表格提供插槽

首先通过表格传入的columns参数,计算出需要渲染的列,这里同样使用计算属性。

 // 将列数组转为列对象,将columnFieldKey值作为键,数组项作为值
    columnMap() {
      return this.columns.reduce((returnValue, cur) => {
        returnValue[cur[columnFieldKey]] = cur;
        return returnValue;
      }, {});
    },
    // 取数组里的列键值--columnFieldKey
    columnKeys() {
      return this.columns
          .map(item => item[columnFieldKey]);
    },

在template中遍历

<div v-for=\"(key) of columnKeys\"
             class=\"ellipsis-cell\"
             :key=\"key\"
             :style=\"itemStyle(columnMap[key])\"
        >
          <slot v-if=\"izSlotRender(columnMap[key])\"
                :name=\"columnMap[key].scopedSlots.customRender\"
                :record=\"row\"
                :text=\"row[key]\">
          </slot>
          <span v-else :title=\"row[key]\">{{ renderItem(row, index, key) }}</span>
        </div>

  // 是否使用插槽渲染
    izSlotRender(item) {
      return item.scopedSlots && item.scopedSlots.customRender;
    },

如果在定义columns时传入了scopedSlots和customRender,将使用插槽渲染。

但是这里存在和ant-design-vue中表格插槽渲染不一样的地方。

我通过slot标签定义的插槽,在父组件获取插槽参数的时候,只能使用slot-scope=\”{record,text}\”对象解构的方式。而ant-design-vue表格是可以直接使用slot-scope=\”record,text\”获取参数的。

另一种滚动加载数据的实现

table数据多的时候打开页面会加载一会才显示数据,这样体验不好,所以要做滚动加载数据

<el-table :data=\"materielList\" style=\"width: 100%\" class=\"familyDataDetail\" height=\"250\">
                <el-table-column prop=\"eventId\" label=\"事件ID\">
                    <template scope=\"scope\">
                        <label>{{eventMap[scope.row.eventId] == null ? \'--\': eventMap[scope.row.eventId].sn}}</label>
                    </template>
                </el-table-column>
                <el-table-column prop=\"title\" label=\"对应事件\">
                    <template scope=\"scope\">
                        <label>{{eventMap[scope.row.eventId] == null ? \'--\': eventMap[scope.row.eventId].title}}</label>
                    </template>
                </el-table-column>
                <el-table-column prop=\"age\" label=\"负责人\">
                    <template scope=\"scope\">
                        <label>{{eventMap == null || eventMap[scope.row.eventId] == null || eventMap[scope.row.eventId].personalInformation == null ? \'--\':
                            eventMap[scope.row.eventId].personalInformation.name}}</label>
                    </template>
                </el-table-column>
                <el-table-column prop=\"birthday\" label=\"物料名称\">
                    <template scope=\"scope\">
                        <label>{{materirlName}}</label>
                    </template>
                </el-table-column>
                <el-table-column prop=\"idcardNo\" label=\"状态\">
                    <template scope=\"scope\">
                        <label>{{formatType(scope.row.type)}}</label>
                    </template>
                </el-table-column>
                <el-table-column prop=\"relationship\" label=\"数量\">
                    <template scope=\"scope\">
                        <label>{{formatUseNum(scope.row.useNum)}}</label>
                    </template>
                </el-table-column>
                <el-table-column prop=\"ethtic\" label=\"使用时间\">
                    <template scope=\"scope\">
                        <label>{{changeTime(scope.row.createOn)}}</label>
                    </template>
                </el-table-column>
            </el-table>

下面是js部分 

methods: {
  init (param) {
  let id = param.param && param.param.id
  if(id){
      this.start = 0
          MaterialRecordService.query({param: {baseId: this.baseId, materialId: id},start: this.start,limit: 30}).then(rsp => {//初次请求数据,30条
            this.start += 30
            this.materielList = rsp.data
            MissionEventService.microList({ids: rsp.data.map(n => n.eventId)}).then(rsp3 => {
                this.eventMap = {}
                rsp3.data.forEach(n => (this.eventMap[n.id] = n))
                 
            })   
          })
  }
  },
  onScroll() {
      let inner = document.querySelector(\'.el-table__body-wrapper\');
      if(inner.scrollHeight - inner.scrollTop <= inner.clientHeight){//为true时证明已经到底,可以请求接口
        if(this.flag){//设一个滚动事件的开关,(在data里面声明 flag: true)默认为true
             this.flag = false             
             MaterialRecordService.query({param: {baseId: this.baseId, materialId: this.entity.id},start: this.start,limit:30}).then(rsp => {//每次加载30条
              this.materielList = this.materielList.concat(rsp.data)
                  this.start += 30
                  this.flag = true
              MissionEventService.microList({ids: rsp.data.map(n => n.eventId)}).then(rsp3 => {
               rsp3.data.forEach(n => (this.eventMap[n.id] = n))
              })
             })            
        }
      }
   }
},
mounted () {
      this.init({...this.param})<br>    //监听表格dom对象的滚动事件
      document.querySelector(\'.el-table__body-wrapper\').addEventListener(\'scroll\', this.onScroll);
    }

在这里我要说明一下监听的dom对象是哪一个

vue实现滚动加载的表格

我还要解释下scrollHeight、scrollTop、clientHeight这三个属性

vue实现滚动加载的表格

这是我截的别人的图加了几笔

scrollHeight:网页正文全文高度,

scrollTop:网页滚动的高度,

clientHeight:网页可视区域的高度

以上就是vue实现滚动加载的表格的详细内容,更多关于vue 滚动加载的表格的资料请关注其它相关文章!

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容