el-table动态渲染列、可编辑单元格、虚拟无缝滚动

针对日常开发的组件二次封装、方案设计实现。包括对el-table的动态渲染、单元格编辑;对于无缝滚动的实现,优化大数据量下的页面卡顿问题。

1. el-table实现动态渲染列

常规使用el-table



表格比较长时,需要些好多的el-table-column;所以想通过动态渲染的方式循环渲染出列项。

官方给出的formatter格式化列项输出的方法只能格式化文本。无法渲染VNode。

尝试通过v-html绑定,报错h is not a function

  // ...
  
    
  

解决办法,通过render方法提供CreateElement函数。新创建一个组件RenderColumn

RenderColumn.vue


在渲染表格时调用,主要在于需要给render方法传入CreateElement方法。



vue-cli脚手架已经继承了JSX的语法,可以直接书写。

2. el-table实现单元格的编辑

实现单元格的编辑,实现编辑组件EditCell.vue

逻辑的核心点:

  1. 非编辑状态下,展示当前列项值,通过点击事件,单元格进入可编辑状态。并可通过this.$refs.input.focus()聚焦

  2. 数据el-input主要在于处理完成输入、enter键后完成编辑状态。

  3. 当完成编辑时,如果传入了校验函数。则需调用函数进行校验。并通过el-popover展示。



如果要实现整行row的编辑,可给每一行数据追加属性editable,整合编辑时更改属性,切换为编辑状态。

切入编辑状态el-input本来想通过autofocus获取焦点的。但没有用,使用了ref组件内部的方法。

3. 实现虚拟无缝滚动seamlessScroll

使用过vue-seamless-scroll,可实现数据的无缝滚动。但当数据量超过大几千时,页面就会变的很卡。通过看源代码实现,加入5000的数据量,需要渲染10000个DOM节点。

通过之前虚拟列表的思想,实现一个虚拟无缝滚动组件

实现滚动的主要API

  1. transform:translate(0px,0px),在水平、垂直方向上进行平移数据列表

  2. window.requestAnimationFrame(()=>{}) 在浏览器下次重绘时调用回调函数,通常为60次/s

实现的主要逻辑:

  • 组件挂载或者数据data变化时进行数据初始化init()

  • init方法用于调用数据切割滚动方法。其中一个参数virtual用于显示控制如果数据量不大时,就没必要虚拟滚动了。

  • move方法中,通过每一帧的渲染更新,回调函数处理this.translateY -= this.speed平移数据列表。

  • splitData中则处理数据切割,判断如果不需要虚拟滚动时,则加载展示所有的数据。

  • 随后监听了translateY的变化,用于处理虚拟列表的滚动分页逻辑

      /**
       * 如果平移的距离大于分页*每项的长度,进行数据滚动重置
       **/
      handleDataScorll() {
        if (
          Math.abs(this.translateY) <
          this.pageOptions.pageSize * this.itemWidth
        ) {
          return;
        }
        // this.stop();
        // 第一页已滚动完成
        if (this.virtual) {
          this.splitData();
        }
        this.translateY = 0;
      },
    

核心的JS逻辑,实现的相关方法。

export default {
  // ...
  mounted() {
    // 复制数据,数据仓
    this.copyData = [...this.data];
    // 切割数据
    this.init();
  },
  computed: {
    boxStyle() {
      return {
        transform: `translate(0, ${this.translateY}px )`,
      };
    },
    total() {
      return this.data.length;
    },
  },
  watch: {
    data(newData) {
      this.copyData = [...newData];
      this.init();
    },
    translateY() {
      this.handleDataScorll();
    },
  },
  methods: {
    init() {
      if (!this.virtual) {
        // 非虚拟列表管滚动,则直接展示所有数据
        this.pageOptions.pageSize = this.total;
      }
      if (this.total > 0) {
        this.splitData();
        this.move();
      }
    },
    move() {
      this.stop();
      this.animationFrame = requestAnimationFrame(() => {
        if (this.total > 0) {
          this.translateY -= this.speed;
        }

        this.move();
      });
    },
    splitData() {
      if (!this.virtual) {
        this.preData = [...this.copyData];
        this.nextData = [...this.copyData];
        return;
      }
      // 只有在虚拟列表时,才调换数据位置
      this.copyData = [...this.copyData, ...this.preData];
      // pre
      this.preData = this.copyData.splice(0, this.pageOptions.pageSize);
      // next
      this.nextData = this.copyData.slice(0, this.pageOptions.pageSize);
    },
    /**
     * 监听滚动的距离
     */
    handleDataScorll() {
      if (
        Math.abs(this.translateY) <
        this.pageOptions.pageSize * this.itemWidth
      ) {
        return;
      }
      // this.stop();
      // 第一页已滚动完成
      if (this.virtual) {
        this.splitData();
      }
      this.translateY = 0;
    },
    stop() {
      if (this.animationFrame) {
        cancelAnimationFrame(this.animationFrame);
      }
    }
  },
};

示例中仅实现竖向滚动,横向滚动后续会追加props属性mode进行逻辑处理。

4. 通过el-select实现联级选择

Element提供的Cascader,但设计师可能需要的是并排的多个下拉,进行控制。

主要的实现逻辑:

  1. 通过level指定联动选择的层级数量。通过循环渲染出el-select,

  2. 还有最关键的实现分级数据, 从data中分级出每一级level数据。视图中则通过optionsData[index]获取数据

  optionsData: function () {
    let arr = [[...this.data]]
    for (let id of this.selectedData) {
      if (!id) {
        arr.push([])
        break
      }
      let data = arr[arr.length - 1].find((item) => item.id === id)
      if (!data) {
        arr.push([])
        break
      }
      arr.push(data.children || [])
    }
    return arr
  }
  1. 最重要的是保证selectedData为层级深度长度的数组,这样才能渲染出正确数量的el-select

  2. 每一层级的事件change通过index来更新选中的数据selelctData



组件仅实现了data为静态数据时的逻辑处理,如果数据是动态的呢,比如异步加载联动数据。

后续会开放一些日常开发封装的公共组件。地址暂时不可访问Fun-UI

你可能感兴趣的:(el-table动态渲染列、可编辑单元格、虚拟无缝滚动)