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 | 69 | \ No newline at end of file | ... | ... |
src/components/table/table.vue
... | ... | @@ -26,12 +26,19 @@ |
26 | 26 | @mouseleave.stop="handleMouseOut(index)" |
27 | 27 | @click.stop="highlightCurrentRow(index)"> |
28 | 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 | 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 | 42 | </td> |
36 | 43 | </tr> |
37 | 44 | </tbody> |
... | ... | @@ -49,13 +56,14 @@ |
49 | 56 | <script> |
50 | 57 | import TableHead from './table-head.vue'; |
51 | 58 | import Checkbox from '../checkbox/checkbox.vue'; |
59 | + import Cell from './cell.vue'; | |
52 | 60 | import Mixin from './mixin'; |
53 | 61 | import { oneOf, getStyle, deepCopy } from '../../utils/assist'; |
54 | 62 | const prefixCls = 'ivu-table'; |
55 | 63 | |
56 | 64 | export default { |
57 | 65 | mixins: [ Mixin ], |
58 | - components: { TableHead, Checkbox }, | |
66 | + components: { TableHead, Checkbox, Cell }, | |
59 | 67 | props: { |
60 | 68 | data: { |
61 | 69 | type: Array, |
... | ... | @@ -108,6 +116,9 @@ |
108 | 116 | compiledUids: [], |
109 | 117 | cloneData: deepCopy(this.data), |
110 | 118 | cloneColumns: deepCopy(this.columns), |
119 | + leftFixedColumns: [], | |
120 | + rightFixedColumns: [], | |
121 | + centerColumns: [], | |
111 | 122 | showSlotHeader: true, |
112 | 123 | showSlotFooter: true, |
113 | 124 | bodyHeight: 0 |
... | ... | @@ -147,53 +158,25 @@ |
147 | 158 | rowClsName (index) { |
148 | 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 | 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 | 265 | center.push(col); |
283 | 266 | } |
284 | 267 | }); |
268 | + this.leftFixedColumns = left; | |
269 | + this.rightFixedColumns = right; | |
270 | + this.centerColumns = center; | |
285 | 271 | this.cloneColumns = left.concat(center).concat(right); |
286 | 272 | } |
287 | 273 | }, |
... | ... | @@ -291,7 +277,7 @@ |
291 | 277 | this.showSlotFooter = this.$els.footer.innerHTML.replace(/\n/g, '').replace(/<!--[\w\W\r\n]*?-->/gmi, '') !== ''; |
292 | 278 | }, |
293 | 279 | ready () { |
294 | - this.compileRender(); | |
280 | + this.handleResize(); | |
295 | 281 | this.fixedHeader(); |
296 | 282 | window.addEventListener('resize', this.handleResize, false); |
297 | 283 | }, |
... | ... | @@ -302,14 +288,14 @@ |
302 | 288 | data: { |
303 | 289 | handler () { |
304 | 290 | this.cloneData = deepCopy(this.data); |
305 | - this.compileRender(true); | |
291 | + this.handleResize(); | |
306 | 292 | }, |
307 | 293 | deep: true |
308 | 294 | }, |
309 | 295 | columns: { |
310 | 296 | handler () { |
311 | 297 | this.parseColumns(); |
312 | - this.compileRender(true); | |
298 | + this.handleResize(); | |
313 | 299 | }, |
314 | 300 | deep: true |
315 | 301 | }, | ... | ... |
src/styles/components/table.less
... | ... | @@ -9,10 +9,33 @@ |
9 | 9 | background-color: #fff; |
10 | 10 | border: 1px solid @border-color-base; |
11 | 11 | border-bottom: 0; |
12 | + border-right: 0; | |
12 | 13 | border-collapse: collapse; |
13 | 14 | box-sizing: border-box; |
14 | 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 | 39 | &-with-header{ |
17 | 40 | border-radius: @border-radius-base @border-radius-base 0 0; |
18 | 41 | } |
... | ... | @@ -36,8 +59,9 @@ |
36 | 59 | } |
37 | 60 | |
38 | 61 | &-body{ |
39 | - overflow-x: hidden; | |
40 | - overflow-y: auto; | |
62 | + //overflow-x: hidden; | |
63 | + //overflow-y: auto; | |
64 | + overflow: auto; | |
41 | 65 | position: relative; |
42 | 66 | } |
43 | 67 | |
... | ... | @@ -91,7 +115,8 @@ |
91 | 115 | } |
92 | 116 | |
93 | 117 | & table{ |
94 | - width: 100%; | |
118 | + //width: 100%; | |
119 | + table-layout: fixed; | |
95 | 120 | } |
96 | 121 | &-border{ |
97 | 122 | th,td{ | ... | ... |
test/routers/table.vue
... | ... | @@ -8,6 +8,7 @@ |
8 | 8 | <!--<i-table size="large" border stripe :columns="columns" :data="data"></i-table>--> |
9 | 9 | <br> |
10 | 10 | <i-table |
11 | + style="width:450px" | |
11 | 12 | border |
12 | 13 | highlight-row |
13 | 14 | :columns="columns" |
... | ... | @@ -57,7 +58,7 @@ |
57 | 58 | title: '地址', |
58 | 59 | key: 'address', |
59 | 60 | align: 'center', |
60 | -// width: 100 | |
61 | + width: 100, | |
61 | 62 | // render (row, column, index) { |
62 | 63 | // if (row.edit) { |
63 | 64 | // return `<i-input :value.sync="data[${index}].name"></i-input>`; |
... | ... | @@ -72,7 +73,8 @@ |
72 | 73 | fixed: 'right', |
73 | 74 | width: 200, |
74 | 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 | 142 | }, |
141 | 143 | ready () { |
142 | 144 | setTimeout(() => { |
145 | + return; | |
143 | 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 | 155 | }, 1000); |
152 | 156 | } |
153 | 157 | } | ... | ... |