vue对el-table的二次封装,双击单元格编辑,避免表格输入框过多卡顿

vue对el-table的二次封装,双击单元格编辑,避免表格输入框过多卡顿

为什么要做这个

项目中表格能编辑的单元格越来越多,界面慢慢的变得卡顿,起初准备自定义每个单元格默认为文字,双击聚焦输入,输入失焦切换回文字,但是这样没有通用性,每次都得copy一份,比较麻烦,于是就想做个封装

怎么做?

先上完整代码

封装文件name:MyTable

<template>
  <el-table v-bind="$attrs" v-on="$listeners" :data="tableData" @cell-dblclick="cellDblclick">
    <template v-for="(item, index) in myColumns">
      <!-- 如果是序号、选择器、或只需要展示的数据就直接展示 -->
      <el-table-column
        :key="item.prop + '#' + index"
        :type="item.type"
        width="55px"
        v-if="['index', 'selection'].includes(item.type)"
      >
      </el-table-column>
      <el-table-column
        :key="item.prop + '#' + index"
        :label="item.label"
        :prop="item.prop"
        v-else-if="item.justShow"
      >
      </el-table-column>
      <!-- 否则先展示为文字,双击渲染为下拉、输入、文本域等输入框 -->
      <el-table-column v-bind="item" :key="item.prop + '##' + index" v-else>
        <template slot-scope="scope">
          <template v-if="formViewMethod(scope, index)">
            <component
              :is="
                typeof item.render === 'function'
                  ? handleRendel(item.render, scope)
                  : item.render
              "
              :scope="scope"
            ></component>
          </template>

          <span v-else v-html="scope.row[item.prop]"></span>
        </template>
      </el-table-column>
    </template>
  </el-table>
</template>

<script>
export default {
  name: "MyTable",
  props: {
    myColumns: {
      require: true,
    },
    tableData: {
      type: Array,
      default: () => []
    },
  },
  data() {
    return {
      editColumnId: null,
      editRowIndex: -1,
    };
  },
  methods: {
    formViewMethod(scope) {
      return (
        scope.$index === this.editRowIndex &&
        this.editColumnId === scope.column.id
      );
    },
    handleRendel(renderFunc, scope) {
      let cel = this.$createElement;
      return {
        render: () => {
          return renderFunc(cel, scope);
        },
      };
    },
    /**
     * 双击单元格开启编辑模式
     *@param {paraName}
     */
    cellDblclick(row, column, cell) {
      // console.log(row, column, cell, event);
      this.editColumnId = column.id;
      this.editRowIndex = this.tableData.findIndex((item) => item === row);
      // 切换为输入状态时自动聚焦
      this.$nextTick(() => {
        // 日期和输入框可以聚焦,但是下拉选择不会展开
        cell.querySelector(".el-input__inner")?.focus();
        // 下拉选择可用下面的,建议用row.prop或自定义一个名称自行判断下
        // cell.querySelector(".el-input__inner")?.click();
      });
    },
  },
};
</script>

复制代码
使用:
<template>
  <div>
    <my-table :myColumns="columns" :tableData="tableData"></my-table>
  </div>
</template>

<script>
import MyTable from "./MyTable.vue";
export default {
  name: "UseMyTable",
  components: {
    MyTable,
  },
  data() {
    return {
      columns: [
        {
          label: "序号",
          type: "index",
        },
        {
          label: "全选",
          type: "selection",
        },
        {
          label: "姓名",
          prop: "name",
          justShow: true,
        },
        {
          label: "日期",
          prop: "date",
          render: (h, { row }) => {
            return (
              <el-date-picker
                v-model={row.date}
                type="date"
                placeholder="选择日期"
              ></el-date-picker>
            );
          },
        },
        {
          label: "地址",
          prop: "address",
          render: (h, { row }) => {
            return <el-input v-model={row.address}></el-input>;
          },
        },
        {
          label: "选择",
          prop: "selectDate",
          render: (h, { row }) => {
            return (
              <el-select v-model={row.selectDate}>
                <el-option label="111" value="111"></el-option>
                <el-option label="222" value="222"></el-option>
              </el-select>
            );
          },
        },
      ],
      tableData: [
        {
          date: "2016-05-02",
          name: "王小虎",
          address: "上海市普陀区金沙江路 1518 弄",
          selectDate: "",
        },
        {
          date: "2016-05-04",
          name: "王小虎",
          address: "上海市普陀区金沙江路 1517 弄",
          selectDate: "",
        },
      ],
    };
  },
};
</script>

复制代码
关键位置说明
  • 双击切换的实现

首先利用el-table的cell-dblclick的事件,通过它的回调参数row, column计算出点击的哪一个单元格editColumnId和editRowIndex,然后通过这两个值将编辑的单元格渲染出来,其他的一律为非编辑状态。

渲染出来后,利用cell-dblclick的第三个参数cell实现自动聚焦输入,提升用户体验

cellDblclick(row, column, cell) {
  // console.log(row, column, cell, event);
  this.editColumnId = column.id;
  this.editRowIndex = this.tableData.findIndex((item) => item === row);
  // 切换为输入状态时自动聚焦
  this.$nextTick(() => {
    // 日期和输入框可以聚焦,但是下拉选择不会展开
    cell.querySelector(".el-input__inner")?.focus();
    // 下拉选择可用下面的,建议用row.prop或自定义一个名称自行判断下
    // cell.querySelector(".el-input__inner")?.click();
  });
},
复制代码
  • render渲染,注意套一层将参数传入
<component
  :is="
    typeof item.render === 'function'
      ? handleRendel(item.render, scope)
      : item.render
  "
  :scope="scope"
></component>
复制代码

效果图

image.png

image.png

image.png

存在的问题

  • el-select不能通过上面的focus自动展开,需要用click事件,可以在row里面的单独定义一个标识特殊处理

  • 不双击别的单元格的话,前一个单元格不会变成文本状态。

初步考虑在document上加点击回调,点击表格外面就将编辑位置置为空(editColumnId和editRowIndex)

  • 输入框和文本高度不一样,切换状态时表格高度会变化,不好看,得调整样式
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享