Commit b52e633ca637d904b0cddd7831b5d60437692eea
1 parent
2c334740
Exists in
master
and in
2 other branches
feat: 优化Table组件
Showing
4 changed files
with
64 additions
and
57 deletions
Show diff stats
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
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> |