update Table

update Table
This commit is contained in:
梁灏 2017-03-09 14:11:22 +08:00
parent b2012015da
commit 486d4fda19
9 changed files with 132 additions and 106 deletions

View file

@ -24,7 +24,7 @@
- [x] Radio - [x] Radio
- [x] Checkbox - [x] Checkbox
- [x] Switch - [x] Switch
- [ ] Table - [x] Table
- [x] Select - [x] Select
- [x] Slider - [x] Slider
- [x] DatePicker - [x] DatePicker

View file

@ -49,6 +49,7 @@ li + li { border-left: solid 1px #bbb; padding-left: 10px; margin-left: 10px; }
<li><router-link to="/transfer">Transfer</router-link></li> <li><router-link to="/transfer">Transfer</router-link></li>
<li><router-link to="/date">Date</router-link></li> <li><router-link to="/date">Date</router-link></li>
<li><router-link to="/form">Form</router-link></li> <li><router-link to="/form">Form</router-link></li>
<li><router-link to="/table">Table</router-link></li>
</ul> </ul>
</nav> </nav>
<router-view></router-view> <router-view></router-view>

View file

@ -161,6 +161,10 @@ const router = new VueRouter({
path: '/form', path: '/form',
component: require('./routers/form.vue') component: require('./routers/form.vue')
}, },
{
path: '/table',
component: require('./routers/table.vue')
},
] ]
}); });

View file

@ -1,96 +1,87 @@
<template> <template>
<i-table highlight-row border :content="self" :columns="columns7" :data="data6"></i-table> <Table width="550" border :columns="columns2" :data="data3"></Table>
</template> </template>
<script> <script>
export default { export default {
data () { data () {
return { return {
self: this, columns2: [
columns7: [
{
type: 'selection',
width: 60,
align: 'center'
},
{ {
title: '姓名', title: '姓名',
key: 'name', key: 'name',
render (row, column, index) { width: 100,
return `<Icon type="person"></Icon> <strong>${row.name}</strong>`; fixed: 'left'
}
}, },
{ {
title: '年龄', title: '年龄',
key: 'age', key: 'age',
sortable: true, width: 100
sortMethod: function (a, b, type) { },
if (type === 'asc') { {
return a < b ? 1 : -1; title: '省份',
} else if (type === 'desc') { key: 'province',
return a > b ? 1 : -1; width: 100
} },
} {
title: '市区',
key: 'city',
width: 100
}, },
{ {
title: '地址', title: '地址',
key: 'address' key: 'address',
width: 200
},
{
title: '邮编',
key: 'zip',
width: 100
}, },
{ {
title: '操作', title: '操作',
key: 'action', key: 'action',
width: 150, fixed: 'right',
align: 'center', width: 120,
render (row, column, index) { render () {
// return `<i-button type="primary" size="small" @click="show(${index})"></i-button> <i-button type="error" size="small" @click="remove(${index})"></i-button>`; return `<Button type="text" size="small">查看</Button><Button type="text" size="small">编辑</Button>`;
return `<Poptip width="250" confirm placement="left" title="您确认删除吗?" @on-ok="deleteProject(${index})">
<i-button size="small" type="error">删除</i-button>
</Poptip>`
} }
} }
], ],
data6: [ data3: [
{ {
name: '王小明', name: '王小明',
age: 18, age: 18,
address: '北京市朝阳区芍药居', address: '北京市朝阳区芍药居',
_highlight: true, province: '北京市',
_checked: true, city: '朝阳区',
_disabled: false zip: 100000
}, },
{ {
name: '张小刚', name: '张小刚',
age: 25, age: 25,
address: '北京市海淀区西二旗', address: '北京市海淀区西二旗',
_checked: false, province: '北京市',
_disabled: true city: '海淀区',
zip: 100000
}, },
{ {
name: '李小红', name: '李小红',
age: 30, age: 30,
address: '上海市浦东新区世纪大道', address: '上海市浦东新区世纪大道',
_checked: true, province: '上海市',
_disabled: true city: '浦东新区',
zip: 100000
}, },
{ {
name: '周小伟', name: '周小伟',
age: 26, age: 26,
address: '深圳市南山区深南大道', address: '深圳市南山区深南大道',
_checked: false, province: '广东',
_disabled: false city: '南山区',
zip: 100000
} }
] ]
} }
},
methods: {
show (index) {
this.$Modal.info({
title: '用户信息',
content: `姓名:${this.data6[index].name}<br>年龄:${this.data6[index].age}<br>地址:${this.data6[index].address}`
})
},
remove (index) {
this.data6.splice(index, 1);
}
} }
} }
</script> </script>

