update Table

update Table
This commit is contained in:
梁灏 2016-11-24 15:27:46 +08:00
parent 744eb0af93
commit 0d13646576
7 changed files with 306 additions and 59 deletions

View file

@ -0,0 +1,7 @@
export default {
methods: {
alignCls (column) {
return column.align ? `${this.prefixCls}-column-${column.align}` : '';
}
}
}

View file

@ -1,15 +1,27 @@
<template> <template>
<thead> <thead>
<tr> <tr>
<th v-for="column in columns" :class="fixedCls(column)">{{{ renderHeader(column, $index) }}}</th> <th v-for="column in columns" :class="alignCls(column)">
<div :class="[prefixCls + '-cell']">
<template v-if="column.type === 'selection'"><Checkbox :checked="isSelectAll" @on-change="selectAll"></Checkbox></template>
<template v-else>{{{ renderHeader(column, $index) }}}</template>
</div>
</th>
</tr> </tr>
</thead> </thead>
</template> </template>
<script> <script>
import Checkbox from '../checkbox/checkbox.vue';
import Mixin from './mixin';
import { deepCopy } from '../../utils/assist';
export default { export default {
mixins: [ Mixin ],
components: { Checkbox },
props: { props: {
prefixCls: String, prefixCls: String,
columns: Array columns: Array,
cloneData: Array
}, },
data () { data () {
return { return {
@ -17,7 +29,9 @@
} }
}, },
computed: { computed: {
isSelectAll () {
return !this.cloneData.some(data => !data._isChecked);
}
}, },
methods: { methods: {
renderHeader (column, $index) { renderHeader (column, $index) {
@ -27,8 +41,18 @@
return column.title || '#'; return column.title || '#';
} }
}, },
fixedCls (column) { selectAll () {
return column.fixed ? `${this.prefixCls}-${column.fixed}` : ''; const status = !this.isSelectAll;
let tmpData = deepCopy(this.cloneData);
tmpData.forEach((data) => {
data._isChecked = status;
});
this.cloneData = tmpData;
if (status) {
this.$parent.selectAll();
}
} }
} }
} }

View file

