优雅的使用 element-ui 中的 table 组件

63,905 阅读4分钟

经常使用 element-ui 的小伙伴应该对 el-table 组件非常熟悉,通常它长下面这个样子:

<template>
  <el-table :data="tableData">
    <el-table-column
      prop="date"
      label="日期">
    </el-table-column>
    <el-table-column
      prop="name"
      label="姓名">
    </el-table-column>
    <el-table-column
      prop="address"
      label="地址">
    </el-table-column>
  </el-table>
</template>

<script>
export default {
  data () {
    return {
      tableData: [{
        date: '2016-05-02',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1518 弄'
      }, {
        date: '2016-05-04',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1517 弄'
      }]
    }
  }
}
</script>

上面代码非常正确,但总觉的少了点什么?

没错,模版中 el-table-column 几乎一致,重复写了

使用 v-for 来优化模版中的 el-table-column

下面是采用 v-for 的版本,将每一列作为一个配置项传入:

<template>
  <el-table :data="tableData">
    <el-table-column
      v-for="{ prop, label } in colConfigs"
      :key="prop"
      :prop="prop"
      :label="label">
    </el-table-column>
  </el-table>
</template>

<script>
export default {
  data () {
    this.colConfigs = [
      { prop: 'date', label: '日期' },
      { prop: 'name', label: '姓名' },
      { prop: 'address', label: '地址' }
    ]
    return {
      tableData: [{
        date: '2016-05-02',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1518 弄'
      }, {
        date: '2016-05-04',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1517 弄'
      }]
    }
  }
}
</script>

这样做的好处在于,如果想再增加一列,完全可以不用动 template,只需要简单的在 this.colConfigs 这个数组中增加一个配置项 { prop: 'xxx', label: 'xxx' } 即可

虽然这样加个配置非常简单,扩展性也比之前直接写模版好,但是如果我有一列是要渲染几个按钮,上面的方式就不起作用了

换句话说,我们即想要简单的属性可以直接加个配置项渲染出来,又希望复杂的渲染能在模版中写出来,要怎么实现呢?

巧用 slot,为 el-table 封装一层

我们先来看一下封装的组件 my-table

// my-table.vue
<template>
  <el-table :data="data">
    <template v-for="colConfig in colConfigs">
      <slot v-if="colConfig.slot" :name="colConfig.slot">
      <el-table-column v-bind="colConfig"></el-table-column>
    </template>  
  </el-table>
</template>

<script>
export default {
  props: ['colConfigs', 'data']
}
</script>

这个封装实际上就是把前面的 colConfigs 作为一个 prop 传入,但是跟上面例子有一点不同的是,配置项中多了一个 slot 属性,通过这个属性,我们就可以像文章最开始那样在模版中写了,用法如下:

<template>
  <my-table
    :data="tableData"
    :col-configs="colConfigs">
    <!-- slot="opt" 不能省略,需要与下面配置项中的对应 -->
    <el-table-column slot="opt">
      <el-button size="mini" slot-scope="{ row }">查看</el-button>
    </el-table-column>
  </my-table>
</template>

<script>
export default {
  data () {
    this.colConfigs = [
      { prop: 'date', label: '日期' },
      { prop: 'name', label: '姓名' },
      { prop: 'address', label: '地址' },
      // 模版中的元素需要对应的有 slot="opt" 属性
      { slot: 'opt' }
    ]
    return {
      tableData: [{
        date: '2016-05-02',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1518 弄'
      }, {
        date: '2016-05-04',
        name: '王小虎',
        address: '上海市普陀区金沙江路 1517 弄'
      }]
    }
  }
}
</script>

现在我们想要增加一个列,只要加个配置项,或者加个 slot ,完美~

等等,假设我的 table 中有几列渲染比较复杂,那几列又都比较相似,像下面这种:

<template>
  <my-table
    :data="tableData"
    :col-configs="colConfigs">
    <el-table-column label="变化" slot="change">
      <span :slot-scope="row">
        {{ row['change'] > 0 ? '+' + row['change']: row['change'] }}
      </span>
    </el-table-column>
    <el-table-column label="趋势" slot="trend">
      <span :slot-scope="row">
        {{ row['trend'] > 0 ? '+' + row['trend']: row['trend'] }}
      </span>
    </el-table-column>
  </my-table>
</template>

又重复写模版了...

使用 :is="component"

我们可以为配置项再增加一个属性 component, 用户可以指定 component 属性来特殊处理某列,实现如下:

// my-table.vue
<template>
  <el-table :data="data">
    <template v-for="colConfig in colConfigs">
      <slot v-if="colConfig.slot" :name="colConfig.slot">
      <component
        v-else-if="colConfig.component"
        :is="config.component" 
        :col-config="colConfig">
      </component>
      <el-table-column v-else v-bind="colConfig"></el-table-column>
    </template>  
  </el-table>
</template>

<script>
export default {
  props: ['colConfigs', 'data']
}
</script>

然后上面的例子就可以改写成:

<template>
  <my-table
    :data="tableData"
    :col-configs="colConfigs">
  </my-table>
</template>
<script>

const PrefixPlusText = {
  props: ['colConfig'],
  template: `
    <el-table-column :label="colConfig.label">
      <span :slot-scope="{ row }">
        {{ parseInt(row[colConfig.prop]) > 0 ? '+' + row[colConfig.prop] : row[colConfig.prop] }}
      </span>
    </el-table-column>
  `
}

export default {
  data () {
    this.colConfigs = [
      { prop: 'change', label: '变化' component: PrefixPlusText },
      { prop: 'name', label: '趋势', component: PrefixPlusText },
    ]
    return {
      tableData: [{
        change: '12%',
        trend: '10%
      }, {
        change: '-12%',
        trend: '-10%'
      }]
    }
  }
}
</script>

总结

table 作为数据展示组件,在日常开发中经常被用到,通过这篇文章,可以看到结合 vueslot/component 特性,做一层封装,可以大大简化 table 的使用,大部分时候只需写一个配置属性就可以了。

最后给一个小 demo