From 7263db12b3aeef2ef201c18dde56f5cb8fa361f5 Mon Sep 17 00:00:00 2001 From: furybean Date: Fri, 4 Nov 2016 16:15:33 +0800 Subject: [PATCH] Table: add single selection back. Add current-change event & highlight-current-row event. --- CHANGELOG.md | 1 + examples/docs/zh-cn/table.md | 2 + packages/table/src/table-body.js | 10 ++++- packages/table/src/table-store.js | 38 +++++++++++++++-- packages/table/src/table.vue | 5 +++ packages/theme-default/src/table.css | 2 +- test/unit/specs/table.spec.js | 61 +++++++++++++++++++++++++++- 7 files changed, 112 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a8ac8563..2b8023f3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ - 修复 Slider 在 Form 中的显示问题 - 修复 Upload 在 onSuccess、onError 钩子无法拿到服务端返回信息的问题 - 改善 tabs 现在支持动态更新 +- Table 新增 highlightCurrentRow 属性、新增 current-change 事件 #### 非兼容性更新 diff --git a/examples/docs/zh-cn/table.md b/examples/docs/zh-cn/table.md index d7cb83be9..f4de10feb 100644 --- a/examples/docs/zh-cn/table.md +++ b/examples/docs/zh-cn/table.md @@ -898,6 +898,7 @@ | stripe | 是否为斑马纹 table | boolean | — | false | | border | 是否带有纵向边框 | boolean | — | false | | fit | 列的宽度是否自撑开 | boolean | — | true | +| highlight-current-row | 是否要高亮当前行 | boolean | - | false | | row-class-name | 行的 className 的回调。 | Function(row, index) | - | - | | row-key | 行数据的 Key,用来优化 Table 的渲染;在使用 reserve-selection 功能的情况下,该属性是必填的 | Function(row), String | - | - | @@ -912,6 +913,7 @@ | cell-click | 当某个单元格被点击时会触发该事件 | row, column, cell, event | | row-click | 当某一行被点击时会触发该事件 | row, event | | sort-change | 当表格的排序条件发生变化的时候会触发该事件 | { column, prop, order } | +| current-change | 当表格的当前行发生变化的时候会触发该事件,如果要高亮当前行,请打开表格的 highlight-current-row 属性 | { column, prop, order } | ### Table Methods | 方法名 | 说明 | 参数 | diff --git a/packages/table/src/table-body.js b/packages/table/src/table-body.js index 098b7ba2c..3515565f1 100644 --- a/packages/table/src/table-body.js +++ b/packages/table/src/table-body.js @@ -9,7 +9,8 @@ export default { required: true }, rowClassName: [String, Function], - fixed: String + fixed: String, + highlight: Boolean }, render(h) { @@ -115,6 +116,11 @@ export default { classes.push(rowClassName.apply(null, [row, index]) || ''); } + const currentRow = this.store.states.currentRow; + if (this.highlight && currentRow === row) { + classes.push('current-row'); + } + return classes.join(' '); }, @@ -161,6 +167,8 @@ export default { } } + this.store.commit('setCurrentRow', row); + table.$emit('row-click', row, event); }, diff --git a/packages/table/src/table-store.js b/packages/table/src/table-store.js index 93b60008a..f0a0da0fd 100644 --- a/packages/table/src/table-store.js +++ b/packages/table/src/table-store.js @@ -74,6 +74,7 @@ const TableStore = function(table, initialState = {}) { selection: [], reserveSelection: false, selectable: null, + currentRow: null, hoverRow: null, filters: {} }; @@ -89,6 +90,9 @@ TableStore.prototype.mutations = { setData(states, data) { states._data = data; states.data = sortData((data || []), states); + + this.updateCurrentRow(); + const selection = states.selection; if (!states.reserveSelection) { @@ -186,13 +190,23 @@ TableStore.prototype.mutations = { states.hoverRow = row; }, + setCurrentRow(states, row) { + const oldCurrentRow = states.currentRow; + states.currentRow = row; + + if (oldCurrentRow !== row) { + this.table.$emit('current-change', row, oldCurrentRow); + } + }, + rowSelectedChanged(states, row) { const changed = toggleRowSelection(states, row); const selection = states.selection; if (changed) { - this.table.$emit('selection-change', selection); - this.table.$emit('select', selection, row); + const table = this.table; + table.$emit('selection-change', selection); + table.$emit('select', selection, row); } this.updateAllSelected(); @@ -216,10 +230,11 @@ TableStore.prototype.mutations = { } }); + const table = this.table; if (selectionChanged) { - this.table.$emit('selection-change', selection); + table.$emit('selection-change', selection); } - this.table.$emit('select-all', selection); + table.$emit('select-all', selection); states.isAllSelected = value; }) }; @@ -295,6 +310,21 @@ TableStore.prototype.scheduleLayout = function() { this.table.debouncedLayout(); }; +TableStore.prototype.updateCurrentRow = function() { + const states = this.states; + const table = this.table; + const data = states.data || []; + const oldCurrentRow = states.currentRow; + + if (data.indexOf(oldCurrentRow) === -1) { + states.currentRow = null; + + if (states.currentRow !== oldCurrentRow) { + table.$emit('current-change', null, oldCurrentRow); + } + } +}; + TableStore.prototype.commit = function(name, ...args) { const mutations = this.mutations; if (mutations[name]) { diff --git a/packages/table/src/table.vue b/packages/table/src/table.vue index bcf97fab5..c4b94f2e8 100644 --- a/packages/table/src/table.vue +++ b/packages/table/src/table.vue @@ -17,6 +17,7 @@ :store="store" :layout="layout" :row-class-name="rowClassName" + :highlight="highlightCurrentRow" :style="{ width: layout.bodyWidth ? layout.bodyWidth - (layout.scrollY ? layout.gutterWidth : 0 ) + 'px' : '' }">
@@ -47,6 +48,7 @@ fixed="left" :store="store" :layout="layout" + :highlight="highlightCurrentRow" :row-class-name="rowClassName" :style="{ width: layout.fixedWidth ? layout.fixedWidth + 'px' : '' }"> @@ -78,6 +80,7 @@ :store="store" :layout="layout" :row-class-name="rowClassName" + :highlight="highlightCurrentRow" :style="{ width: layout.rightFixedWidth ? layout.rightFixedWidth + 'px' : '' }">
@@ -130,6 +133,8 @@ rowClassName: [String, Function], + highlightCurrentRow: Boolean, + emptyText: { type: String, default: $t('el.table.emptyText') diff --git a/packages/theme-default/src/table.css b/packages/theme-default/src/table.css index 19b09356a..4dd5a9499 100644 --- a/packages/theme-default/src/table.css +++ b/packages/theme-default/src/table.css @@ -330,7 +330,7 @@ background-color: #eff2f7; } - tr.current-row { + tr.current-row td { background: #eff7ff; } } diff --git a/test/unit/specs/table.spec.js b/test/unit/specs/table.spec.js index 3ed4b93d2..a5df1dfdf 100644 --- a/test/unit/specs/table.spec.js +++ b/test/unit/specs/table.spec.js @@ -261,7 +261,7 @@ describe('Table', () => { }, data() { - return { result: '' }; + return { result: '', testData: this.testData }; } }, true); }; @@ -358,6 +358,32 @@ describe('Table', () => { done(); }, DELAY); }); + + it('current-change', done => { + const vm = createTable('current-change'); + + setTimeout(_ => { + const cell = vm.$el.querySelectorAll('.el-table__body .cell')[2]; // first row + + triggerEvent(cell.parentNode.parentNode, 'click'); + expect(vm.result).to.length(2); // currentRow, oldCurrentRow + expect(vm.result[0]).to.have.property('name').to.equal(getTestData()[0].name); + expect(vm.result[1]).to.equal(null); + + // clear data => current-change should fire again. + const oldRow = vm.result[0]; + vm.testData = []; + + setTimeout(() => { + expect(vm.result).to.length(2); // currentRow, oldCurrentRow + expect(vm.result[0]).to.equal(null); + expect(vm.result[1]).to.equal(oldRow); + + destroyVM(vm); + done(); + }, DELAY); + }, DELAY); + }); }); describe('column attributes', () => { @@ -825,4 +851,37 @@ describe('Table', () => { }, DELAY); }, DELAY); }); + + it('highlight-current-row', done => { + const vm = createVue({ + template: ` + + + + + + + `, + + created() { + this.testData = getTestData(); + } + }, true); + setTimeout(_ => { + const tr = vm.$el.querySelector('.el-table__body-wrapper tbody tr'); + triggerEvent(tr, 'click', true, false); + setTimeout(_ => { + expect(tr.classList.contains('current-row')).to.be.true; + const rows = vm.$el.querySelectorAll('.el-table__body-wrapper tbody tr'); + + triggerEvent(rows[2], 'click', true, false); + setTimeout(_ => { + expect(tr.classList.contains('current-row')).to.be.false; + expect(rows[2].classList.contains('current-row')).to.be.true; + destroyVM(vm); + done(); + }, DELAY); + }, DELAY); + }, DELAY); + }); });