Commit a3547c1b41b9f411fdc00d327ee093a0cd260dfe
1 parent
abdec99d
update Table
update Table
Showing
4 changed files
with
148 additions
and
65 deletions
Show diff stats
1 | +<template> | ||
2 | + <div :class="[prefixCls + '-cell']"> | ||
3 | + <template v-if="renderType === 'index'">{{index + 1}}</template> | ||
4 | + <template v-if="renderType === 'normal'">{{{ row[column.key] }}}</template> | ||
5 | + </div> | ||
6 | +</template> | ||
7 | +<script> | ||
8 | + export default { | ||
9 | + props: { | ||
10 | + prefixCls: String, | ||
11 | + row: Object, | ||
12 | + column: Object, | ||
13 | + index: Number | ||
14 | + }, | ||
15 | + data () { | ||
16 | + return { | ||
17 | + renderType: '', | ||
18 | + uid: -1 | ||
19 | + } | ||
20 | + }, | ||
21 | + methods: { | ||
22 | + compile () { | ||
23 | + if (this.column.render) { | ||
24 | + const template = this.column.render(this.row, this.column, this.index); | ||
25 | + const cell = document.createElement('div'); | ||
26 | + cell.innerHTML = template; | ||
27 | + const _oldParentChildLen = this.$parent.$parent.$children.length; | ||
28 | + this.$parent.$parent.$compile(cell); | ||
29 | + const _newParentChildLen = this.$parent.$parent.$children.length; | ||
30 | + | ||
31 | + if (_oldParentChildLen !== _newParentChildLen) { // if render normal html node, do not tag | ||
32 | + this.uid = this.$parent.$parent.$children[this.$parent.$parent.$children.length - 1]._uid; // tag it, and delete when data or columns update | ||
33 | + } | ||
34 | + this.$el.innerHTML = ''; | ||
35 | + this.$el.appendChild(cell); | ||
36 | + } | ||
37 | + }, | ||
38 | + destroy () { | ||
39 | + for (let i = 0; i < this.$parent.$parent.$children.length; i++) { | ||
40 | + if (this.$parent.$parent.$children[i]._uid === this.uid) { | ||
41 | + this.$parent.$parent.$children[i].$destroy(); | ||
42 | + } | ||
43 | + } | ||
44 | + } | ||
45 | + }, | ||
46 | + compiled () { | ||
47 | + if (this.column.type === 'index') { | ||
48 | + this.renderType = 'index'; | ||
49 | + } else if (this.column.render) { | ||
50 | + this.renderType = 'render'; | ||
51 | + } else { | ||
52 | + this.renderType = 'normal'; | ||
53 | + } | ||
54 | + }, | ||
55 | + ready () { | ||
56 | + this.compile(); | ||
57 | + }, | ||
58 | + beforeDestroy () { | ||
59 | + this.destroy(); | ||
60 | + }, | ||
61 | + watch: { | ||
62 | + index () { | ||
63 | + this.destroy(); | ||
64 | + this.compile(); | ||
65 | + } | ||
66 | + } | ||
67 | + } | ||
68 | +</script> | ||
0 | \ No newline at end of file | 69 | \ No newline at end of file |
src/components/table/table.vue
@@ -26,12 +26,19 @@ | @@ -26,12 +26,19 @@ | ||
26 | @mouseleave.stop="handleMouseOut(index)" | 26 | @mouseleave.stop="handleMouseOut(index)" |
27 | @click.stop="highlightCurrentRow(index)"> | 27 | @click.stop="highlightCurrentRow(index)"> |
28 | <td v-for="column in cloneColumns" :class="alignCls(column)"> | 28 | <td v-for="column in cloneColumns" :class="alignCls(column)"> |
29 | - <div :class="[prefixCls + '-cell']"> | ||
30 | - <template v-if="column.type === 'selection'"> | ||
31 | - <Checkbox :checked="cloneData[index] && cloneData[index]._isChecked" @on-change="toggleSelect(index)"></Checkbox> | ||
32 | - </template> | ||
33 | - <template v-else>{{{ renderRow(row, column, index) }}}</template> | 29 | + <div :class="[prefixCls + '-cell']" v-if="column.type === 'selection'"> |
30 | + <Checkbox :checked="cloneData[index] && cloneData[index]._isChecked" @on-change="toggleSelect(index)"></Checkbox> | ||
34 | </div> | 31 | </div> |
32 | + <Cell v-else :prefix-cls="prefixCls" :row="row" :column="column" :index="index"></Cell> | ||
33 | + <!--<div :class="[prefixCls + '-cell']" v-else>--> | ||
34 | + <!--{{{ renderRow(row, column, index) }}}--> | ||
35 | + <!--</div>--> | ||
36 | + <!--<div :class="[prefixCls + '-cell']">--> | ||
37 | + <!--<template v-if="column.type === 'selection'">--> | ||
38 | + <!--<Checkbox :checked="cloneData[index] && cloneData[index]._isChecked" @on-change="toggleSelect(index)"></Checkbox>--> | ||
39 | + <!--</template>--> | ||
40 | + <!--<template v-else>{{{ renderRow(row, column, index) }}}</template>--> | ||
41 | + <!--</div>--> | ||
35 | </td> | 42 | </td> |
36 | </tr> | 43 | </tr> |
37 | </tbody> | 44 | </tbody> |
@@ -49,13 +56,14 @@ | @@ -49,13 +56,14 @@ | ||
49 | <script> | 56 | <script> |
50 | import TableHead from './table-head.vue'; | 57 | import TableHead from './table-head.vue'; |
51 | import Checkbox from '../checkbox/checkbox.vue'; | 58 | import Checkbox from '../checkbox/checkbox.vue'; |
59 | + import Cell from './cell.vue'; | ||
52 | import Mixin from './mixin'; | 60 | import Mixin from './mixin'; |
53 | import { oneOf, getStyle, deepCopy } from '../../utils/assist'; | 61 | import { oneOf, getStyle, deepCopy } from '../../utils/assist'; |
54 | const prefixCls = 'ivu-table'; | 62 | const prefixCls = 'ivu-table'; |
55 | 63 | ||
56 | export default { | 64 | export default { |
57 | mixins: [ Mixin ], | 65 | mixins: [ Mixin ], |
58 | - components: { TableHead, Checkbox }, | 66 | + components: { TableHead, Checkbox, Cell }, |
59 | props: { | 67 | props: { |
60 | data: { | 68 | data: { |
61 | type: Array, | 69 | type: Array, |
@@ -108,6 +116,9 @@ | @@ -108,6 +116,9 @@ | ||
108 | compiledUids: [], | 116 | compiledUids: [], |
109 | cloneData: deepCopy(this.data), | 117 | cloneData: deepCopy(this.data), |
110 | cloneColumns: deepCopy(this.columns), | 118 | cloneColumns: deepCopy(this.columns), |
119 | + leftFixedColumns: [], | ||
120 | + rightFixedColumns: [], | ||
121 | + centerColumns: [], | ||
111 | showSlotHeader: true, | 122 | showSlotHeader: true, |
112 | showSlotFooter: true, | 123 | showSlotFooter: true, |
113 | bodyHeight: 0 | 124 | bodyHeight: 0 |
@@ -147,53 +158,25 @@ | @@ -147,53 +158,25 @@ | ||
147 | rowClsName (index) { | 158 | rowClsName (index) { |
148 | return this.rowClassName(this.data[index], index); | 159 | return this.rowClassName(this.data[index], index); |
149 | }, | 160 | }, |
150 | - renderRow (row, column, index) { | ||
151 | - return column.type === 'index' ? index + 1 : column.render ? '' : row[column.key]; | ||
152 | - }, | ||
153 | - compileRender (update = false) { | 161 | + handleResize () { |
154 | this.$nextTick(() => { | 162 | this.$nextTick(() => { |
155 | - if (update) { | ||
156 | - for (let i = 0; i < this.$parent.$children.length; i++) { | ||
157 | - const index = this.compiledUids.indexOf(this.$parent.$children[i]._uid); | ||
158 | - if (index > -1) { | ||
159 | - this.$parent.$children[i].$destroy(); | ||
160 | - this.compiledUids.splice(index, 1); | ||
161 | - i--; | ||
162 | - } | ||
163 | - } | 163 | + const allWidth = !this.columns.some(cell => !cell.width); |
164 | + if (allWidth) { | ||
165 | + this.tableWidth = this.columns.map(cell => cell.width).reduce((a, b) => a + b); | ||
166 | + } else { | ||
167 | + this.tableWidth = parseInt(getStyle(this.$el, 'width')) - 1; | ||
164 | } | 168 | } |
165 | - | ||
166 | - const $el = this.$els.render; | ||
167 | - for (let i = 0; i < this.cloneColumns.length; i++) { | ||
168 | - const column = this.cloneColumns[i]; | ||
169 | - if (column.render) { | ||
170 | - for (let j = 0; j < this.data.length; j++) { | ||
171 | - // todo 做一个缓存,只在需要改render时再重新编译,data改变时不用再编译 | ||
172 | - const row = this.data[j]; | ||
173 | - const template = column.render(row, column, j); | ||
174 | - const cell = document.createElement('div'); | ||
175 | - cell.innerHTML = template; | ||
176 | - const _oldParentChildLen = this.$parent.$children.length; | ||
177 | - this.$parent.$compile(cell); | ||
178 | - const _newParentChildLen = this.$parent.$children.length; | ||
179 | - | ||
180 | - if (_oldParentChildLen !== _newParentChildLen) { // if render normal html node, do not tag | ||
181 | - this.compiledUids.push(this.$parent.$children[this.$parent.$children.length - 1]._uid); // tag it, and delete when data or columns update | ||
182 | - } | ||
183 | - $el.children[j].children[i].children[0].innerHTML = ''; | ||
184 | - $el.children[j].children[i].children[0].appendChild(cell); | 169 | + this.$nextTick(() => { |
170 | + this.columnsWidth = []; | ||
171 | + let autoWidthIndex = -1 | ||
172 | + if (allWidth) autoWidthIndex = this.cloneColumns.findIndex(cell => !cell.width); | ||
173 | + this.$els.tbody.querySelectorAll('tbody tr')[0].querySelectorAll('td').forEach((cell, index) => { | ||
174 | + if (index === autoWidthIndex) { | ||
175 | + this.columnsWidth.push(parseInt(getStyle(cell, 'width')) - 1); | ||
176 | + } else { | ||
177 | + this.columnsWidth.push(parseInt(getStyle(cell, 'width'))); | ||
185 | } | 178 | } |
186 | - } | ||
187 | - } | ||
188 | - this.handleResize(); | ||
189 | - }); | ||
190 | - }, | ||
191 | - handleResize () { | ||
192 | - this.tableWidth = parseInt(getStyle(this.$el, 'width')); | ||
193 | - this.$nextTick(() => { | ||
194 | - this.columnsWidth = []; | ||
195 | - this.$els.tbody.querySelectorAll('tbody tr')[0].querySelectorAll('td').forEach((cell) => { | ||
196 | - this.columnsWidth.push(parseInt(getStyle(cell, 'width'))); | 179 | + }); |
197 | }); | 180 | }); |
198 | }); | 181 | }); |
199 | }, | 182 | }, |
@@ -282,6 +265,9 @@ | @@ -282,6 +265,9 @@ | ||
282 | center.push(col); | 265 | center.push(col); |
283 | } | 266 | } |
284 | }); | 267 | }); |
268 | + this.leftFixedColumns = left; | ||
269 | + this.rightFixedColumns = right; | ||
270 | + this.centerColumns = center; | ||
285 | this.cloneColumns = left.concat(center).concat(right); | 271 | this.cloneColumns = left.concat(center).concat(right); |
286 | } | 272 | } |
287 | }, | 273 | }, |
@@ -291,7 +277,7 @@ | @@ -291,7 +277,7 @@ | ||
291 | this.showSlotFooter = this.$els.footer.innerHTML.replace(/\n/g, '').replace(/<!--[\w\W\r\n]*?-->/gmi, '') !== ''; | 277 | this.showSlotFooter = this.$els.footer.innerHTML.replace(/\n/g, '').replace(/<!--[\w\W\r\n]*?-->/gmi, '') !== ''; |
292 | }, | 278 | }, |
293 | ready () { | 279 | ready () { |
294 | - this.compileRender(); | 280 | + this.handleResize(); |
295 | this.fixedHeader(); | 281 | this.fixedHeader(); |
296 | window.addEventListener('resize', this.handleResize, false); | 282 | window.addEventListener('resize', this.handleResize, false); |
297 | }, | 283 | }, |
@@ -302,14 +288,14 @@ | @@ -302,14 +288,14 @@ | ||
302 | data: { | 288 | data: { |
303 | handler () { | 289 | handler () { |
304 | this.cloneData = deepCopy(this.data); | 290 | this.cloneData = deepCopy(this.data); |
305 | - this.compileRender(true); | 291 | + this.handleResize(); |
306 | }, | 292 | }, |
307 | deep: true | 293 | deep: true |
308 | }, | 294 | }, |
309 | columns: { | 295 | columns: { |
310 | handler () { | 296 | handler () { |
311 | this.parseColumns(); | 297 | this.parseColumns(); |
312 | - this.compileRender(true); | 298 | + this.handleResize(); |
313 | }, | 299 | }, |
314 | deep: true | 300 | deep: true |
315 | }, | 301 | }, |
src/styles/components/table.less
@@ -9,10 +9,33 @@ | @@ -9,10 +9,33 @@ | ||
9 | background-color: #fff; | 9 | background-color: #fff; |
10 | border: 1px solid @border-color-base; | 10 | border: 1px solid @border-color-base; |
11 | border-bottom: 0; | 11 | border-bottom: 0; |
12 | + border-right: 0; | ||
12 | border-collapse: collapse; | 13 | border-collapse: collapse; |
13 | box-sizing: border-box; | 14 | box-sizing: border-box; |
14 | position: relative; | 15 | position: relative; |
15 | 16 | ||
17 | + &:before{ | ||
18 | + content: ''; | ||
19 | + width: 100%; | ||
20 | + height: 1px; | ||
21 | + position: absolute; | ||
22 | + left: 0; | ||
23 | + bottom: 0; | ||
24 | + background-color: @border-color-base; | ||
25 | + z-index: 1; | ||
26 | + } | ||
27 | + | ||
28 | + &:after{ | ||
29 | + content: ''; | ||
30 | + width: 1px; | ||
31 | + height: 100%; | ||
32 | + position: absolute; | ||
33 | + top: 0; | ||
34 | + right: 0; | ||
35 | + background-color: @border-color-base; | ||
36 | + z-index: 1; | ||
37 | + } | ||
38 | + | ||
16 | &-with-header{ | 39 | &-with-header{ |
17 | border-radius: @border-radius-base @border-radius-base 0 0; | 40 | border-radius: @border-radius-base @border-radius-base 0 0; |
18 | } | 41 | } |
@@ -36,8 +59,9 @@ | @@ -36,8 +59,9 @@ | ||
36 | } | 59 | } |
37 | 60 | ||
38 | &-body{ | 61 | &-body{ |
39 | - overflow-x: hidden; | ||
40 | - overflow-y: auto; | 62 | + //overflow-x: hidden; |
63 | + //overflow-y: auto; | ||
64 | + overflow: auto; | ||
41 | position: relative; | 65 | position: relative; |
42 | } | 66 | } |
43 | 67 | ||
@@ -91,7 +115,8 @@ | @@ -91,7 +115,8 @@ | ||
91 | } | 115 | } |
92 | 116 | ||
93 | & table{ | 117 | & table{ |
94 | - width: 100%; | 118 | + //width: 100%; |
119 | + table-layout: fixed; | ||
95 | } | 120 | } |
96 | &-border{ | 121 | &-border{ |
97 | th,td{ | 122 | th,td{ |
test/routers/table.vue
@@ -8,6 +8,7 @@ | @@ -8,6 +8,7 @@ | ||
8 | <!--<i-table size="large" border stripe :columns="columns" :data="data"></i-table>--> | 8 | <!--<i-table size="large" border stripe :columns="columns" :data="data"></i-table>--> |
9 | <br> | 9 | <br> |
10 | <i-table | 10 | <i-table |
11 | + style="width:450px" | ||
11 | border | 12 | border |
12 | highlight-row | 13 | highlight-row |
13 | :columns="columns" | 14 | :columns="columns" |
@@ -57,7 +58,7 @@ | @@ -57,7 +58,7 @@ | ||
57 | title: '地址', | 58 | title: '地址', |
58 | key: 'address', | 59 | key: 'address', |
59 | align: 'center', | 60 | align: 'center', |
60 | -// width: 100 | 61 | + width: 100, |
61 | // render (row, column, index) { | 62 | // render (row, column, index) { |
62 | // if (row.edit) { | 63 | // if (row.edit) { |
63 | // return `<i-input :value.sync="data[${index}].name"></i-input>`; | 64 | // return `<i-input :value.sync="data[${index}].name"></i-input>`; |
@@ -72,7 +73,8 @@ | @@ -72,7 +73,8 @@ | ||
72 | fixed: 'right', | 73 | fixed: 'right', |
73 | width: 200, | 74 | width: 200, |
74 | render (row, column, index) { | 75 | render (row, column, index) { |
75 | - return `<i-button @click="edit(${index})">编辑</i-button>` | 76 | + return `<i-button @click="edit(${index})">${row.name}</i-button>` |
77 | +// return `<a>${row.name}</a>` | ||
76 | } | 78 | } |
77 | } | 79 | } |
78 | ], | 80 | ], |
@@ -140,14 +142,16 @@ | @@ -140,14 +142,16 @@ | ||
140 | }, | 142 | }, |
141 | ready () { | 143 | ready () { |
142 | setTimeout(() => { | 144 | setTimeout(() => { |
145 | + return; | ||
143 | // this.height = 150; | 146 | // this.height = 150; |
144 | - return | ||
145 | - this.data.push({ | ||
146 | - name: '刘天娇2', | ||
147 | - age: 272, | ||
148 | - address: '北京市东城区2', | ||
149 | - edit: false | ||
150 | - }); | 147 | +// return |
148 | +// this.data.push({ | ||
149 | +// name: '刘天娇2', | ||
150 | +// age: 272, | ||
151 | +// address: '北京市东城区2', | ||
152 | +// edit: false | ||
153 | +// }); | ||
154 | + this.data.splice(1, 1) | ||
151 | }, 1000); | 155 | }, 1000); |
152 | } | 156 | } |
153 | } | 157 | } |