当前位置:   article > 正文

两种方式对el-table二次封装

el-table二次封装

1、序言

        完整源码:el-table-example: 两种方式对el-table二次封装

        最近在公司写了好多的后台管理系统,管理系统很大部分都是elementui下的el-table,el-table中有很多 <el-table-column></el-table-column>是重复的,像这样:

        能不能通过配置项让其自动生成 <el-table-column></el-table-column>,省去冗余代码。下一次管理系统添加新模块相似的内容,就不用复制粘贴了。有一说一,复制粘贴完成需求速度非常快、并且效果不错,但是代码就像屎山,冗余度、可维护性都比较差,长期复制粘贴没什么成长!

2、自定义组件方式封装el-table

  2.1、封装

        (1)在src下建立components文件夹

        (2)在components文件夹下建立Table/index.vue、index.js两个文件夹

        (3)index.js文件全局注册封装的Table组件

  1. import Vue from 'vue';
  2. import Table from './index.vue';
  3. /* 封装的表格组件 */
  4. // 全局注册<Table>组件
  5. Vue.component('CommonTable', Table);

        (4)index.vue文件封装Table组件

        遇到一些自定义列就使用作用域名插槽填充,名称为prop值,并在coloum中配置slot属性。像这样:

  1. <!-- 表格组件 -->
  2. <template>
  3. <div>
  4. <el-table :data="data" stripe style="width: 100%" v-loading="loading" @selection-change="handleSelectionChange">
  5. <!--选择-->
  6. <el-table-column v-if="hasSelection" type="selection" width="55" />
  7. <!--序号-->
  8. <el-table-column v-if="hasIndex" type="index" width="55" />
  9. <!--数据源-->
  10. <template v-for="(column, index) in columns">
  11. <!-- 表头存在type类型 -->
  12. <el-table-column v-if="
  13. column.type &&
  14. (column.type == 'selection' || column.type == 'index')
  15. " :type="column.type" />
  16. <!-- 表头是数据或操作内容 -->
  17. <el-table-column v-else :label="column.label">
  18. <template v-if="!column.type" slot-scope="{ row, $index}">
  19. <slot v-if="column.slot" :name="column.slot" :row="row" :index="$index" />
  20. <span v-else>{{ row[column.prop] }}</span>
  21. </template>
  22. </el-table-column>
  23. </template>
  24. </el-table>
  25. </div>
  26. </template>
  27. <script>
  28. export default {
  29. name: 'Table',
  30. props: {
  31. loading: {
  32. type: Boolean,
  33. default: () => false
  34. },
  35. // 是否可以选择
  36. hasSelection: {
  37. type: Boolean,
  38. default: () => false
  39. },
  40. // 是否有序列项
  41. hasIndex: {
  42. type: Boolean,
  43. default: () => false
  44. },
  45. // 这是相应的字段展示
  46. columns: {
  47. type: Array,
  48. default: () => []
  49. },
  50. // 这是数据源
  51. data: {
  52. type: Array,
  53. default: () => []
  54. }
  55. },
  56. methods: {
  57. // 将选中的行发送到父组件
  58. handleSelectionChange(val) {
  59. const selectionArr = []
  60. val.forEach(item => {
  61. selectionArr.push(item)
  62. })
  63. this.$emit('commitSelection', selectionArr)
  64. },
  65. },
  66. }
  67. </script>

         (5)main.js中引入全局注册组件

  1. import Vue from 'vue'
  2. import App from './App.vue'
  3. import router from './router'
  4. import store from './store'
  5. import "./assets/css/main.css";
  6. /* 全局注册的组件 */
  7. import './components/Table/index'; // 表格组件
  8. new Vue({
  9. router,
  10. store,
  11. render: h => h(App)
  12. }).$mount('#app')

  2.2、使用

  1. <template>
  2. <div>
  3. <common-table :columns="columns" :data="tableData">
  4. <template slot="isPublic" slot-scope="{ row }">
  5. {{ transformPublic(row.isPublic) }}
  6. </template>
  7. <template slot="operation" slot-scope="{ row }">
  8. <el-button type="primary">
  9. 编辑
  10. </el-button>
  11. <el-button type="danger">
  12. 删除
  13. </el-button>
  14. </template>
  15. </common-table>
  16. </div>
  17. </template>
  18. <script>
  19. export default {
  20. data() {
  21. return {
  22. tableData: [{
  23. id: 11,
  24. name: '绿色天使幼儿园',
  25. count: 100,
  26. address: '北京',
  27. isPublic: 1,
  28. }, {
  29. id: 22,
  30. name: '金苹果幼儿园',
  31. count: 200,
  32. address: '上海',
  33. isPublic: 1,
  34. }, {
  35. id: 33,
  36. name: '童趣幼儿园',
  37. count: 300,
  38. address: '广州',
  39. isPublic: 0,
  40. }, {
  41. id: 44,
  42. name: '快乐星球幼儿园',
  43. count: 400,
  44. address: '深圳',
  45. isPublic: 0,
  46. }],
  47. columns: [
  48. { prop: 'id', label: 'id' },
  49. { prop: 'name', label: '名称' },
  50. { prop: 'count', label: '人数' },
  51. { prop: 'isPublic', label: '是否公办', slot: 'isPublic' },
  52. { prop: 'address', label: '地址' },
  53. {
  54. label: "操作",
  55. slot: "operation"
  56. }
  57. ]
  58. }
  59. },
  60. computed: {
  61. transformPublic() {
  62. return function (isPublic) {
  63. let t = {
  64. 1: '是',
  65. 0: '否'
  66. }
  67. return t[isPublic]
  68. }
  69. }
  70. }
  71. }
  72. </script>
  73. <style scoped></style>

