vue之JSX封装table

封装之前先看下 (opens new window)

babel-plugin-transform-vue-jsx (opens new window)

基于ElementUI的table二次封装

最近搞中台开发,用的ElementUI的Table组件比较多,几乎每个页面都用,相比react的antd,饿了么的table就相对臃肿了,可能是因为框架的原因吧。

本次封装用的jsx语法,vue模板拓展性不是特别显优势,没有jsx灵活。想看jsx在vue中怎么使用的请转看下之前的文章

# 组件封装源码

//EnhanceTable.jsx
import table from "../mixins/table"

export default {
  mixins: [table],
  props: {
    otherTableParams: { // 设置table其他参数
      type: Object,
       default: function () {
        return {}; // Object/Array的属性必须使用函数返回默认值  箭头函数不行
      }
    },
    otherPaginationParams: { // 设置分页其他参数
      type: Object,
       default: function () {
        return {};
      }
    },
    tableColumn: { // table的column
      type: Array,
       default: function () {
        return [];
      }
    },
    multiple: {
      type: Boolean,
      default: false
    },
  },
  methods: {
    handleButtons(item, record) {
      // 处理操作部分按钮 -> 可以在外面自定义,必须是jsx
      if (item.handleButtons) return item.handleButtons(record);
      return (
        !!item.list.length && item.list.map((item) => {
          return (
            <el-button
              disabled={item.disabled}
              key={item.title}
              type="text"
              size="small"
              style={item.styles}
              onClick={() => item.cb(record)}
            >
              {item.title}
            </el-button>
          )
        })
      );
    }
    // handleCurrentChange(val) {
    //   this.$emit('currentChange', val);
    // },
  },
  mounted() {
  },
  render() {
    const {tableOptions, paginationOptions, paginationOptionsMethod, tableOptionsMethod, otherTableParams, tableColumn, multiple} = this;
    return (
      <div>
        <el-table
          {...{
            props: {
              ...tableOptions,
              ...otherTableParams.props,
            },
            on: {
              ...tableOptionsMethod,
              ...otherTableParams.on
            }
          }}
        >
          {/* table多选 */}
          {
            multiple && (
              <el-table-column
                type="selection"
                width="55"
                fixed={'left'}
              />
            )
          }
          {/* table列表 */}
          {
            tableColumn.map((item) => {
              if (item.type === 'button') {
                // 操作部分
                return (
                  <el-table-column
                    label={item.label || '操作'}
                    width={item.width || '88'}
                    fixed={item.fixed || 'right'}
                    {...{
                      scopedSlots: {
                        default: ({row}) => {
                          return this.handleButtons(item, row)
                        }
                      }
                    }}
                  />
                )
              }
              return (
                <el-table-column
                  props={item}
                  key={item.prop}
                  {...{
                    // 自定义的渲染方式,拓展性
                    scopedSlots: {
                      default: ({row}) => {
                        return item.render ? item.render(row[item.prop], row) : row[item.prop]
                      }
                    }
                  }}
                />
              )
            })
          }
        </el-table>
        {/*分页*/}
        <el-pagination
          {...{
            class: paginationOptions.class,  // 支持拓展
            props: {
              ...paginationOptions,
            },
            on: {
              ...paginationOptionsMethod
            },
          }}
        />
      </div>
    );
  }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135

# EnhanceTable 文档

# 组件使用

<template>
    <enhance-table ref="table" :multiple="true" :otherTableParams="otherTableParams" :tableColumn="column"
    />
</template>
<script>
  import EnhanceTable from "../components/EnhanceTable"

  export default {
    data() {
      return {
        otherTableParams: {// table的参数
          props: {
            border: true,
            stripe: true,
            size: 'small',
            'default-sort': {prop: 'createTime', order: 'ascending'}
          }
        },
        otherPaginationParams:{},// 分页的参数
        column: [  // table的列
          {
            prop: "roleId",
            label: "序号",
            width: 100,
          },
          {
            prop: 'roleName',
            label: "角色名称",
            'width': "110"
          },
          {
            prop: "createTime",
            label: "创建时间",
            sortable: true
          },
          {
            prop: 'roleName',
            label: "角色名称",
            //formatter  完全可以用render代替
            render: (text, record) => { // 当前行的值,当前行数据
              // console.log(record);
              return <h4>{text}</h4>
            },
          },
          { // 最后的操作列,可根据list里面展示要操作的按钮,和回调
            type: 'button',
            width: '118',
            label: "设置",
            list: [
              {title: '查看', disabled: false, styles: {color: '#777'}, cb: this.seeHandle},
              {title: '编辑', cb: this.editHandle}
            ],
            // handleButtons: () => (<div>111</div>)  // 自定义的内容
          }
        ]
      }
    },
    components: {EnhanceTable},
    methods: {
      queryList() { // 子组件默认的请求名称
        this.$nextTick(async () => {  
          // 因为当前算是父组件,当执行到父组件的created周期才会执行它的子组件,所以这个时候子组件的data的一些方法获取不到,或者可以在mounted周期里面执行异步请求
          const {paginationOptions: {pageSize, currentPage}, handlePageData} = this.$refs.table;// 获取子组件mixins里面的参数
          const {data: {items, page: {totalRecord}}} = 
          await this.$fetch(`http://xx..xx/role?pageSize=${pageSize}&pageNum=${currentPage}`, {
            headers: {
              Authentication: 'xxxxx'
            },
          });
          handlePageData(items, totalRecord);  // mixin里面统一处理
        });
      },
      editHandle(...options) {
        console.log(options, '编辑');
      },
      seeHandle(...options) {
        console.log(options, '查看');
      }
    },
    created() {
      this.queryList();//必须是这个名称 
    },
    mounted() {
    }
  }
</script>

<style type="text/scss" lang="scss" scoped>

</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90

# 最后在送一个当前使用的mixins

// table.mixins.js
const table = {
  data() {
    return {
      tableOptions: {
        data: [], // 列表数据
        border: true, // 带边框
        style: "width: 100%",
        size: "small",
        multipleSelection: [], // 列表多选
      },
      tableOptionsMethod: {
        "selection-change": this.handleSelectionChange
      },
      paginationOptions: {
        class: "fyDiv",
        background: true, // 带有背景色
        layout: "total, sizes, prev, pager, next",
        pageSizes: [10, 20, 30, 40],
        total: 0, // 应用列表总数量
        pageSize: 10, // 当前分页数量
        currentPage: 1, // 当前页数第一页
        showPage: false, // 是否显示分页组件,必须total总数也要小于当前要展示的页数
      },
      paginationOptionsMethod: {
        "size-change": this.handleSizeChange,
        "current-change": this.handleCurrentChange
      }
    };
  },
  methods: {
    // 获取数据回调处理分页和data
    handlePageData(data, total) {
      this.tableOptions.data = data;
      // 如果还有下一页,则显示分页插件
      if (total > 10) {
        this.paginationOptions.showPage = false;
      } else {
        this.paginationOptions.showPage = true;
        this.paginationOptions.currentPage = 1;
        this.paginationOptions.pageSize = 10;
      }
      this.paginationOptions.total = total;
    },
    // 选项变化
    handleSelectionChange(multipleSelection) {
      console.log(multipleSelection, "选中");
      this.tableOptions.multipleSelection = multipleSelection;
    },
    // 改变页数
    handleCurrentChange(currentPage) {
      this.paginationOptions.currentPage = currentPage;
      this.queryList ? this.queryList() : this.$parent.queryList();
    },
    // 选择页数
    handleSizeChange(currentSize) {
      this.paginationOptions.pageSize = currentSize;
      this.paginationOptions.currentPage = 1;
      this.queryList ? this.queryList() : this.$parent.queryList();
    },
    // 搜索专用
    handleSearchChange(page = 1, size = 10) {
      this.paginationOptions.pageSize = size;
      this.paginationOptions.currentPage = page;
      this.queryList ? this.queryList() : this.$parent.queryList();
    }
  }
};

export default table;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70

# 写在最后

当前的table组件是针对自己项目的需求封装,兼容了饿了么table大部分的业务场景,随着后期的业务拓展,当前的组件的拓展性也会增强,封装路漫漫,一点点完善吧。