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 | } | ... | ... |