ElementUI解决自定义表头

本文介绍了如何使用v-for实现ElementUI表格中用户自定义列顺序的需求,详细探讨了不同类型的列形态,特别是复杂自定义列的处理,通过动态组件和render函数来解决。文中给出了HTML和TypeScript的示例代码,并对比了iview的配置方式,强调了Vue中slot-scope的弃用建议。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

开门见山,我直接阐述我的问题的由来:

根据Element官方的Demo,使用其渲染一个表格需要以下代码:

<el-table
    :data="data"
    stripe border>
    <el-table-column
      prop="date"
      label="日期"
      width="180">
    </el-table-column>
    <el-table-column
      prop="name"
      label="姓名"
      width="180">
    </el-table-column>
    <el-table-column
      prop="address"
      label="地址">
    </el-table-column>
  </el-table>

在此,我们不讨论多级表头及各种骚操作,假设项目经理提出了一个新的需求。”不同的用户表格需要展示的列不同,不同用户可以根据自己的使用偏好自定义表格列的顺序(序号列不参与)。“

我们开始着手实现这个需求,我们提出两个实现方案:1、v-if;2、v-for;

本文主要阐述以v-for来实现这一需求,因此对于方案1的实现仅仅阐述思路。v-if仅仅可以根据权限的不同实现表格展示特定的列,单表格的顺序是没法控制的,在编码的时候就被局限了。通过保留一个JSON,为表格的每个字段分配一个布尔变量,对于每个<el-table-column /> 使用v-if,编码繁琐,使用及其不便还不能完全实现需求。

下面开始阐述v-for的实现细节:

我们首先分析<el-table-column />有几种形态。1、checkbox列;2 、序号列;3、标准列(标准列很简单,就是行数据是什么样,就展示成什么样,如上述代码所示);4、自定义显示内容列(划重点);自定义列有两类,4.1是当前列的内容由行数据的多个字段确定;4.2 当前列渲染出来的html片段需要能触发事件;4.2是整个需求里最复杂的点,因为我们在v-for的时候是没法像x写寻常的时候写如下代码:

<el-table-column label="操作">
    <template slot-scope="scope">
        <span @click="someHandler(scope.row)">Click Me!</span>
    </template>
</el-table-column>

此时,我们需要用到动态组件,先直接贴代码,随后进行解释:

html部分:

<template>
  <el-table-column
    :label="column.label"
    :prop="column.prop"
    :width="column.width"
    :min-width="column.minWidth"
    :header-align="column.align"
    :sortable="column.sortable"
    :fixed="column.fixed"
    :sort-method="column.sortMethod"
    show-overflow-tooltip
  >
    <template v-if="!column.columns" #default="{ row }">
      <a
        class="f-csp"
        v-if="column.routeHandler"
        @click="column.routeHandler(row)"
      >{{ row[column.prop] }}</a>
      <div v-else-if="column.html" v-html="column.html(row)"></div>
      <component v-else-if="column.component" :is="column.component.name" :row="row"></component>
      <div
        v-else
        :class="$ui.renderColumnClass(row, column)"
        v-html="$ui.renderColumn(row, column)"
      ></div>
    </template>
    <template v-if="column.columns">
      <base-table-column
        v-for="subColumn in column.columns"
        :key="subColumn.prop"
        :column="subColumn"
      ></base-table-column>
    </template>
  </el-table-column>
</template>

JS部分(基于TypeScript):


import { Vue, Component, Prop } from 'vue-property-decorator';
import { CustomColumn } from '@/types';
@Component({
  name: 'BaseTableColumn',
})
export default class BaseTableColumn extends Vue {
  @Prop({ type: Object, required: true }) column!: CustomColumn;
  created() {
    if (this.column.component) {
      Vue.component(this.column.component.name, {
        props: {
          row: {
            type: Object,
            required: true,
          },
        },
        render: this.column.component.render,
      });
    }
  }
}

在HTML部分有一个关键的标签是<component />,传送门

于是,我们在基础组件创建的时候,全局注册一个名为this.column.component.name的组件。Vue的组件html部分有2种形态,一种是写在单文件里面的html代码的形式。另一种是使用render函数的形式。其实最终都是转换为render形式,只不过前者需要经过vue的compile变成render函数的形式,使得我们开放上书写更简洁。render函数请参看:Here

基础组件编写完成,假设我们需要往我们的基础组件传递columns的数组,当我们在外部使用的时候对于这类列只需要编写代码如下:

[{
          label: '评分次数',
          prop: 'scoreCounter',
          width: '80',
          render: (col: any) => {
            return typeof col == 'undefined' ? '暂无评分' : col;
          },
          component: {
            name: 'RateEntry',
            render(h) {
              let row = this.$props.row;
              let empty = typeof row.scoreCounter == 'undefined' || row.scoreCounter <= 0;
              return h(
                'span',
                {
                  class: {
                    'f-csp': !empty,
                  },
                  style: {
                    color: empty ? 'black' : '#337ab7',
                    textDecoration: empty ? 'none' : 'underline',
                  },
                  on: {
                    click: (e: Event) => {
                        // do something that you want to do
                    },
                  },
                },
                empty ? '暂无评分' : row.scoreCounter,
              );
            },
          },
        },]

注意,在render函数里面的this并不是vm。

我在之前使用过iview,iview是通过配置实现表格列的展示,个人观点是它把这一过程于内部进行了隐藏。

写在最后:slot-scope 或者 scope 已经不再推荐使用,详情请看Here

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值