3、jsx方式封装el-table

  3.1、jsx

        我看网上还有使用jsx方式来封装el-table,jsx能够抽象组件,jsx是一种javascript和xml结合的一种语法,它既有javascript的灵活性,也有xml的规范性,但是有一说一,写起来真不习惯、真不舒服!

        babel能将es6转换成es5,还能将jsx转换成javascript,所以babel插件必不可少!惊喜的发现脚手架cli已经配置好babel插件,基本可以直接上手写jsx了!jsx语法和vue语法还是有一些差别的,详细去看看网上例子,掌握好它上手react比较容易!

        写jsx记得要把vue中的template、script、style标签去掉

  3.2、封装

        (1)src/components/JsxTable/index.js 建立文件夹

        (2)render()中 return <div> <el-table></el-table>  </div>

        (3)自定义指令v-loading还有语法糖@selection-change 使用不了,需要转译一下让jsx识别

  1. // @selection-change语法糖没法在jsx直接使用,需要转译一下
  2. const listeners = {
  3. on: {
  4. ['selection-change']: val => this.$emit('commitSelection', val)
  5. }
  6. };
  7. // v-loading没法在jsx直接使用,需要转译一下
  8. const directives = {
  9. directives: [{ name: 'loading', value: loading }]
  10. };

        (4)attrs和scopedSlots 

        attrs 属性是用于将父组件属性传递(除了 prop 传递的属性、class 和 style )给子组件, 这通常用于将事件监听器和自定义属性传递给子组件。

        scopedSlots 是用于将父组件的作用域插槽(scoped slot)传递给子组件,以便子组件可以在父组件提供的数据上进行渲染。在父组件中,标签并设置slot-scope属性来创建作用域插槽,然后在子组件中使用this.$slots属性来获取这些插槽

  1. // 渲染列
  2. const renderColumn = () => {
  3. return columns.map(item => {
  4. const attribute = {
  5. attrs: { ...item }
  6. };
  7. if (item.slot) {
  8. attribute.scopedSlots = {
  9. default: this.$scopedSlots[item.slot]
  10. };
  11. }
  12. return <el-table-column {...attribute} />;
  13. });
  14. };

        (5)将属性、事件、指令组装到el-table中,并通过render()返回组装好的el-table

  1. // 渲染表格
  2. const renderTable = (
  3. <el-table data={dataList} {...listeners} {...directives} style="width: 100%" >
  4. {renderColumn()}
  5. </el-table >
  6. );
  7. return <div>{renderTable}</div>;

  3.3、使用

  1. <template>
  2. <div>
  3. <jsx-table :columns="columns" :dataList="tableData" hasSelection @commitSelection="getselected">
  4. <template slot="isPublic" slot-scope="{ row }">
  5. {{ transformPublic(row.isPublic) }}
  6. </template>
  7. <template slot="operation" slot-scope="scope">
  8. <el-button type="primary">
  9. 编辑
  10. </el-button>
  11. <el-button type="danger">
  12. 删除
  13. </el-button>
  14. </template>
  15. </jsx-table>
  16. </div>
  17. </template>
  18. <script>
  19. import JsxTable from '@/components/JsxTable'
  20. export default {
  21. components: {
  22. JsxTable
  23. },
  24. data() {
  25. return {
  26. tableData: [{
  27. id: 11,
  28. name: '绿色天使幼儿园',
  29. count: 100,
  30. address: '北京',
  31. isPublic: 1,
  32. }, {
  33. id: 22,
  34. name: '金苹果幼儿园',
  35. count: 200,
  36. address: '上海',
  37. isPublic: 1,
  38. }, {
  39. id: 33,
  40. name: '童趣幼儿园',
  41. count: 300,
  42. address: '广州',
  43. isPublic: 0,
  44. }, {
  45. id: 44,
  46. name: '快乐星球幼儿园',
  47. count: 400,
  48. address: '深圳',
  49. isPublic: 0,
  50. }],
  51. columns: [
  52. { prop: 'id', label: 'id' },
  53. { prop: 'name', label: '名称' },
  54. { prop: 'count', label: '人数' },
  55. { prop: 'isPublic', label: '是否公办', slot: 'isPublic' },
  56. { prop: 'address', label: '地址' },
  57. {
  58. label: "操作",
  59. slot: "operation"
  60. }
  61. ]
  62. }
  63. },
  64. methods: {
  65. // 获取选中行
  66. getselected(val) {
  67. console.log('val:', val);
  68. }
  69. },
  70. computed: {
  71. transformPublic() {
  72. return function (isPublic) {
  73. let t = {
  74. 1: '是',
  75. 0: '否'
  76. }
  77. return t[isPublic]
  78. }
  79. }
  80. }
  81. }
  82. </script>
  83. <style scoped></style>
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/621622
推荐阅读