Commit b52e633ca637d904b0cddd7831b5d60437692eea

Authored by 刘汉宸
1 parent 2c334740

feat: 优化Table组件

examples/views/docs/component/table.md
@@ -6,7 +6,7 @@ @@ -6,7 +6,7 @@
6 6
7 基本参数与ElementUI的`el-table`相同。 7 基本参数与ElementUI的`el-table`相同。
8 8
9 -::: snippet 支持`size`继承 9 +::: snippet 支持来自表单的`size`继承
10 10
11 ```html 11 ```html
12 <template> 12 <template>
@@ -44,23 +44,14 @@ export default { @@ -44,23 +44,14 @@ export default {
44 44
45 ```html 45 ```html
46 <template> 46 <template>
47 - <el-form size="mini">  
48 - <el-row>  
49 - <el-col :span="18">  
50 - <z-table v-model="tableData" type="editable" border :columns="columns">  
51 - <template #column-editor-gender="{ value, onInput }">  
52 - <el-radio-group size="mini" :value="value" @input="onInput">  
53 - <el-radio-button label="男">男</el-radio-button>  
54 - <el-radio-button label="女">女</el-radio-button>  
55 - </el-radio-group>  
56 - </template>  
57 - </z-table>  
58 - </el-col>  
59 - <el-col :span="6" style="padding-left: 10px">  
60 - <pre class="demo-model">{{ tableData }}</pre>  
61 - </el-col>  
62 - </el-row>  
63 - </el-form> 47 + <z-table v-model="tableData" type="editable" border :columns="columns">
  48 + <template #editor-gender="{ value, onInput }">
  49 + <el-radio-group size="mini" :value="value" @input="onInput">
  50 + <el-radio-button label="男">男</el-radio-button>
  51 + <el-radio-button label="女">女</el-radio-button>
  52 + </el-radio-group>
  53 + </template>
  54 + </z-table>
64 </template> 55 </template>
65 56
66 <script> 57 <script>
@@ -68,14 +59,15 @@ export default { @@ -68,14 +59,15 @@ export default {
68 data() { 59 data() {
69 return { 60 return {
70 tableData: [ 61 tableData: [
71 - { name: '张三', age: 31, gender: '男' },  
72 - { name: '李四', age: 27, gender: '女' },  
73 - { name: '王五', age: 16, gender: '男' }, 62 + { name: '张三', age: 31, gender: '男', remark: '' },
  63 + { name: '李四', age: 27, gender: '女', remark: '' },
  64 + { name: '王五', age: 16, gender: '男', remark: '' },
74 ], 65 ],
75 columns: [ 66 columns: [
76 { prop: 'name', label: '姓名', editable: false }, 67 { prop: 'name', label: '姓名', editable: false },
77 { type: 'el-input-number', prop: 'age', label: '年龄' }, 68 { type: 'el-input-number', prop: 'age', label: '年龄' },
78 { prop: 'gender', label: '性别' }, 69 { prop: 'gender', label: '性别' },
  70 + { prop: 'remark', label: '备注' },
79 ] 71 ]
80 }; 72 };
81 }, 73 },
@@ -83,4 +75,15 @@ export default { @@ -83,4 +75,15 @@ export default {
83 </script> 75 </script>
84 ``` 76 ```
85 77
86 -:::  
87 \ No newline at end of file 78 \ No newline at end of file
  79 +:::
  80 +
  81 +## API
  82 +
  83 +## Attribute 属性
  84 +
  85 +参数|说明|类型|可选值|默认值
  86 +-|-|-|-|-
  87 +data | 表格数据 | Array | - | -
  88 +value | 表格数据(支持v-model) | Array | - | []
  89 +columns | 表格列配置 | Array | - | []
  90 +type | 表格类型 | String | normal、editable | normal
88 \ No newline at end of file 91 \ No newline at end of file
packages/table/editable.vue
@@ -30,23 +30,21 @@ @@ -30,23 +30,21 @@
30 <el-table :data="tableData | tableDataFilter" :size="tableSize" v-bind="_props" @header-click="onHeaderClick" @cell-click="onCellClick" @cell-dblclick="onCellDblclick"> 30 <el-table :data="tableData | tableDataFilter" :size="tableSize" v-bind="_props" @header-click="onHeaderClick" @cell-click="onCellClick" @cell-dblclick="onCellDblclick">
31 <template v-for="(item, index) in columns"> 31 <template v-for="(item, index) in columns">
32 <el-table-column v-bind="item" :key="index"> 32 <el-table-column v-bind="item" :key="index">
33 - <template #header>  
34 - <span>{{ item.label }}</span>  
35 - </template> 33 + <slot :name="`header-${item.prop}`" slot="header"></slot>
36 <template #default="{ row, column }"> 34 <template #default="{ row, column }">
37 - <table-column-cell  
38 - :disabled="item.editable === false" 35 + <cell-editor
  36 + :disabled="disabled || item.editable === false"
39 :editable="item.editable !== false && (row.$editable || (tableEditCell.index === row.$index && tableEditCell.prop === item.prop))" 37 :editable="item.editable !== false && (row.$editable || (tableEditCell.index === row.$index && tableEditCell.prop === item.prop))"
40 :type="item.type" 38 :type="item.type"
41 :value="row[column.property]" 39 :value="row[column.property]"
42 @input="onCellInput" 40 @input="onCellInput"
43 - @edit-click="onCellDblclick(row, column)"  
44 - @edit-confirm="onHeaderClick" 41 + @edit-click="setEditCell(row, column)"
  42 + @edit-confirm="cancelEditCell"
45 > 43 >
46 - <template v-if="$scopedSlots[`column-editor-${item.prop}`]">  
47 - <slot :name="`column-editor-${item.prop}`" :value="row[column.property]" :onInput="onCellInput"></slot> 44 + <template v-if="$scopedSlots[`editor-${item.prop}`]">
  45 + <slot :name="`editor-${item.prop}`" :value="row[column.property]" :onInput="onCellInput"></slot>
48 </template> 46 </template>
49 - </table-column-cell> 47 + </cell-editor>
50 </template> 48 </template>
51 </el-table-column> 49 </el-table-column>
52 </template> 50 </template>
@@ -62,16 +60,12 @@ export default { @@ -62,16 +60,12 @@ export default {
62 name: 'TableEditable', 60 name: 'TableEditable',
63 extends: TableNormal, 61 extends: TableNormal,
64 components: { 62 components: {
65 - tableColumnCell: { 63 + cellEditor: {
66 props: { 64 props: {
67 value: [String, Number, Array, Object], 65 value: [String, Number, Array, Object],
68 type: { type: String, default: 'el-input' }, 66 type: { type: String, default: 'el-input' },
69 editable: Boolean, 67 editable: Boolean,
70 disabled: Boolean, 68 disabled: Boolean,
71 - showHandler: {  
72 - type: Boolean,  
73 - default: true,  
74 - },  
75 }, 69 },
76 watch: { 70 watch: {
77 editable(val) { 71 editable(val) {
@@ -84,7 +78,7 @@ export default { @@ -84,7 +78,7 @@ export default {
84 }, 78 },
85 render(h) { 79 render(h) {
86 if (this.editable) { 80 if (this.editable) {
87 - let editRender = [ 81 + let editorRender = [
88 h(this.type, { 82 h(this.type, {
89 props: { value: this.value, size: 'mini' }, 83 props: { value: this.value, size: 'mini' },
90 on: { 84 on: {
@@ -95,21 +89,21 @@ export default { @@ -95,21 +89,21 @@ export default {
95 }), 89 }),
96 ]; 90 ];
97 if (this.$scopedSlots.default) { 91 if (this.$scopedSlots.default) {
98 - editRender = [this.$scopedSlots.default()]; 92 + editorRender = [this.$scopedSlots.default()];
99 } 93 }
100 - if (this.showHandler !== false) { 94 + if (!this.disabled) {
101 const handlerItems = [h('i', { attrs: { title: '确定', class: 'el-icon-check' }, on: { click: () => this.$emit('edit-confirm') } })]; 95 const handlerItems = [h('i', { attrs: { title: '确定', class: 'el-icon-check' }, on: { click: () => this.$emit('edit-confirm') } })];
102 // handlerItems.push(h('i', { attrs: { title: '取消', class: 'el-icon-close' }, on: { click: () => this.$emit('edit-confirm') } })); 96 // handlerItems.push(h('i', { attrs: { title: '取消', class: 'el-icon-close' }, on: { click: () => this.$emit('edit-confirm') } }));
103 const handler = h('span', handlerItems); 97 const handler = h('span', handlerItems);
104 - editRender.push(handler); 98 + editorRender.push(handler);
105 } 99 }
106 - return h('span', { class: 'z-table-column__cell-editable' }, editRender); 100 + return h('span', { class: 'z-table-column__cell-editable' }, editorRender);
107 } 101 }
108 - const defauleRender = [this.value];  
109 - if (!this.disabled && this.showHandler !== false) {  
110 - defauleRender.push(h('i', { attrs: { title: '编辑', class: 'el-icon-edit' }, on: { click: () => this.$emit('edit-click') } })); 102 + const valueRender = [h('span', this.value)];
  103 + if (!this.disabled) {
  104 + valueRender.push(h('i', { attrs: { title: '编辑', class: 'el-icon-edit' }, on: { click: () => this.$emit('edit-click') } }));
111 } 105 }
112 - return h('span', { class: 'z-table-column__cell-editable' }, defauleRender); 106 + return h('span', { class: 'z-table-column__cell-editable' }, valueRender);
113 }, 107 },
114 }, 108 },
115 }, 109 },
@@ -126,6 +120,8 @@ export default { @@ -126,6 +120,8 @@ export default {
126 return []; 120 return [];
127 }, 121 },
128 }, 122 },
  123 + clickable: Boolean,
  124 + disabled: Boolean,
129 ...tableProps, 125 ...tableProps,
130 }, 126 },
131 watch: { 127 watch: {
@@ -146,21 +142,30 @@ export default { @@ -146,21 +142,30 @@ export default {
146 return value.map((item, index) => ({ ...item, $index: index })); 142 return value.map((item, index) => ({ ...item, $index: index }));
147 }, 143 },
148 }, 144 },
149 - // mounted() {  
150 - // console.log(this.$scopedSlots);  
151 - // },  
152 methods: { 145 methods: {
153 onHeaderClick() { 146 onHeaderClick() {
154 - this.tableEditCell = {}; 147 + if (this.clickable) {
  148 + this.cancelEditCell();
  149 + }
155 }, 150 },
156 - onCellClick(row, column, cell, event) {  
157 - if (row.$index !== this.tableEditCell.index || column.property !== this.tableEditCell.prop) {  
158 - this.tableEditCell = {}; 151 + onCellClick(row, column) {
  152 + if (this.clickable) {
  153 + if (row.$index !== this.tableEditCell.index || column.property !== this.tableEditCell.prop) {
  154 + this.tableEditCell = {};
  155 + }
159 } 156 }
160 }, 157 },
161 - onCellDblclick(row, column, cell, event) { 158 + onCellDblclick(row, column) {
  159 + if (this.clickable) {
  160 + this.setEditCell(row, column);
  161 + }
  162 + },
  163 + setEditCell(row, column) {
162 this.tableEditCell = { index: row.$index, prop: column.property }; 164 this.tableEditCell = { index: row.$index, prop: column.property };
163 }, 165 },
  166 + cancelEditCell() {
  167 + this.tableEditCell = {};
  168 + },
164 onCellInput(value) { 169 onCellInput(value) {
165 const tableData = cloneDeep(this.tableData); 170 const tableData = cloneDeep(this.tableData);
166 const tableRow = tableData[this.tableEditCell.index]; 171 const tableRow = tableData[this.tableEditCell.index];
packages/table/index.js
@@ -19,6 +19,8 @@ export default { @@ -19,6 +19,8 @@ export default {
19 return []; 19 return [];
20 }, 20 },
21 }, 21 },
  22 + clickable: Boolean,
  23 + disabled: Boolean,
22 ...tableProps, 24 ...tableProps,
23 }, 25 },
24 render(h) { 26 render(h) {
packages/table/normal.vue
@@ -29,8 +29,5 @@ export default { @@ -29,8 +29,5 @@ export default {
29 return this.size || this._elFormItemSize || (this.elForm || {}).size || (this.$ELEMENT || {}).size; 29 return this.size || this._elFormItemSize || (this.elForm || {}).size || (this.$ELEMENT || {}).size;
30 }, 30 },
31 }, 31 },
32 - mounted() {  
33 - // console.log(this);  
34 - },  
35 }; 32 };
36 </script> 33 </script>