View file

@ -2,15 +2,17 @@
<div :class="classes"> <div :class="classes">
<template v-if="renderType === 'index'">{{naturalIndex + 1}}</template> <template v-if="renderType === 'index'">{{naturalIndex + 1}}</template>
<template v-if="renderType === 'selection'"> <template v-if="renderType === 'selection'">
<Checkbox :checked="checked" @on-change="toggleSelect" :disabled="disabled"></Checkbox> <Checkbox :value="checked" @on-change="toggleSelect" :disabled="disabled"></Checkbox>
</template> </template>
<template v-if="renderType === 'normal'">{{{ row[column.key] }}}</template> <template v-if="renderType === 'normal'"><span v-html="row[column.key]"></span></template>
</div> </div>
</template> </template>
<script> <script>
import Vue from 'vue';
import Checkbox from '../checkbox/checkbox.vue'; import Checkbox from '../checkbox/checkbox.vue';
export default { export default {
name: 'TableCell',
components: { Checkbox }, components: { Checkbox },
props: { props: {
prefixCls: String, prefixCls: String,
@ -29,7 +31,7 @@
return { return {
renderType: '', renderType: '',
uid: -1, uid: -1,
content: this.$parent.$parent.content content: this.$parent.$parent.currentContent
}; };
}, },
computed: { computed: {
@ -51,14 +53,34 @@
const cell = document.createElement('div'); const cell = document.createElement('div');
cell.innerHTML = template; cell.innerHTML = template;
const _oldParentChildLen = $parent.$children.length; const _oldParentChildLen = $parent.$children.length;
$parent.$compile(cell); // todo ready // $parent.$compile(cell); // todo ready
const _newParentChildLen = $parent.$children.length; const _newParentChildLen = $parent.$children.length;
if (_oldParentChildLen !== _newParentChildLen) { // if render normal html node, do not tag if (_oldParentChildLen !== _newParentChildLen) { // if render normal html node, do not tag
this.uid = $parent.$children[$parent.$children.length - 1]._uid; // tag it, and delete when data or columns update this.uid = $parent.$children[$parent.$children.length - 1]._uid; // tag it, and delete when data or columns update
} }
this.$el.innerHTML = ''; this.$el.innerHTML = '';
this.$el.appendChild(cell); // this.$el.appendChild(cell);
let methods = {};
let $_parent = this.$parent;
while($_parent != null && $_parent._name != '<Table>'){
$_parent = $_parent.$parent;
}
if ($_parent) {
Object.keys($_parent).forEach(key => {
const func = this.$parent.$parent.$parent[`${key}`];
if(typeof(func) === 'function' &&func.name === 'boundFn'){
methods[`${key}`] = func;
}
});
}
const res = Vue.compile(cell.outerHTML);
const compt = new Vue({
render: res.render,
staticRenderFns: res.staticRenderFns,
methods: methods
});
compt.$mount(this.$el);
} }
}, },
destroy () { destroy () {
@ -73,7 +95,7 @@
this.$parent.$parent.toggleSelect(this.index); this.$parent.$parent.toggleSelect(this.index);
} }
}, },
compiled () { created () {
if (this.column.type === 'index') { if (this.column.type === 'index') {
this.renderType = 'index'; this.renderType = 'index';
} else if (this.column.type === 'selection') { } else if (this.column.type === 'selection') {
@ -84,8 +106,10 @@
this.renderType = 'normal'; this.renderType = 'normal';
} }
}, },
ready () { mounted () {
this.compile(); this.$nextTick(() => {
this.compile();
});
}, },
beforeDestroy () { beforeDestroy () {
this.destroy(); this.destroy();

View file

@ -1,11 +1,11 @@
<template> <template>
<table cellspacing="0" cellpadding="0" border="0" :style="style"> <table cellspacing="0" cellpadding="0" border="0" :style="styleObject">
<colgroup> <colgroup>
<col v-for="column in columns" :width="setCellWidth(column, $index, false)"> <col v-for="(column, index) in columns" :width="setCellWidth(column, index, false)">
</colgroup> </colgroup>
<tbody :class="[prefixCls + '-tbody']"> <tbody :class="[prefixCls + '-tbody']">
<tr <tr
v-for="(index, row) in data" v-for="(row, index) in data"
:class="rowClasses(row._index)" :class="rowClasses(row._index)"
@mouseenter.stop="handleMouseIn(row._index)" @mouseenter.stop="handleMouseIn(row._index)"
@mouseleave.stop="handleMouseOut(row._index)" @mouseleave.stop="handleMouseOut(row._index)"
@ -32,11 +32,12 @@
import Mixin from './mixin'; import Mixin from './mixin';
export default { export default {
name: 'TableBody',
mixins: [ Mixin ], mixins: [ Mixin ],
components: { Cell }, components: { Cell },
props: { props: {
prefixCls: String, prefixCls: String,
style: Object, styleObject: Object,
columns: Array, columns: Array,
data: Array, // rebuildData data: Array, // rebuildData
objData: Object, objData: Object,

View file

@ -1,43 +1,43 @@
<template> <template>
<table cellspacing="0" cellpadding="0" border="0" :style="styles"> <table cellspacing="0" cellpadding="0" border="0" :style="styles">
<colgroup> <colgroup>
<col v-for="column in columns" :width="setCellWidth(column, $index, true)"> <col v-for="(column, index) in columns" :width="setCellWidth(column, index, true)">
</colgroup> </colgroup>
<thead> <thead>
<tr> <tr>
<th v-for="(index, column) in columns" :class="alignCls(column)"> <th v-for="(column, index) in columns" :class="alignCls(column)">
<div :class="cellClasses(column)"> <div :class="cellClasses(column)">
<template v-if="column.type === 'selection'"><Checkbox :checked="isSelectAll" @on-change="selectAll"></Checkbox></template> <template v-if="column.type === 'selection'"><Checkbox :value="isSelectAll" @on-change="selectAll"></Checkbox></template>
<template v-else> <template v-else>
{{{ renderHeader(column, $index) }}} <span v-html="renderHeader(column, index)"></span>
<span :class="[prefixCls + '-sort']" v-if="column.sortable"> <span :class="[prefixCls + '-sort']" v-if="column.sortable">
<i class="ivu-icon ivu-icon-arrow-up-b" :class="{on: column._sortType === 'asc'}" @click="handleSort($index, 'asc')"></i> <i class="ivu-icon ivu-icon-arrow-up-b" :class="{on: column._sortType === 'asc'}" @click="handleSort(index, 'asc')"></i>
<i class="ivu-icon ivu-icon-arrow-down-b" :class="{on: column._sortType === 'desc'}" @click="handleSort($index, 'desc')"></i> <i class="ivu-icon ivu-icon-arrow-down-b" :class="{on: column._sortType === 'desc'}" @click="handleSort(index, 'desc')"></i>
</span> </span>
<Poptip <Poptip
v-if="isPopperShow(column)" v-if="isPopperShow(column)"
:visible.sync="column._filterVisible" :visible="column._filterVisible"
placement="bottom" placement="bottom"
@on-popper-hide="handleFilterHide($index)"> @on-popper-hide="handleFilterHide(index)">
<span :class="[prefixCls + '-filter']"> <span :class="[prefixCls + '-filter']">
<i class="ivu-icon ivu-icon-funnel" :class="{on: column._isFiltered}"></i> <i class="ivu-icon ivu-icon-funnel" :class="{on: column._isFiltered}"></i>
</span> </span>
<div slot="content" :class="[prefixCls + '-filter-list']" v-if="column._filterMultiple"> <div slot="content" :class="[prefixCls + '-filter-list']" v-if="column._filterMultiple">
<div :class="[prefixCls + '-filter-list-item']"> <div :class="[prefixCls + '-filter-list-item']">
<checkbox-group :model.sync="column._filterChecked"> <checkbox-group v-model="column._filterChecked">
<checkbox v-for="item in column.filters" :value="item.value">{{ item.label }}</checkbox> <checkbox v-for="item in column.filters" :value="item.value">{{ item.label }}</checkbox>
</checkbox-group> </checkbox-group>
</div> </div>
<div :class="[prefixCls + '-filter-footer']"> <div :class="[prefixCls + '-filter-footer']">
<i-button type="text" size="small" :disabled="!column._filterChecked.length" @click="handleFilter($index)">{{ t('i.table.confirmFilter') }}</i-button> <i-button type="text" size="small" :disabled="!column._filterChecked.length" @click.native="handleFilter(index)">{{ t('i.table.confirmFilter') }}</i-button>
<i-button type="text" size="small" @click="handleReset($index)">{{ t('i.table.resetFilter') }}</i-button> <i-button type="text" size="small" @click.native="handleReset(index)">{{ t('i.table.resetFilter') }}</i-button>
</div> </div>
</div> </div>
<div slot="content" :class="[prefixCls + '-filter-list']" v-else> <div slot="content" :class="[prefixCls + '-filter-list']" v-else>
<ul :class="[prefixCls + '-filter-list-single']"> <ul :class="[prefixCls + '-filter-list-single']">
<li <li
:class="itemAllClasses(column)" :class="itemAllClasses(column)"
@click="handleReset($index)">{{ t('i.table.clearFilter') }}</li> @click="handleReset(index)">{{ t('i.table.clearFilter') }}</li>
<li <li
:class="itemClasses(column, item)" :class="itemClasses(column, item)"
v-for="item in column.filters" v-for="item in column.filters"
@ -61,11 +61,12 @@
import Locale from '../../mixins/locale'; import Locale from '../../mixins/locale';
export default { export default {
name: 'TableHead',
mixins: [ Mixin, Locale ], mixins: [ Mixin, Locale ],
components: { CheckboxGroup, Checkbox, Poptip, iButton }, components: { CheckboxGroup, Checkbox, Poptip, iButton },
props: { props: {
prefixCls: String, prefixCls: String,
style: Object, styleObject: Object,
columns: Array, columns: Array,
objData: Object, objData: Object,
data: Array, // rebuildData data: Array, // rebuildData
@ -77,8 +78,8 @@
}, },
computed: { computed: {
styles () { styles () {
const style = Object.assign({}, this.style); const style = Object.assign({}, this.styleObject);
const width = this.$parent.bodyHeight === 0 ? parseInt(this.style.width) : parseInt(this.style.width) + this.$parent.scrollBarWidth; const width = this.$parent.bodyHeight === 0 ? parseInt(this.styleObject.width) : parseInt(this.styleObject.width) + this.$parent.scrollBarWidth;
style.width = `${width}px`; style.width = `${width}px`;
return style; return style;
}, },

View file

@ -1,22 +1,22 @@
<template> <template>
<div :class="wrapClasses" :style="styles"> <div :class="wrapClasses" :style="styles">
<div :class="classes"> <div :class="classes">
<div :class="[prefixCls + '-title']" v-if="showSlotHeader" v-el:title><slot name="header"></slot></div> <div :class="[prefixCls + '-title']" v-if="showSlotHeader" ref="title"><slot name="header"></slot></div>
<div :class="[prefixCls + '-header']" v-if="showHeader" v-el:header @mousewheel="handleMouseWheel"> <div :class="[prefixCls + '-header']" v-if="showHeader" ref="header" @mousewheel="handleMouseWheel">
<table-head <table-head
:prefix-cls="prefixCls" :prefix-cls="prefixCls"
:style="tableStyle" :styleObject="tableStyle"
:columns="cloneColumns" :columns="cloneColumns"
:obj-data="objData" :obj-data="objData"
:columns-width="columnsWidth" :columns-width="columnsWidth"
:data="rebuildData"></table-head> :data="rebuildData"></table-head>
</div> </div>
<div :class="[prefixCls + '-body']" :style="bodyStyle" v-el:body @scroll="handleBodyScroll" <div :class="[prefixCls + '-body']" :style="bodyStyle" ref="body" @scroll="handleBodyScroll"
v-show="!((!!noDataText && (!data || data.length === 0)) || (!!noFilteredDataText && (!rebuildData || rebuildData.length === 0)))"> v-show="!((!!noDataText && (!data || data.length === 0)) || (!!noFilteredDataText && (!rebuildData || rebuildData.length === 0)))">
<table-body <table-body
v-ref:tbody ref="tbody"
:prefix-cls="prefixCls" :prefix-cls="prefixCls"
:style="tableStyle" :styleObject="tableStyle"
:columns="cloneColumns" :columns="cloneColumns"
:data="rebuildData" :data="rebuildData"
:columns-width="columnsWidth" :columns-width="columnsWidth"
@ -24,12 +24,13 @@
</div> </div>
<div <div
:class="[prefixCls + '-tip']" :class="[prefixCls + '-tip']"
v-else> v-show="((!!noDataText && (!data || data.length === 0)) || (!!noFilteredDataText && (!rebuildData || rebuildData.length === 0)))">
<table cellspacing="0" cellpadding="0" border="0"> <table cellspacing="0" cellpadding="0" border="0">
<tbody> <tbody>
<tr> <tr>
<td :style="{ 'height': bodyStyle.height }"> <td :style="{ 'height': bodyStyle.height }">
{{{!data || data.length === 0 ? noDataText : noFilteredDataText}}} <span v-html="noDataText" v-if="!data || data.length === 0"></span>
<span v-html="noFilteredDataText" v-else></span>
</td> </td>
</tr> </tr>
</tbody> </tbody>
@ -40,17 +41,17 @@
<table-head <table-head
fixed="left" fixed="left"
:prefix-cls="prefixCls" :prefix-cls="prefixCls"
:style="fixedTableStyle" :styleObject="fixedTableStyle"
:columns="leftFixedColumns" :columns="leftFixedColumns"
:obj-data="objData" :obj-data="objData"
:columns-width.sync="columnsWidth" :columns-width.sync="columnsWidth"
:data="rebuildData"></table-head> :data="rebuildData"></table-head>
</div> </div>
<div :class="[prefixCls + '-fixed-body']" :style="fixedBodyStyle" v-el:fixed-body> <div :class="[prefixCls + '-fixed-body']" :style="fixedBodyStyle" ref="fixedBody">
<table-body <table-body
fixed="left" fixed="left"
:prefix-cls="prefixCls" :prefix-cls="prefixCls"
:style="fixedTableStyle" :styleObject="fixedTableStyle"
:columns="leftFixedColumns" :columns="leftFixedColumns"
:data="rebuildData" :data="rebuildData"
:columns-width="columnsWidth" :columns-width="columnsWidth"
@ -62,24 +63,24 @@
<table-head <table-head
fixed="right" fixed="right"
:prefix-cls="prefixCls" :prefix-cls="prefixCls"
:style="fixedRightTableStyle" :styleObject="fixedRightTableStyle"
:columns="rightFixedColumns" :columns="rightFixedColumns"
:obj-data="objData" :obj-data="objData"
:columns-width.sync="columnsWidth" :columns-width="columnsWidth"
:data="rebuildData"></table-head> :data="rebuildData"></table-head>
</div> </div>
<div :class="[prefixCls + '-fixed-body']" :style="fixedBodyStyle" v-el:fixed-right-body> <div :class="[prefixCls + '-fixed-body']" :style="fixedBodyStyle" ref="fixedRightBody">
<table-body <table-body
fixed="right" fixed="right"
:prefix-cls="prefixCls" :prefix-cls="prefixCls"
:style="fixedRightTableStyle" :styleObject="fixedRightTableStyle"
:columns="rightFixedColumns" :columns="rightFixedColumns"
:data="rebuildData" :data="rebuildData"
:columns-width="columnsWidth" :columns-width="columnsWidth"
:obj-data="objData"></table-body> :obj-data="objData"></table-body>
</div> </div>
</div> </div>
<div :class="[prefixCls + '-footer']" v-if="showSlotFooter" v-el:footer><slot name="footer"></slot></div> <div :class="[prefixCls + '-footer']" v-if="showSlotFooter" ref="footer"><slot name="footer"></slot></div>
</div> </div>
</div> </div>
</template> </template>
@ -93,6 +94,7 @@
const prefixCls = 'ivu-table'; const prefixCls = 'ivu-table';
export default { export default {
name: 'Table',
components: { tableHead, tableBody }, components: { tableHead, tableBody },
props: { props: {
data: { data: {
@ -170,7 +172,8 @@
showSlotFooter: true, showSlotFooter: true,
bodyHeight: 0, bodyHeight: 0,
bodyRealHeight: 0, bodyRealHeight: 0,
scrollBarWidth: getScrollBarSize() scrollBarWidth: getScrollBarSize(),
currentContent: this.content
}; };
}, },
computed: { computed: {
@ -415,9 +418,9 @@
fixedHeader () { fixedHeader () {
if (this.height) { if (this.height) {
this.$nextTick(() => { this.$nextTick(() => {
const titleHeight = parseInt(getStyle(this.$els.title, 'height')) || 0; const titleHeight = parseInt(getStyle(this.$refs.title, 'height')) || 0;
const headerHeight = parseInt(getStyle(this.$els.header, 'height')) || 0; const headerHeight = parseInt(getStyle(this.$refs.header, 'height')) || 0;
const footerHeight = parseInt(getStyle(this.$els.footer, 'height')) || 0; const footerHeight = parseInt(getStyle(this.$refs.footer, 'height')) || 0;
this.bodyHeight = this.height - titleHeight - headerHeight - footerHeight; this.bodyHeight = this.height - titleHeight - headerHeight - footerHeight;
}); });
} else { } else {
@ -428,14 +431,14 @@
this.cloneColumns.forEach((col) => col._filterVisible = false); this.cloneColumns.forEach((col) => col._filterVisible = false);
}, },
handleBodyScroll (event) { handleBodyScroll (event) {
if (this.showHeader) this.$els.header.scrollLeft = event.target.scrollLeft; if (this.showHeader) this.$refs.header.scrollLeft = event.target.scrollLeft;
if (this.isLeftFixed) this.$els.fixedBody.scrollTop = event.target.scrollTop; if (this.isLeftFixed) this.$refs.fixedBody.scrollTop = event.target.scrollTop;
if (this.isRightFixed) this.$els.fixedRightBody.scrollTop = event.target.scrollTop; if (this.isRightFixed) this.$refs.fixedRightBody.scrollTop = event.target.scrollTop;
this.hideColumnFilter(); this.hideColumnFilter();
}, },
handleMouseWheel (event) { handleMouseWheel (event) {
const deltaX = event.deltaX; const deltaX = event.deltaX;
const $body = this.$els.body; const $body = this.$refs.body;
if (deltaX > 0) { if (deltaX > 0) {
$body.scrollLeft = $body.scrollLeft + 10; $body.scrollLeft = $body.scrollLeft + 10;
@ -639,13 +642,13 @@
ExportCsv.download(params.filename, data); ExportCsv.download(params.filename, data);
} }
}, },
compiled () { created () {
if (!this.content) this.content = this.$parent; if (!this.content) this.currentContent = this.$parent;
this.showSlotHeader = this.$els.title.innerHTML.replace(/\n/g, '').replace(/<!--[\w\W\r\n]*?-->/gmi, '') !== ''; this.showSlotHeader = this.$refs.title !== undefined;
this.showSlotFooter = this.$els.footer.innerHTML.replace(/\n/g, '').replace(/<!--[\w\W\r\n]*?-->/gmi, '') !== ''; this.showSlotFooter = this.$refs.footer !== undefined;
this.rebuildData = this.makeDataWithSortAndFilter(); this.rebuildData = this.makeDataWithSortAndFilter();
}, },
ready () { mounted () {
this.handleResize(); this.handleResize();
this.fixedHeader(); this.fixedHeader();
this.$nextTick(() => this.ready = true); this.$nextTick(() => this.ready = true);

View file

@ -33,7 +33,7 @@ import Slider from './components/slider';
import Spin from './components/spin'; import Spin from './components/spin';
import Steps from './components/steps'; import Steps from './components/steps';
import Switch from './components/switch'; import Switch from './components/switch';
// import Table from './components/table'; import Table from './components/table';
import Tabs from './components/tabs'; import Tabs from './components/tabs';
import Tag from './components/tag'; import Tag from './components/tag';
import Timeline from './components/timeline'; import Timeline from './components/timeline';
@ -100,6 +100,7 @@ const iview = {
Steps, Steps,
iSwitch: Switch, iSwitch: Switch,
// iTable: Table, // iTable: Table,
Table,
Tabs: Tabs, Tabs: Tabs,
TabPane: Tabs.Pane, TabPane: Tabs.Pane,
Tag, Tag,