Commit 7f34c510307215cc599a2ba86d638570e16e0fe5
1 parent
3ef4dfb9
update Table
update Table
Showing
6 changed files
with
149 additions
and
89 deletions
Show diff stats
src/components/table/cell.vue
| @@ -17,7 +17,8 @@ | @@ -17,7 +17,8 @@ | ||
| 17 | row: Object, | 17 | row: Object, |
| 18 | column: Object, | 18 | column: Object, |
| 19 | index: Number, | 19 | index: Number, |
| 20 | - checked: Boolean | 20 | + checked: Boolean, |
| 21 | + fixed: Boolean | ||
| 21 | }, | 22 | }, |
| 22 | data () { | 23 | data () { |
| 23 | return { | 24 | return { |
| @@ -30,7 +31,7 @@ | @@ -30,7 +31,7 @@ | ||
| 30 | return [ | 31 | return [ |
| 31 | `${this.prefixCls}-cell`, | 32 | `${this.prefixCls}-cell`, |
| 32 | { | 33 | { |
| 33 | - [`${this.prefixCls}-hidden`]: this.column.fixed && (this.column.fixed === 'left' || this.column.fixed === 'right') | 34 | + [`${this.prefixCls}-hidden`]: !this.fixed && this.column.fixed && (this.column.fixed === 'left' || this.column.fixed === 'right') |
| 34 | } | 35 | } |
| 35 | ] | 36 | ] |
| 36 | } | 37 | } |
| @@ -38,29 +39,31 @@ | @@ -38,29 +39,31 @@ | ||
| 38 | methods: { | 39 | methods: { |
| 39 | compile () { | 40 | compile () { |
| 40 | if (this.column.render) { | 41 | if (this.column.render) { |
| 42 | + const $parent = this.$parent.$parent.$parent; | ||
| 41 | const template = this.column.render(this.row, this.column, this.index); | 43 | const template = this.column.render(this.row, this.column, this.index); |
| 42 | const cell = document.createElement('div'); | 44 | const cell = document.createElement('div'); |
| 43 | cell.innerHTML = template; | 45 | cell.innerHTML = template; |
| 44 | - const _oldParentChildLen = this.$parent.$parent.$children.length; | ||
| 45 | - this.$parent.$parent.$compile(cell); | ||
| 46 | - const _newParentChildLen = this.$parent.$parent.$children.length; | 46 | + const _oldParentChildLen = $parent.$children.length; |
| 47 | + $parent.$compile(cell); | ||
| 48 | + const _newParentChildLen = $parent.$children.length; | ||
| 47 | 49 | ||
| 48 | if (_oldParentChildLen !== _newParentChildLen) { // if render normal html node, do not tag | 50 | if (_oldParentChildLen !== _newParentChildLen) { // if render normal html node, do not tag |
| 49 | - this.uid = this.$parent.$parent.$children[this.$parent.$parent.$children.length - 1]._uid; // tag it, and delete when data or columns update | 51 | + this.uid = $parent.$children[$parent.$children.length - 1]._uid; // tag it, and delete when data or columns update |
| 50 | } | 52 | } |
| 51 | this.$el.innerHTML = ''; | 53 | this.$el.innerHTML = ''; |
| 52 | this.$el.appendChild(cell); | 54 | this.$el.appendChild(cell); |
| 53 | } | 55 | } |
| 54 | }, | 56 | }, |
| 55 | destroy () { | 57 | destroy () { |
| 56 | - for (let i = 0; i < this.$parent.$parent.$children.length; i++) { | ||
| 57 | - if (this.$parent.$parent.$children[i]._uid === this.uid) { | ||
| 58 | - this.$parent.$parent.$children[i].$destroy(); | 58 | + const $parent = this.$parent.$parent.$parent; |
| 59 | + for (let i = 0; i < $parent.$children.length; i++) { | ||
| 60 | + if ($parent.$children[i]._uid === this.uid) { | ||
| 61 | + $parent.$children[i].$destroy(); | ||
| 59 | } | 62 | } |
| 60 | } | 63 | } |
| 61 | }, | 64 | }, |
| 62 | toggleSelect (index) { | 65 | toggleSelect (index) { |
| 63 | - this.$parent.toggleSelect(index); | 66 | + this.$parent.$parent.toggleSelect(index); |
| 64 | } | 67 | } |
| 65 | }, | 68 | }, |
| 66 | compiled () { | 69 | compiled () { |
src/components/table/table-body.vue
| 1 | <template> | 1 | <template> |
| 2 | - <table cellspacing="0" cellpadding="0" border="0"> | ||
| 3 | - | 2 | + <table cellspacing="0" cellpadding="0" border="0" :style="style"> |
| 3 | + <colgroup> | ||
| 4 | + <col v-for="column in columns" :width="setCellWidth(column, $index)"> | ||
| 5 | + </colgroup> | ||
| 6 | + <tbody :class="[prefixCls + '-tbody']"> | ||
| 7 | + <tr | ||
| 8 | + v-for="(index, row) in data" | ||
| 9 | + :class="[prefixCls + '-row', rowClsName(index), {[prefixCls + '-row-highlight']: cloneData[index] && cloneData[index]._isHighlight, [prefixCls + '-row-hover']: cloneData[index] && cloneData[index]._isHover}]" | ||
| 10 | + @mouseenter.stop="handleMouseIn(index)" | ||
| 11 | + @mouseleave.stop="handleMouseOut(index)" | ||
| 12 | + @click.stop="highlightCurrentRow(index)"> | ||
| 13 | + <td v-for="column in columns" :class="alignCls(column)"> | ||
| 14 | + <Cell | ||
| 15 | + :fixed="fixed" | ||
| 16 | + :prefix-cls="prefixCls" | ||
| 17 | + :row="row" | ||
| 18 | + :column="column" | ||
| 19 | + :index="index" | ||
| 20 | + :checked="cloneData[index] && cloneData[index]._isChecked"></Cell> | ||
| 21 | + </td> | ||
| 22 | + </tr> | ||
| 23 | + </tbody> | ||
| 4 | </table> | 24 | </table> |
| 5 | </template> | 25 | </template> |
| 6 | <script> | 26 | <script> |
| 27 | + import Cell from './cell.vue'; | ||
| 28 | + import Mixin from './mixin'; | ||
| 29 | + | ||
| 7 | export default { | 30 | export default { |
| 31 | + mixins: [ Mixin ], | ||
| 32 | + components: { Cell }, | ||
| 8 | props: { | 33 | props: { |
| 9 | - | ||
| 10 | - }, | ||
| 11 | - data () { | ||
| 12 | - return { | ||
| 13 | - | ||
| 14 | - } | ||
| 15 | - }, | ||
| 16 | - computed: { | ||
| 17 | - | 34 | + prefixCls: String, |
| 35 | + style: Object, | ||
| 36 | + columns: Array, | ||
| 37 | + data: Array, | ||
| 38 | + cloneData: Array, | ||
| 39 | + fixed: Boolean | ||
| 18 | }, | 40 | }, |
| 19 | methods: { | 41 | methods: { |
| 20 | - | 42 | + setCellWidth (column, index) { |
| 43 | + return this.$parent.setCellWidth(column, index); | ||
| 44 | + }, | ||
| 45 | + rowClsName (index) { | ||
| 46 | + return this.$parent.rowClassName(this.data[index], index); | ||
| 47 | + }, | ||
| 48 | + handleMouseIn (index) { | ||
| 49 | + this.$parent.handleMouseIn(index); | ||
| 50 | + }, | ||
| 51 | + handleMouseOut (index) { | ||
| 52 | + this.$parent.handleMouseOut(index); | ||
| 53 | + }, | ||
| 54 | + highlightCurrentRow (index) { | ||
| 55 | + this.$parent.highlightCurrentRow(index); | ||
| 56 | + } | ||
| 21 | } | 57 | } |
| 22 | } | 58 | } |
| 23 | </script> | 59 | </script> |
| 24 | \ No newline at end of file | 60 | \ No newline at end of file |
src/components/table/table-head.vue
| 1 | <template> | 1 | <template> |
| 2 | - <thead> | ||
| 3 | - <tr> | ||
| 4 | - <th v-for="column in columns" :class="alignCls(column)"> | ||
| 5 | - <div :class="[prefixCls + '-cell', {[prefixCls + '-hidden']: column.fixed && (column.fixed === 'left' || column.fixed === 'right')}]"> | ||
| 6 | - <template v-if="column.type === 'selection'"><Checkbox :checked="isSelectAll" @on-change="selectAll"></Checkbox></template> | ||
| 7 | - <template v-else>{{{ renderHeader(column, $index) }}}</template> | ||
| 8 | - </div> | ||
| 9 | - </th> | ||
| 10 | - </tr> | ||
| 11 | - </thead> | 2 | + <table cellspacing="0" cellpadding="0" border="0" :style="style"> |
| 3 | + <colgroup> | ||
| 4 | + <col v-for="column in columns" :width="setCellWidth(column, $index)"> | ||
| 5 | + </colgroup> | ||
| 6 | + <thead> | ||
| 7 | + <tr> | ||
| 8 | + <th v-for="column in columns" :class="alignCls(column)"> | ||
| 9 | + <div :class="[prefixCls + '-cell', {[prefixCls + '-hidden']: !fixed && column.fixed && (column.fixed === 'left' || column.fixed === 'right')}]"> | ||
| 10 | + <template v-if="column.type === 'selection'"><Checkbox :checked="isSelectAll" @on-change="selectAll"></Checkbox></template> | ||
| 11 | + <template v-else>{{{ renderHeader(column, $index) }}}</template> | ||
| 12 | + </div> | ||
| 13 | + </th> | ||
| 14 | + </tr> | ||
| 15 | + </thead> | ||
| 16 | + </table> | ||
| 12 | </template> | 17 | </template> |
| 13 | <script> | 18 | <script> |
| 14 | import Checkbox from '../checkbox/checkbox.vue'; | 19 | import Checkbox from '../checkbox/checkbox.vue'; |
| @@ -20,13 +25,10 @@ | @@ -20,13 +25,10 @@ | ||
| 20 | components: { Checkbox }, | 25 | components: { Checkbox }, |
| 21 | props: { | 26 | props: { |
| 22 | prefixCls: String, | 27 | prefixCls: String, |
| 28 | + style: Object, | ||
| 23 | columns: Array, | 29 | columns: Array, |
| 24 | - cloneData: Array | ||
| 25 | - }, | ||
| 26 | - data () { | ||
| 27 | - return { | ||
| 28 | - | ||
| 29 | - } | 30 | + cloneData: Array, |
| 31 | + fixed: Boolean | ||
| 30 | }, | 32 | }, |
| 31 | computed: { | 33 | computed: { |
| 32 | isSelectAll () { | 34 | isSelectAll () { |
| @@ -34,6 +36,9 @@ | @@ -34,6 +36,9 @@ | ||
| 34 | } | 36 | } |
| 35 | }, | 37 | }, |
| 36 | methods: { | 38 | methods: { |
| 39 | + setCellWidth (column, index) { | ||
| 40 | + return this.$parent.setCellWidth(column, index); | ||
| 41 | + }, | ||
| 37 | renderHeader (column, $index) { | 42 | renderHeader (column, $index) { |
| 38 | if ('renderHeader' in this.columns[$index]) { | 43 | if ('renderHeader' in this.columns[$index]) { |
| 39 | return this.columns[$index].renderHeader(column, $index); | 44 | return this.columns[$index].renderHeader(column, $index); |
src/components/table/table.vue
| @@ -2,70 +2,51 @@ | @@ -2,70 +2,51 @@ | ||
| 2 | <div :class="classes" :style="styles"> | 2 | <div :class="classes" :style="styles"> |
| 3 | <div :class="[prefixCls + '-title']" v-if="showSlotHeader" v-el:title><slot name="header"></slot></div> | 3 | <div :class="[prefixCls + '-title']" v-if="showSlotHeader" v-el:title><slot name="header"></slot></div> |
| 4 | <div :class="[prefixCls + '-header']" v-if="showHeader" v-el:header @mousewheel="handleMouseWheel"> | 4 | <div :class="[prefixCls + '-header']" v-if="showHeader" v-el:header @mousewheel="handleMouseWheel"> |
| 5 | - <table cellspacing="0" cellpadding="0" border="0" :style="tableStyle"> | ||
| 6 | - <colgroup> | ||
| 7 | - <col v-for="column in cloneColumns" :width="setCellWidth(column, $index)"> | ||
| 8 | - </colgroup> | ||
| 9 | - <thead | ||
| 10 | - is="table-head" | ||
| 11 | - :prefix-cls="prefixCls" | ||
| 12 | - :clone-data.sync="cloneData" | ||
| 13 | - :columns="cloneColumns"></thead> | ||
| 14 | - </table> | 5 | + <table-head |
| 6 | + :prefix-cls="prefixCls" | ||
| 7 | + :style="tableStyle" | ||
| 8 | + :columns="cloneColumns" | ||
| 9 | + :clone-data="cloneData"></table-head> | ||
| 15 | </div> | 10 | </div> |
| 16 | <div :class="[prefixCls + '-body']" :style="bodyStyle" v-el:body @scroll="handleBodyScroll"> | 11 | <div :class="[prefixCls + '-body']" :style="bodyStyle" v-el:body @scroll="handleBodyScroll"> |
| 17 | - <table cellspacing="0" cellpadding="0" border="0" :style="tableStyle" v-el:tbody> | ||
| 18 | - <colgroup> | ||
| 19 | - <col v-for="column in cloneColumns" :width="setCellWidth(column, $index)"> | ||
| 20 | - </colgroup> | ||
| 21 | - <tbody :class="[prefixCls + '-tbody']" v-el:render> | ||
| 22 | - <tr | ||
| 23 | - v-for="(index, row) in data" | ||
| 24 | - :class="[prefixCls + '-row', rowClsName(index), {[prefixCls + '-row-highlight']: cloneData[index] && cloneData[index]._isHighlight, [prefixCls + '-row-hover']: cloneData[index] && cloneData[index]._isHover}]" | ||
| 25 | - @mouseenter.stop="handleMouseIn(index)" | ||
| 26 | - @mouseleave.stop="handleMouseOut(index)" | ||
| 27 | - @click.stop="highlightCurrentRow(index)"> | ||
| 28 | - <td v-for="column in cloneColumns" :class="alignCls(column)"> | ||
| 29 | - <Cell | ||
| 30 | - :prefix-cls="prefixCls" | ||
| 31 | - :row="row" | ||
| 32 | - :column="column" | ||
| 33 | - :index="index" | ||
| 34 | - :checked="cloneData[index] && cloneData[index]._isChecked"></Cell> | ||
| 35 | - </td> | ||
| 36 | - </tr> | ||
| 37 | - </tbody> | ||
| 38 | - </table> | 12 | + <table-body |
| 13 | + v-ref:tbody | ||
| 14 | + :prefix-cls="prefixCls" | ||
| 15 | + :style="tableStyle" | ||
| 16 | + :columns="cloneColumns" | ||
| 17 | + :data="data" | ||
| 18 | + :clone-data="cloneData"></table-body> | ||
| 39 | </div> | 19 | </div> |
| 40 | <div :class="[prefixCls + '-fixed']"> | 20 | <div :class="[prefixCls + '-fixed']"> |
| 41 | - <table cellspacing="0" cellpadding="0" border="0"> | ||
| 42 | - <colgroup> | ||
| 43 | - <col v-for="column in leftFixedColumns" :width="setCellWidth(column, $index)"> | ||
| 44 | - </colgroup> | ||
| 45 | - <tbody :class="[prefixCls + '-tbody']"> | ||
| 46 | - <tr> | ||
| 47 | - | ||
| 48 | - </tr> | ||
| 49 | - </tbody> | ||
| 50 | - </table> | 21 | + <!--todo设置个div头部--> |
| 22 | + <table-body | ||
| 23 | + fixed | ||
| 24 | + :prefix-cls="prefixCls" | ||
| 25 | + :style="fixedTableStyle" | ||
| 26 | + :columns="leftFixedColumns" | ||
| 27 | + :data="data" | ||
| 28 | + :clone-data="cloneData"></table-body> | ||
| 51 | </div> | 29 | </div> |
| 52 | <div :class="[prefixCls + '-fixed-right']"> | 30 | <div :class="[prefixCls + '-fixed-right']"> |
| 53 | - | 31 | + <table-body |
| 32 | + fixed | ||
| 33 | + :prefix-cls="prefixCls" | ||
| 34 | + :style="fixedRightTableStyle" | ||
| 35 | + :columns="rightFixedColumns" | ||
| 36 | + :data="data" | ||
| 37 | + :clone-data="cloneData"></table-body> | ||
| 54 | </div> | 38 | </div> |
| 55 | <div :class="[prefixCls + '-footer']" v-if="showSlotFooter" v-el:footer><slot name="footer"></slot></div> | 39 | <div :class="[prefixCls + '-footer']" v-if="showSlotFooter" v-el:footer><slot name="footer"></slot></div> |
| 56 | </div> | 40 | </div> |
| 57 | </template> | 41 | </template> |
| 58 | <script> | 42 | <script> |
| 59 | - import TableHead from './table-head.vue'; | ||
| 60 | - import Checkbox from '../checkbox/checkbox.vue'; | ||
| 61 | - import Cell from './cell.vue'; | ||
| 62 | - import Mixin from './mixin'; | 43 | + import tableHead from './table-head.vue'; |
| 44 | + import tableBody from './table-body.vue'; | ||
| 63 | import { oneOf, getStyle, deepCopy } from '../../utils/assist'; | 45 | import { oneOf, getStyle, deepCopy } from '../../utils/assist'; |
| 64 | const prefixCls = 'ivu-table'; | 46 | const prefixCls = 'ivu-table'; |
| 65 | 47 | ||
| 66 | export default { | 48 | export default { |
| 67 | - mixins: [ Mixin ], | ||
| 68 | - components: { TableHead, Checkbox, Cell }, | 49 | + components: { tableHead, tableBody }, |
| 69 | props: { | 50 | props: { |
| 70 | data: { | 51 | data: { |
| 71 | type: Array, | 52 | type: Array, |
| @@ -154,6 +135,16 @@ | @@ -154,6 +135,16 @@ | ||
| 154 | if (this.tableWidth !== 0) style.width = `${this.tableWidth}px`; | 135 | if (this.tableWidth !== 0) style.width = `${this.tableWidth}px`; |
| 155 | return style; | 136 | return style; |
| 156 | }, | 137 | }, |
| 138 | + fixedTableStyle () { | ||
| 139 | + let style = {}; | ||
| 140 | + if (this.leftFixedColumns.length) style.width = this.leftFixedColumns.reduce((a, b) => a + b); | ||
| 141 | + return style; | ||
| 142 | + }, | ||
| 143 | + fixedRightTableStyle () { | ||
| 144 | + let style = {}; | ||
| 145 | + if (this.rightFixedColumns.length) style.width = this.rightFixedColumns.reduce((a, b) => a + b); | ||
| 146 | + return style; | ||
| 147 | + }, | ||
| 157 | bodyStyle () { | 148 | bodyStyle () { |
| 158 | let style = {}; | 149 | let style = {}; |
| 159 | if (this.bodyHeight !== 0) style.height = `${this.bodyHeight}px`; | 150 | if (this.bodyHeight !== 0) style.height = `${this.bodyHeight}px`; |
| @@ -177,7 +168,7 @@ | @@ -177,7 +168,7 @@ | ||
| 177 | let autoWidthIndex = -1; | 168 | let autoWidthIndex = -1; |
| 178 | if (allWidth) autoWidthIndex = this.cloneColumns.findIndex(cell => !cell.width); | 169 | if (allWidth) autoWidthIndex = this.cloneColumns.findIndex(cell => !cell.width); |
| 179 | 170 | ||
| 180 | - const $td = this.$els.tbody.querySelectorAll('tbody tr')[0].querySelectorAll('td'); | 171 | + const $td = this.$refs.tbody.$el.querySelectorAll('tbody tr')[0].querySelectorAll('td'); |
| 181 | for (let i = 0; i < $td.length; i++) { // can not use forEach in Firefox | 172 | for (let i = 0; i < $td.length; i++) { // can not use forEach in Firefox |
| 182 | if (i === autoWidthIndex) { | 173 | if (i === autoWidthIndex) { |
| 183 | this.columnsWidth.push(parseInt(getStyle($td[i], 'width')) - 1); | 174 | this.columnsWidth.push(parseInt(getStyle($td[i], 'width')) - 1); |
src/styles/components/table.less
| @@ -189,4 +189,29 @@ | @@ -189,4 +189,29 @@ | ||
| 189 | background-color: @table-td-highlight-bg; | 189 | background-color: @table-td-highlight-bg; |
| 190 | } | 190 | } |
| 191 | } | 191 | } |
| 192 | + | ||
| 193 | + &-fixed, &-fixed-right{ | ||
| 194 | + position: absolute; | ||
| 195 | + top: 0; | ||
| 196 | + left: 0; | ||
| 197 | + box-shadow: 1px 0 8px #d3d4d6; | ||
| 198 | + overflow-x: hidden; | ||
| 199 | + | ||
| 200 | + &::before { | ||
| 201 | + content: ''; | ||
| 202 | + width: 100%; | ||
| 203 | + height: 1px; | ||
| 204 | + background-color: @border-color-base; | ||
| 205 | + position: absolute; | ||
| 206 | + left: 0; | ||
| 207 | + bottom: 0; | ||
| 208 | + z-index: 4; | ||
| 209 | + } | ||
| 210 | + } | ||
| 211 | + &-fixed-right{ | ||
| 212 | + top: 0; | ||
| 213 | + left: auto; | ||
| 214 | + right: 0; | ||
| 215 | + box-shadow: -1px 0 8px #d3d4d6; | ||
| 216 | + } | ||
| 192 | } | 217 | } |
| 193 | \ No newline at end of file | 218 | \ No newline at end of file |
test/routers/table.vue