@ -1,24 +1,35 @@
<template> <template>
<div :class="classes"> <div :class="classes">
<div :class="[prefixCls + '-header']"> <div :class="[prefixCls + '-header']" v-if="showHeader">
<table cellspacing="0" cellpadding="0" border="0" :style="{width: tableWidth + 'px'}"> <table cellspacing="0" cellpadding="0" border="0" :style="tableStyle">
<colgroup> <colgroup>
<col v-for="column in columns" :width="setCellWidth(column, $index)"> <col v-for="column in columns" :width="setCellWidth(column, $index)">
</colgroup> </colgroup>
<thead <thead
is="table-head" is="table-head"
:prefix-cls="prefixCls + '-thead'" :prefix-cls="prefixCls"
:clone-data.sync="cloneData"
:columns="columns"></thead> :columns="columns"></thead>
</table> </table>
</div> </div>
<div :class="[prefixCls + '-body']"> <div :class="[prefixCls + '-body']">
<table cellspacing="0" cellpadding="0" border="0" :style="{width: tableWidth + 'px'}" v-el:tbody> <table cellspacing="0" cellpadding="0" border="0" :style="tableStyle" v-el:tbody>
<colgroup> <colgroup>
<col v-for="column in columns" :width="setCellWidth(column, $index)"> <col v-for="column in columns" :width="setCellWidth(column, $index)">
</colgroup> </colgroup>
<tbody :class="[prefixCls + '-tbody']" v-el:render> <tbody :class="[prefixCls + '-tbody']" v-el:render>
<tr :class="[prefixCls + '-row']" v-for="(index, row) in data"> <tr
<td v-for="column in columns">{{{ renderRow(row, column) }}}</td> v-for="(index, row) in data"
:class="[prefixCls + '-row', {[prefixCls + '-row-highlight']: cloneData[index] && cloneData[index]._isHighlight}]"
@click.stop="highlightCurrentRow(index)">
<td v-for="column in columns" :class="alignCls(column)">
<div :class="[prefixCls + '-cell']">
<template v-if="column.type === 'selection'">
<Checkbox :checked="cloneData[index] && cloneData[index]._isChecked" @on-change="toggleSelect(index)"></Checkbox>
</template>
<template v-else>{{{ renderRow(row, column, index) }}}</template>
</div>
</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
@ -27,11 +38,14 @@
</template> </template>
<script> <script>
import TableHead from './table-head.vue'; import TableHead from './table-head.vue';
import { oneOf, getStyle } from '../../utils/assist'; import Checkbox from '../checkbox/checkbox.vue';
import Mixin from './mixin';
import { oneOf, getStyle, deepCopy } from '../../utils/assist';
const prefixCls = 'ivu-table'; const prefixCls = 'ivu-table';
export default { export default {
components: { TableHead }, mixins: [ Mixin ],
components: { TableHead, Checkbox },
props: { props: {
data: { data: {
type: Array, type: Array,
@ -58,21 +72,11 @@
type: Boolean, type: Boolean,
default: false default: false
}, },
fit: {
type: Boolean,
default: true
},
showHeader: { showHeader: {
type: Boolean, type: Boolean,
default: true default: true
}, },
selection: { highlightRow: {
validator (value) {
return oneOf(value, ['single', 'multiple', false]);
},
default: false
},
showIndex: {
type: Boolean, type: Boolean,
default: false default: false
} }
@ -82,7 +86,8 @@
tableWidth: 0, tableWidth: 0,
columnsWidth: [], columnsWidth: [],
prefixCls: prefixCls, prefixCls: prefixCls,
compiledUids: [] compiledUids: [],
cloneData: deepCopy(this.data)
} }
}, },
computed: { computed: {
@ -90,14 +95,21 @@
return [ return [
`${prefixCls}`, `${prefixCls}`,
{ {
[`${prefixCls}-${this.size}`]: !!this.size [`${prefixCls}-${this.size}`]: !!this.size,
[`${prefixCls}-border`]: this.border,
[`${prefixCls}-stripe`]: this.stripe
} }
] ]
},
tableStyle () {
let style = {};
if (this.tableWidth !== 0) style.width = `${this.tableWidth}px`;
return style;
} }
}, },
methods: { methods: {
renderRow (row, column) { renderRow (row, column, index) {
return 'render' in column ? '' : row[column.key]; return column.type === 'index' ? index + 1 : column.render ? '' : row[column.key];
}, },
compileRender (update = false) { compileRender (update = false) {
this.$nextTick(() => { this.$nextTick(() => {
@ -117,7 +129,7 @@
const column = this.columns[i]; const column = this.columns[i];
if (column.render) { if (column.render) {
for (let j = 0; j < this.data.length; j++) { for (let j = 0; j < this.data.length; j++) {
// todo renderdata // todo renderdata
const row = this.data[j]; const row = this.data[j];
const template = column.render(row, column, j); const template = column.render(row, column, j);
const cell = document.createElement('div'); const cell = document.createElement('div');
@ -129,8 +141,8 @@
if (_oldParentChildLen !== _newParentChildLen) { // if render normal html node, do not tag if (_oldParentChildLen !== _newParentChildLen) { // if render normal html node, do not tag
this.compiledUids.push(this.$parent.$children[this.$parent.$children.length - 1]._uid); // tag it, and delete when data or columns update this.compiledUids.push(this.$parent.$children[this.$parent.$children.length - 1]._uid); // tag it, and delete when data or columns update
} }
$el.children[j].children[i].innerHTML = ''; $el.children[j].children[i].children[0].innerHTML = '';
$el.children[j].children[i].appendChild(cell); $el.children[j].children[i].children[0].appendChild(cell);
} }
} }
} }
@ -148,6 +160,49 @@
}, },
setCellWidth (column, index) { setCellWidth (column, index) {
return column.width ? column.width : this.columnsWidth[index]; return column.width ? column.width : this.columnsWidth[index];
},
highlightCurrentRow (index) {
if (!this.highlightRow || this.cloneData[index]._isHighlight) return;
let oldIndex = -1;
this.cloneData.forEach((item, index) => {
if (item._isHighlight) {
oldIndex = index;
item._isHighlight = false;
return true;
}
});
const row = Object.assign({}, this.cloneData[index], {
_isHighlight: true
});
this.cloneData.$set(index, row);
const oldData = oldIndex < 0 ? null : JSON.parse(JSON.stringify(this.data[oldIndex]));
this.$emit('on-current-change', JSON.parse(JSON.stringify(this.data[index])), oldData);
},
getSelection () {
let selectionIndexes = [];
this.cloneData.forEach((data, index) => {
if (data._isChecked) selectionIndexes.push(index);
});
return JSON.parse(JSON.stringify(this.data.filter((data, index) => selectionIndexes.indexOf(index) > -1)));
},
toggleSelect (index) {
const status = !this.cloneData[index]._isChecked;
const row = Object.assign({}, this.cloneData[index], {
_isChecked: status
});
this.cloneData.$set(index, row);
const selection = this.getSelection();
if (status) {
this.$emit('on-select', selection, JSON.parse(JSON.stringify(this.data[index])));
}
this.$emit('on-selection-change', selection);
},
selectAll () {
this.$emit('on-select-all', this.getSelection());
} }
}, },
ready () { ready () {
@ -160,6 +215,7 @@
watch: { watch: {
data: { data: {
handler () { handler () {
this.cloneData = deepCopy(this.data);
this.compileRender(true); this.compileRender(true);
}, },
deep: true deep: true

View file

@ -1,35 +1,118 @@
@table-prefix-cls: ~"@{css-prefix}table"; @table-prefix-cls: ~"@{css-prefix}table";
.@{table-prefix-cls} { .@{table-prefix-cls} {
position: relative; width: 100%;
overflow: hidden;
box-sizing: border-box;
max-width: 100%; max-width: 100%;
background-color: #fff; overflow: hidden;
border-collapse: collapse;
border: 1px solid @border-color-base;
color: @text-color; color: @text-color;
font-size: @font-size-small; font-size: @font-size-small;
background-color: #fff;
border: 1px solid @border-color-base;
border-bottom: 0;
border-collapse: collapse;
box-sizing: border-box;
position: relative;
&-large { th, td
font-size: @font-size-base;
}
& th {
white-space: nowrap;
overflow: hidden;
}
& th,
td
{ {
min-width: 0; min-width: 0;
height: 40px; height: 48px;
box-sizing: border-box; box-sizing: border-box;
text-align: left; text-align: left;
text-overflow: ellipsis; text-overflow: ellipsis;
vertical-align: middle; vertical-align: middle;
position: relative; position: relative;
border-bottom: 1px solid @border-color-base; border-bottom: 1px solid @border-color-split;
}
th {
height: 40px;
white-space: nowrap;
overflow: hidden;
background-color: @table-thead-bg;
}
td{
background-color: #fff;
transition: background-color @transition-time @ease-in-out;
}
th&-column,
td&-column
{
&-left{
text-align: left;
}
&-center{
text-align: center;
}
&-right{
text-align: right;
}
}
& table{
width: 100%;
}
&-border{
th,td{
border-right: 1px solid @border-color-split;
}
}
&-cell{
padding-left: 18px;
padding-right: 18px;
overflow: hidden;
text-overflow: ellipsis;
white-space: normal;
word-break: break-all;
box-sizing: border-box;
}
th &-cell{
display: inline-block;
position: relative;
word-wrap: normal;
vertical-align: middle;
}
&-stripe &-body{
tr:nth-child(2n) {
td{
background-color: @table-td-stripe-bg;
}
}
}
tr:hover{
td{
background-color: @table-td-hover-bg;
}
}
&-large {
font-size: @font-size-base;
th{
height: 48px;
}
td{
height: 60px;
}
}
&-small{
th{
height: 32px;
}
td{
height: 40px;
}
}
&-row-highlight,
tr&-row-highlight:hover,
&-stripe &-body tr&-row-highlight:nth-child(2n)
{
td{
background-color: @table-td-highlight-bg;
}
} }
} }

View file

@ -38,6 +38,10 @@
@background-color-select-hover: @input-disabled-bg; @background-color-select-hover: @input-disabled-bg;
@tooltip-bg : rgba(70, 76, 91, .9); @tooltip-bg : rgba(70, 76, 91, .9);
@head-bg : #f9fafc; @head-bg : #f9fafc;
@table-thead-bg : #f5f7f9;
@table-td-stripe-bg : #f5f7f9;
@table-td-hover-bg : #ebf7ff;
@table-td-highlight-bg : #ebf7ff;
// Shadow // Shadow
@shadow-color : rgba(0, 0, 0, .2); @shadow-color : rgba(0, 0, 0, .2);

View file

@ -70,7 +70,7 @@ export function getStyle (element, styleName) {
styleName = 'cssFloat'; styleName = 'cssFloat';
} }
try { try {
var computed = document.defaultView.getComputedStyle(element, ''); const computed = document.defaultView.getComputedStyle(element, '');
return element.style[styleName] || computed ? computed[styleName] : null; return element.style[styleName] || computed ? computed[styleName] : null;
} catch(e) { } catch(e) {
return element.style[styleName]; return element.style[styleName];
@ -87,4 +87,48 @@ export function warnProp(component, prop, correctType, wrongType) {
correctType = firstUpperCase(correctType); correctType = firstUpperCase(correctType);
wrongType = firstUpperCase(wrongType); wrongType = firstUpperCase(wrongType);
console.error(`[iView warn]: Invalid prop: type check failed for prop ${prop}. Expected ${correctType}, got ${wrongType}. (found in component: ${component})`); console.error(`[iView warn]: Invalid prop: type check failed for prop ${prop}. Expected ${correctType}, got ${wrongType}. (found in component: ${component})`);
} }
function typeOf(obj) {
const toString = Object.prototype.toString;
const map = {
'[object Boolean]' : 'boolean',
'[object Number]' : 'number',
'[object String]' : 'string',
'[object Function]' : 'function',
'[object Array]' : 'array',
'[object Date]' : 'date',
'[object RegExp]' : 'regExp',
'[object Undefined]': 'undefined',
'[object Null]' : 'null',
'[object Object]' : 'object'
};
return map[toString.call(obj)];
}
// deepCopy
function deepCopy(data) {
const t = typeOf(data);
let o;
if (t === 'array') {
o = [];
} else if ( t === 'object') {
o = {};
} else {
return data;
}
if (t === 'array') {
for (let i = 0; i < data.length; i++) {
o.push(deepCopy(data[i]));
}
} else if ( t === 'object') {
for (let i in data) {
o[i] = deepCopy(data[i]);
}
}
return o;
}
export {deepCopy}

View file

@ -1,6 +1,10 @@
<template> <template>
<div> <div>
<i-table :columns="columns" :data="data"></i-table> <!--<i-table size="large" border stripe :columns="columns" :data="data"></i-table>-->
<br>
<i-table border :columns="columns" :data="data" @on-current-change="current" @on-select="select" @on-selection-change="schange" @on-select-all="sall"></i-table>
<br>
<!--<i-table size="small" border stripe :columns="columns" :data="data"></i-table>-->
</div> </div>
</template> </template>
<script> <script>
@ -11,16 +15,20 @@
data () { data () {
return { return {
columns: [ columns: [
{
type: 'selection',
width: 50
},
{ {
title: '姓名', title: '姓名',
key: 'name', key: 'name',
fixed: 'left', align: 'left',
// width: 100 // width: 100
}, },
{ {
title: '年龄', title: '年龄',
key: 'age', key: 'age',
fixed: 'right', align: 'right',
// width: 100 // width: 100
// render (row) { // render (row) {
// return `<i-button>${row.age}</i-button>` // return `<i-button>${row.age}</i-button>`
@ -29,7 +37,7 @@
{ {
title: '地址', title: '地址',
key: 'address', key: 'address',
fixed: 'center', align: 'center',
// width: 100 // width: 100
// render (row, column, index) { // render (row, column, index) {
// if (row.edit) { // if (row.edit) {
@ -65,7 +73,13 @@
name: '刘天娇', name: '刘天娇',
age: 27, age: 27,
address: '北京市东城区', address: '北京市东城区',
edit: true edit: false
},
{
name: '胡国伟',
age: 28,
address: '北京市西城区',
edit: false
} }
] ]
} }
@ -78,12 +92,27 @@
this.$Message.info(name); this.$Message.info(name);
}, },
edit (index) { edit (index) {
this.data[index].edit = true; // this.data[index].edit = true;
this.$Message.info(this.data[index].name);
},
current (newData, oldData) {
console.log(newData);
console.log(oldData);
},
select (a,b){
console.log(a);
console.log(b);
},
schange (a) {
console.log(a)
},
sall (a) {
console.log(a)
} }
}, },
ready () { ready () {
setTimeout(() => { setTimeout(() => {
return; // return
this.data.push({ this.data.push({
name: '刘天娇2', name: '刘天娇2',
age: 272, age: 272,