Merge branch '2.0' into 2.0
This commit is contained in:
commit
eeaf90df89
453 changed files with 86037 additions and 26227 deletions
|
@ -1,14 +1,21 @@
|
|||
<template>
|
||||
<div :class="classes" ref="cell">
|
||||
<template v-if="renderType === 'index'">{{naturalIndex + 1}}</template>
|
||||
<template v-if="renderType === 'index'"><span>{{ column.indexMethod ? column.indexMethod(row) : (naturalIndex + 1) }}</span></template>
|
||||
<template v-if="renderType === 'selection'">
|
||||
<Checkbox :value="checked" @click.native.stop="handleClick" @on-change="toggleSelect" :disabled="disabled"></Checkbox>
|
||||
</template>
|
||||
<template v-if="renderType === 'html'"><span v-html="row[column.key]"></span></template>
|
||||
<template v-if="renderType === 'normal'"><span>{{row[column.key]}}</span></template>
|
||||
<template v-if="renderType === 'normal'">
|
||||
<template v-if="column.tooltip">
|
||||
<Tooltip transfer :content="row[column.key]" :disabled="!showTooltip" :max-width="300" class="ivu-table-cell-tooltip">
|
||||
<span ref="content" @mouseenter="handleTooltipIn" @mouseleave="handleTooltipOut" class="ivu-table-cell-tooltip-content">{{ row[column.key] }}</span>
|
||||
</Tooltip>
|
||||
</template>
|
||||
<span v-else>{{row[column.key]}}</span>
|
||||
</template>
|
||||
<template v-if="renderType === 'expand' && !row._disableExpand">
|
||||
<div :class="expandCls" @click="toggleExpand">
|
||||
<Icon type="ios-arrow-right"></Icon>
|
||||
<Icon type="ios-arrow-forward"></Icon>
|
||||
</div>
|
||||
</template>
|
||||
<Cell
|
||||
|
@ -23,10 +30,11 @@
|
|||
import Cell from './expand';
|
||||
import Icon from '../icon/icon.vue';
|
||||
import Checkbox from '../checkbox/checkbox.vue';
|
||||
import Tooltip from '../tooltip/tooltip.vue';
|
||||
|
||||
export default {
|
||||
name: 'TableCell',
|
||||
components: { Icon, Checkbox, Cell },
|
||||
components: { Icon, Checkbox, Cell, Tooltip },
|
||||
props: {
|
||||
prefixCls: String,
|
||||
row: Object,
|
||||
|
@ -45,7 +53,8 @@
|
|||
return {
|
||||
renderType: '',
|
||||
uid: -1,
|
||||
context: this.$parent.$parent.$parent.currentContext
|
||||
context: this.$parent.$parent.$parent.currentContext,
|
||||
showTooltip: false, // 鼠标滑过overflow文本时,再检查是否需要显示
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
@ -55,7 +64,8 @@
|
|||
{
|
||||
[`${this.prefixCls}-hidden`]: !this.fixed && this.column.fixed && (this.column.fixed === 'left' || this.column.fixed === 'right'),
|
||||
[`${this.prefixCls}-cell-ellipsis`]: this.column.ellipsis || false,
|
||||
[`${this.prefixCls}-cell-with-expand`]: this.renderType === 'expand'
|
||||
[`${this.prefixCls}-cell-with-expand`]: this.renderType === 'expand',
|
||||
[`${this.prefixCls}-cell-with-selection`]: this.renderType === 'selection'
|
||||
}
|
||||
];
|
||||
},
|
||||
|
@ -77,6 +87,13 @@
|
|||
},
|
||||
handleClick () {
|
||||
// 放置 Checkbox 冒泡
|
||||
},
|
||||
handleTooltipIn () {
|
||||
const $content = this.$refs.content;
|
||||
this.showTooltip = $content.scrollWidth > $content.offsetWidth;
|
||||
},
|
||||
handleTooltipOut () {
|
||||
this.showTooltip = false;
|
||||
}
|
||||
},
|
||||
created () {
|
||||
|
|
|
@ -17,22 +17,13 @@ export default {
|
|||
isPopperShow (column) {
|
||||
return column.filters && ((!this.fixed && !column.fixed) || (this.fixed === 'left' && column.fixed === 'left') || (this.fixed === 'right' && column.fixed === 'right'));
|
||||
},
|
||||
setCellWidth (column, index, top) {
|
||||
setCellWidth (column) {
|
||||
let width = '';
|
||||
if (column.width) {
|
||||
width = column.width;
|
||||
} else if (this.columnsWidth[column._index]) {
|
||||
width = this.columnsWidth[column._index].width;
|
||||
}
|
||||
// when browser has scrollBar,set a width to resolve scroll position bug
|
||||
if (width && this.columns.length === index + 1 && top && this.$parent.bodyHeight !== 0) {
|
||||
width += this.$parent.scrollBarWidth;
|
||||
}
|
||||
// when fixed type,reset first right fixed column's width
|
||||
if (this.fixed === 'right') {
|
||||
const firstFixedIndex = this.columns.findIndex((col) => col.fixed === 'right');
|
||||
if (firstFixedIndex === index) width += this.$parent.scrollBarWidth;
|
||||
}
|
||||
if (width === '0') width = '';
|
||||
return width;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<table cellspacing="0" cellpadding="0" border="0" :style="styleObject">
|
||||
<colgroup>
|
||||
<col v-for="(column, index) in columns" :width="setCellWidth(column, index, false)">
|
||||
<col v-for="(column, index) in columns" :width="setCellWidth(column)">
|
||||
</colgroup>
|
||||
<tbody :class="[prefixCls + '-tbody']">
|
||||
<template v-for="(row, index) in data">
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
<template>
|
||||
<table cellspacing="0" cellpadding="0" border="0" :style="styles">
|
||||
<colgroup>
|
||||
<col v-for="(column, index) in columns" :width="setCellWidth(column, index, true)">
|
||||
<col v-for="(column, index) in columns" :width="setCellWidth(column)">
|
||||
<col v-if="$parent.showVerticalScrollBar" :width="$parent.scrollBarWidth"/>
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th v-for="(column, index) in columns" :class="alignCls(column)">
|
||||
<tr v-for="(cols, rowIndex) in headRows">
|
||||
<th
|
||||
v-for="(column, index) in cols"
|
||||
:colspan="column.colSpan"
|
||||
:rowspan="column.rowSpan"
|
||||
:class="alignCls(column)">
|
||||
<div :class="cellClasses(column)">
|
||||
<template v-if="column.type === 'expand'">
|
||||
<span v-if="!column.renderHeader">{{ column.title || '' }}</span>
|
||||
|
@ -13,46 +18,51 @@
|
|||
</template>
|
||||
<template v-else-if="column.type === 'selection'"><Checkbox :value="isSelectAll" :disabled="!data.length" @on-change="selectAll"></Checkbox></template>
|
||||
<template v-else>
|
||||
<span v-if="!column.renderHeader" @click="handleSortByHead(index)">{{ column.title || '#' }}</span>
|
||||
<span v-if="!column.renderHeader" :class="{[prefixCls + '-cell-sort']: column.sortable}" @click="handleSortByHead(getColumn(rowIndex, index)._index)">{{ column.title || '#' }}</span>
|
||||
<render-header v-else :render="column.renderHeader" :column="column" :index="index"></render-header>
|
||||
<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-down-b" :class="{on: column._sortType === 'desc'}" @click="handleSort(index, 'desc')"></i>
|
||||
<i class="ivu-icon ivu-icon-md-arrow-dropup" :class="{on: getColumn(rowIndex, index)._sortType === 'asc'}" @click="handleSort(getColumn(rowIndex, index)._index, 'asc')"></i>
|
||||
<i class="ivu-icon ivu-icon-md-arrow-dropdown" :class="{on: getColumn(rowIndex, index)._sortType === 'desc'}" @click="handleSort(getColumn(rowIndex, index)._index, 'desc')"></i>
|
||||
</span>
|
||||
<Poptip
|
||||
v-if="isPopperShow(column)"
|
||||
v-model="column._filterVisible"
|
||||
v-model="getColumn(rowIndex, index)._filterVisible"
|
||||
placement="bottom"
|
||||
@on-popper-hide="handleFilterHide(column._index)">
|
||||
popper-class="ivu-table-popper"
|
||||
transfer
|
||||
@on-popper-hide="handleFilterHide(getColumn(rowIndex, index)._index)">
|
||||
<span :class="[prefixCls + '-filter']">
|
||||
<i class="ivu-icon ivu-icon-funnel" :class="{on: column._isFiltered}"></i>
|
||||
<i class="ivu-icon ivu-icon-ios-funnel" :class="{on: getColumn(rowIndex, index)._isFiltered}"></i>
|
||||
</span>
|
||||
<div slot="content" :class="[prefixCls + '-filter-list']" v-if="column._filterMultiple">
|
||||
|
||||
<div slot="content" :class="[prefixCls + '-filter-list']" v-if="getColumn(rowIndex, index)._filterMultiple">
|
||||
<div :class="[prefixCls + '-filter-list-item']">
|
||||
<checkbox-group v-model="column._filterChecked">
|
||||
<checkbox-group v-model="getColumn(rowIndex, index)._filterChecked">
|
||||
<checkbox v-for="(item, index) in column.filters" :key="index" :label="item.value">{{ item.label }}</checkbox>
|
||||
</checkbox-group>
|
||||
</div>
|
||||
<div :class="[prefixCls + '-filter-footer']">
|
||||
<i-button type="text" size="small" :disabled="!column._filterChecked.length" @click.native="handleFilter(column._index)">{{ t('i.table.confirmFilter') }}</i-button>
|
||||
<i-button type="text" size="small" @click.native="handleReset(column._index)">{{ t('i.table.resetFilter') }}</i-button>
|
||||
<i-button type="text" size="small" :disabled="!getColumn(rowIndex, index)._filterChecked.length" @click.native="handleFilter(getColumn(rowIndex, index)._index)">{{ t('i.table.confirmFilter') }}</i-button>
|
||||
<i-button type="text" size="small" @click.native="handleReset(getColumn(rowIndex, index)._index)">{{ t('i.table.resetFilter') }}</i-button>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="content" :class="[prefixCls + '-filter-list']" v-else>
|
||||
<ul :class="[prefixCls + '-filter-list-single']">
|
||||
<li
|
||||
:class="itemAllClasses(column)"
|
||||
@click="handleReset(column._index)">{{ t('i.table.clearFilter') }}</li>
|
||||
:class="itemAllClasses(getColumn(rowIndex, index))"
|
||||
@click="handleReset(getColumn(rowIndex, index)._index)">{{ t('i.table.clearFilter') }}</li>
|
||||
<li
|
||||
:class="itemClasses(column, item)"
|
||||
:class="itemClasses(getColumn(rowIndex, index), item)"
|
||||
v-for="item in column.filters"
|
||||
@click="handleSelect(column._index, item.value)">{{ item.label }}</li>
|
||||
@click="handleSelect(getColumn(rowIndex, index)._index, item.value)">{{ item.label }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</Poptip>
|
||||
</template>
|
||||
</div>
|
||||
</th>
|
||||
|
||||
<th v-if="$parent.showVerticalScrollBar && rowIndex===0" :class='scrollBarCellClass()' :rowspan="headRows.length"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
|
@ -80,12 +90,14 @@
|
|||
fixed: {
|
||||
type: [Boolean, String],
|
||||
default: false
|
||||
}
|
||||
},
|
||||
columnRows: Array,
|
||||
fixedColumnRows: Array
|
||||
},
|
||||
computed: {
|
||||
styles () {
|
||||
const style = Object.assign({}, this.styleObject);
|
||||
const width = this.$parent.bodyHeight === 0 ? parseInt(this.styleObject.width) : parseInt(this.styleObject.width) + this.$parent.scrollBarWidth;
|
||||
const width = parseInt(this.styleObject.width) ;
|
||||
style.width = `${width}px`;
|
||||
return style;
|
||||
},
|
||||
|
@ -101,6 +113,14 @@
|
|||
}
|
||||
|
||||
return isSelectAll;
|
||||
},
|
||||
headRows () {
|
||||
const isGroup = this.columnRows.length > 1;
|
||||
if (isGroup) {
|
||||
return this.fixed ? this.fixedColumnRows : this.columnRows;
|
||||
} else {
|
||||
return [this.columns];
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
@ -108,7 +128,25 @@
|
|||
return [
|
||||
`${this.prefixCls}-cell`,
|
||||
{
|
||||
[`${this.prefixCls}-hidden`]: !this.fixed && column.fixed && (column.fixed === 'left' || column.fixed === 'right')
|
||||
[`${this.prefixCls}-hidden`]: !this.fixed && column.fixed && (column.fixed === 'left' || column.fixed === 'right'),
|
||||
[`${this.prefixCls}-cell-with-selection`]: column.type === 'selection'
|
||||
}
|
||||
];
|
||||
},
|
||||
scrollBarCellClass(){
|
||||
let hasRightFixed = false;
|
||||
for(let i in this.headRows){
|
||||
for(let j in this.headRows[i]){
|
||||
if(this.headRows[i][j].fixed === 'right') {
|
||||
hasRightFixed=true;
|
||||
break;
|
||||
}
|
||||
if(hasRightFixed) break;
|
||||
}
|
||||
}
|
||||
return [
|
||||
{
|
||||
[`${this.prefixCls}-hidden`]: hasRightFixed
|
||||
}
|
||||
];
|
||||
},
|
||||
|
@ -165,6 +203,17 @@
|
|||
},
|
||||
handleFilterHide (index) {
|
||||
this.$parent.handleFilterHide(index);
|
||||
},
|
||||
// 因为表头嵌套不是深拷贝,所以没有 _ 开头的方法,在 isGroup 下用此列
|
||||
getColumn (rowIndex, index) {
|
||||
const isGroup = this.columnRows.length > 1;
|
||||
|
||||
if (isGroup) {
|
||||
const id = this.headRows[rowIndex][index].__id;
|
||||
return this.columns.filter(item => item.__id === id)[0];
|
||||
} else {
|
||||
return this.headRows[rowIndex][index];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -5,8 +5,9 @@
|
|||
<div :class="[prefixCls + '-header']" v-if="showHeader" ref="header" @mousewheel="handleMouseWheel">
|
||||
<table-head
|
||||
:prefix-cls="prefixCls"
|
||||
:styleObject="tableStyle"
|
||||
:styleObject="tableHeaderStyle"
|
||||
:columns="cloneColumns"
|
||||
:column-rows="columnRows"
|
||||
:obj-data="objData"
|
||||
:columns-width="columnsWidth"
|
||||
:data="rebuildData"></table-head>
|
||||
|
@ -24,12 +25,12 @@
|
|||
:obj-data="objData"></table-body>
|
||||
</div>
|
||||
<div
|
||||
:class="[prefixCls + '-tip']"
|
||||
:class="[prefixCls + '-tip']" :style="bodyStyle" @scroll="handleBodyScroll"
|
||||
v-show="((!!localeNoDataText && (!data || data.length === 0)) || (!!localeNoFilteredDataText && (!rebuildData || rebuildData.length === 0)))">
|
||||
<table cellspacing="0" cellpadding="0" border="0">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td :style="{ 'height': bodyStyle.height }">
|
||||
<td :style="{'height':bodyStyle.height,'width':`${this.headerWidth}px`}">
|
||||
<span v-html="localeNoDataText" v-if="!data || data.length === 0"></span>
|
||||
<span v-html="localeNoFilteredDataText" v-else></span>
|
||||
</td>
|
||||
|
@ -44,11 +45,13 @@
|
|||
:prefix-cls="prefixCls"
|
||||
:styleObject="fixedTableStyle"
|
||||
:columns="leftFixedColumns"
|
||||
:column-rows="columnRows"
|
||||
:fixed-column-rows="leftFixedColumnRows"
|
||||
:obj-data="objData"
|
||||
:columns-width="columnsWidth"
|
||||
:data="rebuildData"></table-head>
|
||||
</div>
|
||||
<div :class="[prefixCls + '-fixed-body']" :style="fixedBodyStyle" ref="fixedBody">
|
||||
<div :class="[prefixCls + '-fixed-body']" :style="fixedBodyStyle" ref="fixedBody" @mousewheel="handleFixedMousewheel" @DOMMouseScroll="handleFixedMousewheel">
|
||||
<table-body
|
||||
fixed="left"
|
||||
:drag="drag"
|
||||
|
@ -67,11 +70,13 @@
|
|||
:prefix-cls="prefixCls"
|
||||
:styleObject="fixedRightTableStyle"
|
||||
:columns="rightFixedColumns"
|
||||
:column-rows="columnRows"
|
||||
:fixed-column-rows="rightFixedColumnRows"
|
||||
:obj-data="objData"
|
||||
:columns-width="columnsWidth"
|
||||
:data="rebuildData"></table-head>
|
||||
</div>
|
||||
<div :class="[prefixCls + '-fixed-body']" :style="fixedBodyStyle" ref="fixedRightBody">
|
||||
<div :class="[prefixCls + '-fixed-body']" :style="fixedBodyStyle" ref="fixedRightBody" @mousewheel="handleFixedMousewheel" @DOMMouseScroll="handleFixedMousewheel">
|
||||
<table-body
|
||||
fixed="right"
|
||||
:drag="drag"
|
||||
|
@ -83,6 +88,7 @@
|
|||
:obj-data="objData"></table-body>
|
||||
</div>
|
||||
</div>
|
||||
<div :class="[prefixCls + '-fixed-right-header']" :style="fixedRightHeaderStyle" v-if="isRightFixed"></div>
|
||||
<div :class="[prefixCls + '-footer']" v-if="showSlotFooter" ref="footer"><slot name="footer"></slot></div>
|
||||
</div>
|
||||
<Spin fix size="large" v-if="loading">
|
||||
|
@ -100,6 +106,7 @@
|
|||
import ExportCsv from './export-csv';
|
||||
import Locale from '../../mixins/locale';
|
||||
import elementResizeDetectorMaker from 'element-resize-detector';
|
||||
import { getAllColumns, convertToRows, convertColumnOrder, getRandomStr } from './util';
|
||||
|
||||
const prefixCls = 'ivu-table';
|
||||
|
||||
|
@ -126,6 +133,9 @@
|
|||
size: {
|
||||
validator (value) {
|
||||
return oneOf(value, ['small', 'large', 'default']);
|
||||
},
|
||||
default () {
|
||||
return !this.$IVIEW || this.$IVIEW.size === '' ? 'default' : this.$IVIEW.size;
|
||||
}
|
||||
},
|
||||
width: {
|
||||
|
@ -178,6 +188,7 @@
|
|||
}
|
||||
},
|
||||
data () {
|
||||
const colsWithId = this.makeColumnsId(this.columns);
|
||||
return {
|
||||
ready: false,
|
||||
tableWidth: 0,
|
||||
|
@ -186,14 +197,21 @@
|
|||
compiledUids: [],
|
||||
objData: this.makeObjData(), // checkbox or highlight-row
|
||||
rebuildData: [], // for sort or filter
|
||||
cloneColumns: this.makeColumns(),
|
||||
cloneColumns: this.makeColumns(colsWithId),
|
||||
columnRows: this.makeColumnRows(false, colsWithId),
|
||||
leftFixedColumnRows: this.makeColumnRows('left', colsWithId),
|
||||
rightFixedColumnRows: this.makeColumnRows('right', colsWithId),
|
||||
allColumns: getAllColumns(colsWithId), // for multiple table-head, get columns that have no children
|
||||
showSlotHeader: true,
|
||||
showSlotFooter: true,
|
||||
bodyHeight: 0,
|
||||
bodyRealHeight: 0,
|
||||
scrollBarWidth: getScrollBarSize(),
|
||||
currentContext: this.context,
|
||||
cloneData: deepCopy(this.data) // when Cell has a button to delete row data, clickCurrentRow will throw an error, so clone a data
|
||||
cloneData: deepCopy(this.data), // when Cell has a button to delete row data, clickCurrentRow will throw an error, so clone a data
|
||||
showVerticalScrollBar:false,
|
||||
showHorizontalScrollBar:false,
|
||||
headerWidth:0,
|
||||
headerHeight:0,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
@ -243,7 +261,7 @@
|
|||
styles () {
|
||||
let style = {};
|
||||
if (this.height) {
|
||||
const height = (this.isLeftFixed || this.isRightFixed) ? parseInt(this.height) + this.scrollBarWidth : parseInt(this.height);
|
||||
const height = parseInt(this.height);
|
||||
style.height = `${height}px`;
|
||||
}
|
||||
if (this.width) style.width = `${this.width}px`;
|
||||
|
@ -256,17 +274,22 @@
|
|||
if (this.bodyHeight === 0) {
|
||||
width = this.tableWidth;
|
||||
} else {
|
||||
if (this.bodyHeight > this.bodyRealHeight) {
|
||||
width = this.tableWidth;
|
||||
} else {
|
||||
width = this.tableWidth - this.scrollBarWidth;
|
||||
}
|
||||
width = this.tableWidth - (this.showVerticalScrollBar?this.scrollBarWidth:0);
|
||||
}
|
||||
// const width = this.bodyHeight === 0 ? this.tableWidth : this.tableWidth - this.scrollBarWidth;
|
||||
style.width = `${width}px`;
|
||||
}
|
||||
return style;
|
||||
},
|
||||
tableHeaderStyle () {
|
||||
let style = {};
|
||||
if (this.tableWidth !== 0) {
|
||||
let width = '';
|
||||
width = this.tableWidth;
|
||||
style.width = `${width}px`;
|
||||
}
|
||||
return style;
|
||||
},
|
||||
fixedTableStyle () {
|
||||
let style = {};
|
||||
let width = 0;
|
||||
|
@ -282,15 +305,26 @@
|
|||
this.rightFixedColumns.forEach((col) => {
|
||||
if (col.fixed && col.fixed === 'right') width += col._width;
|
||||
});
|
||||
width += this.scrollBarWidth;
|
||||
//width += this.scrollBarWidth;
|
||||
style.width = `${width}px`;
|
||||
style.right = `${this.showVerticalScrollBar?this.scrollBarWidth:0}px`;
|
||||
return style;
|
||||
},
|
||||
fixedRightHeaderStyle () {
|
||||
let style = {};
|
||||
let width = 0;
|
||||
let height = this.headerHeight+1;
|
||||
if(this.showVerticalScrollBar){
|
||||
width = this.scrollBarWidth;
|
||||
}
|
||||
style.width = `${width}px`;
|
||||
style.height = `${height}px`;
|
||||
return style;
|
||||
},
|
||||
bodyStyle () {
|
||||
let style = {};
|
||||
if (this.bodyHeight !== 0) {
|
||||
// add a height to resolve scroll bug when browser has a scrollBar in fixed type and height prop
|
||||
const height = (this.isLeftFixed || this.isRightFixed) ? this.bodyHeight + this.scrollBarWidth : this.bodyHeight;
|
||||
const height = this.bodyHeight;
|
||||
style.height = `${height}px`;
|
||||
}
|
||||
return style;
|
||||
|
@ -298,41 +332,16 @@
|
|||
fixedBodyStyle () {
|
||||
let style = {};
|
||||
if (this.bodyHeight !== 0) {
|
||||
let height = this.bodyHeight + this.scrollBarWidth - 1;
|
||||
|
||||
// #2102 里,如果 Table 没有设置 width,而是集成父级的 width,固定列也应该不包含滚动条高度,所以这里直接计算表格宽度
|
||||
const tableWidth = parseInt(getStyle(this.$el, 'width')) - 1;
|
||||
if ((this.width && this.width < this.tableWidth) || tableWidth < this.tableWidth){
|
||||
height = this.bodyHeight;
|
||||
}
|
||||
// style.height = this.scrollBarWidth > 0 ? `${this.bodyHeight}px` : `${this.bodyHeight - 1}px`;
|
||||
style.height = this.scrollBarWidth > 0 ? `${height}px` : `${height - 1}px`;
|
||||
let height = this.bodyHeight - (this.showHorizontalScrollBar?this.scrollBarWidth:0);
|
||||
style.height = this.showHorizontalScrollBar ? `${height}px` : `${height - 1}px`;
|
||||
}
|
||||
return style;
|
||||
},
|
||||
leftFixedColumns () {
|
||||
let left = [];
|
||||
let other = [];
|
||||
this.cloneColumns.forEach((col) => {
|
||||
if (col.fixed && col.fixed === 'left') {
|
||||
left.push(col);
|
||||
} else {
|
||||
other.push(col);
|
||||
}
|
||||
});
|
||||
return left.concat(other);
|
||||
return convertColumnOrder(this.cloneColumns, 'left');
|
||||
},
|
||||
rightFixedColumns () {
|
||||
let right = [];
|
||||
let other = [];
|
||||
this.cloneColumns.forEach((col) => {
|
||||
if (col.fixed && col.fixed === 'right') {
|
||||
right.push(col);
|
||||
} else {
|
||||
other.push(col);
|
||||
}
|
||||
});
|
||||
return right.concat(other);
|
||||
return convertColumnOrder(this.cloneColumns, 'right');
|
||||
},
|
||||
isLeftFixed () {
|
||||
return this.columns.some(col => col.fixed && col.fixed === 'left');
|
||||
|
@ -346,46 +355,111 @@
|
|||
return this.rowClassName(this.data[index], index);
|
||||
},
|
||||
handleResize () {
|
||||
this.$nextTick(() => {
|
||||
const allWidth = !this.columns.some(cell => !cell.width); // each column set a width
|
||||
if (allWidth) {
|
||||
this.tableWidth = this.columns.map(cell => cell.width).reduce((a, b) => a + b, 0);
|
||||
} else {
|
||||
this.tableWidth = parseInt(getStyle(this.$el, 'width')) - 1;
|
||||
//let tableWidth = parseInt(getStyle(this.$el, 'width')) - 1;
|
||||
let tableWidth = this.$el.offsetWidth - 1;
|
||||
let columnsWidth = {};
|
||||
let sumMinWidth = 0;
|
||||
let hasWidthColumns = [];
|
||||
let noWidthColumns = [];
|
||||
let maxWidthColumns = [];
|
||||
let noMaxWidthColumns = [];
|
||||
this.cloneColumns.forEach((col) => {
|
||||
if (col.width) {
|
||||
hasWidthColumns.push(col);
|
||||
}
|
||||
this.columnsWidth = {};
|
||||
if (!this.$refs.tbody) return;
|
||||
this.$nextTick(() => {
|
||||
let columnsWidth = {};
|
||||
let autoWidthIndex = -1;
|
||||
if (allWidth) autoWidthIndex = this.cloneColumns.findIndex(cell => !cell.width);//todo 这行可能有问题
|
||||
|
||||
if (this.data.length) {
|
||||
const $tr = this.$refs.tbody.$el.querySelectorAll('tbody tr');
|
||||
if ($tr.length === 0) return;
|
||||
const $td = $tr[0].children;
|
||||
|
||||
for (let i = 0; i < $td.length; i++) { // can not use forEach in Firefox
|
||||
const column = this.cloneColumns[i];
|
||||
|
||||
let width = parseInt(getStyle($td[i], 'width'));
|
||||
if (i === autoWidthIndex) {
|
||||
width = parseInt(getStyle($td[i], 'width')) - 1;
|
||||
}
|
||||
if (column.width) width = column.width;
|
||||
|
||||
this.cloneColumns[i]._width = width;
|
||||
|
||||
columnsWidth[column._index] = {
|
||||
width: width
|
||||
};
|
||||
}
|
||||
this.columnsWidth = columnsWidth;
|
||||
else{
|
||||
noWidthColumns.push(col);
|
||||
if (col.minWidth) {
|
||||
sumMinWidth += col.minWidth;
|
||||
}
|
||||
});
|
||||
// get table real height,for fixed when set height prop,but height < table's height,show scrollBarWidth
|
||||
this.bodyRealHeight = parseInt(getStyle(this.$refs.tbody.$el, 'height'));
|
||||
if (col.maxWidth) {
|
||||
maxWidthColumns.push(col);
|
||||
}
|
||||
else {
|
||||
noMaxWidthColumns.push(col);
|
||||
}
|
||||
}
|
||||
col._width = null;
|
||||
});
|
||||
|
||||
|
||||
let unUsableWidth = hasWidthColumns.map(cell => cell.width).reduce((a, b) => a + b, 0);
|
||||
let usableWidth = tableWidth - unUsableWidth - sumMinWidth - (this.showVerticalScrollBar?this.scrollBarWidth:0) - 1;
|
||||
let usableLength = noWidthColumns.length;
|
||||
let columnWidth = 0;
|
||||
if(usableWidth > 0 && usableLength > 0){
|
||||
columnWidth = parseInt(usableWidth / usableLength);
|
||||
}
|
||||
|
||||
|
||||
for (let i = 0; i < this.cloneColumns.length; i++) {
|
||||
const column = this.cloneColumns[i];
|
||||
let width = columnWidth + (column.minWidth?column.minWidth:0);
|
||||
if(column.width){
|
||||
width = column.width;
|
||||
}
|
||||
else{
|
||||
if (column._width) {
|
||||
width = column._width;
|
||||
}
|
||||
else {
|
||||
if (column.minWidth > width){
|
||||
width = column.minWidth;
|
||||
}
|
||||
else if (column.maxWidth < width){
|
||||
width = column.maxWidth;
|
||||
}
|
||||
|
||||
if (usableWidth>0) {
|
||||
usableWidth -= width - (column.minWidth?column.minWidth:0);
|
||||
usableLength--;
|
||||
if (usableLength > 0) {
|
||||
columnWidth = parseInt(usableWidth / usableLength);
|
||||
}
|
||||
else {
|
||||
columnWidth = 0;
|
||||
}
|
||||
}
|
||||
else{
|
||||
columnWidth = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
column._width = width;
|
||||
|
||||
columnsWidth[column._index] = {
|
||||
width: width
|
||||
};
|
||||
|
||||
}
|
||||
if(usableWidth>0) {
|
||||
usableLength = noMaxWidthColumns.length;
|
||||
columnWidth = parseInt(usableWidth / usableLength);
|
||||
for (let i = 0; i < noMaxWidthColumns.length; i++) {
|
||||
const column = noMaxWidthColumns[i];
|
||||
let width = column._width + columnWidth;
|
||||
if (usableLength > 1) {
|
||||
usableLength--;
|
||||
usableWidth -= columnWidth;
|
||||
columnWidth = parseInt(usableWidth / usableLength);
|
||||
}
|
||||
else {
|
||||
columnWidth = 0;
|
||||
}
|
||||
|
||||
column._width = width;
|
||||
|
||||
columnsWidth[column._index] = {
|
||||
width: width
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
this.tableWidth = this.cloneColumns.map(cell => cell._width).reduce((a, b) => a + b, 0) + (this.showVerticalScrollBar?this.scrollBarWidth:0) + 1;
|
||||
this.columnsWidth = columnsWidth;
|
||||
this.fixedHeader();
|
||||
},
|
||||
handleMouseIn (_index) {
|
||||
if (this.disabledHover) return;
|
||||
|
@ -439,6 +513,7 @@
|
|||
for (let i in this.objData) {
|
||||
if (parseInt(i) === _index) {
|
||||
data = this.objData[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
const status = !data._isChecked;
|
||||
|
@ -455,11 +530,16 @@
|
|||
for (let i in this.objData) {
|
||||
if (parseInt(i) === _index) {
|
||||
data = this.objData[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
const status = !data._isExpanded;
|
||||
this.objData[_index]._isExpanded = status;
|
||||
this.$emit('on-expand', JSON.parse(JSON.stringify(this.cloneData[_index])), status);
|
||||
|
||||
if(this.height){
|
||||
this.$nextTick(()=>this.fixedBody());
|
||||
}
|
||||
},
|
||||
selectAll (status) {
|
||||
// this.rebuildData.forEach((data) => {
|
||||
|
@ -480,9 +560,12 @@
|
|||
const selection = this.getSelection();
|
||||
if (status) {
|
||||
this.$emit('on-select-all', selection);
|
||||
} else {
|
||||
this.$emit('on-select-all-cancel', selection);
|
||||
}
|
||||
this.$emit('on-selection-change', selection);
|
||||
},
|
||||
|
||||
fixedHeader () {
|
||||
if (this.height) {
|
||||
this.$nextTick(() => {
|
||||
|
@ -490,11 +573,45 @@
|
|||
const headerHeight = parseInt(getStyle(this.$refs.header, 'height')) || 0;
|
||||
const footerHeight = parseInt(getStyle(this.$refs.footer, 'height')) || 0;
|
||||
this.bodyHeight = this.height - titleHeight - headerHeight - footerHeight;
|
||||
this.$nextTick(()=>this.fixedBody());
|
||||
});
|
||||
} else {
|
||||
this.bodyHeight = 0;
|
||||
this.$nextTick(()=>this.fixedBody());
|
||||
}
|
||||
},
|
||||
fixedBody (){
|
||||
if (this.$refs.header) {
|
||||
this.headerWidth = this.$refs.header.children[0].offsetWidth;
|
||||
this.headerHeight = this.$refs.header.children[0].offsetHeight;
|
||||
//this.showHorizontalScrollBar = this.headerWidth>this.$refs.header.offsetWidth;
|
||||
}
|
||||
|
||||
if (!this.$refs.tbody || !this.data || this.data.length === 0) {
|
||||
this.showVerticalScrollBar = false;
|
||||
}
|
||||
else{
|
||||
let bodyContentEl = this.$refs.tbody.$el;
|
||||
let bodyEl = bodyContentEl.parentElement;
|
||||
let bodyContentHeight = bodyContentEl.offsetHeight;
|
||||
let bodyHeight = bodyEl.offsetHeight;
|
||||
|
||||
this.showHorizontalScrollBar = bodyEl.offsetWidth < bodyContentEl.offsetWidth + (this.showVerticalScrollBar?this.scrollBarWidth:0);
|
||||
this.showVerticalScrollBar = this.bodyHeight? bodyHeight - (this.showHorizontalScrollBar?this.scrollBarWidth:0) < bodyContentHeight : false;
|
||||
|
||||
if(this.showVerticalScrollBar){
|
||||
bodyEl.classList.add(this.prefixCls +'-overflowY');
|
||||
}else{
|
||||
bodyEl.classList.remove(this.prefixCls +'-overflowY');
|
||||
}
|
||||
if(this.showHorizontalScrollBar){
|
||||
bodyEl.classList.add(this.prefixCls +'-overflowX');
|
||||
}else{
|
||||
bodyEl.classList.remove(this.prefixCls +'-overflowX');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
hideColumnFilter () {
|
||||
this.cloneColumns.forEach((col) => col._filterVisible = false);
|
||||
},
|
||||
|
@ -504,6 +621,41 @@
|
|||
if (this.isRightFixed) this.$refs.fixedRightBody.scrollTop = event.target.scrollTop;
|
||||
this.hideColumnFilter();
|
||||
},
|
||||
handleFixedMousewheel(event) {
|
||||
let deltaY = event.deltaY;
|
||||
if(!deltaY && event.detail){
|
||||
deltaY = event.detail * 40;
|
||||
}
|
||||
if(!deltaY && event.wheelDeltaY){
|
||||
deltaY = -event.wheelDeltaY;
|
||||
}
|
||||
if(!deltaY && event.wheelDelta){
|
||||
deltaY = -event.wheelDelta;
|
||||
}
|
||||
if(!deltaY) return;
|
||||
const body = this.$refs.body;
|
||||
const currentScrollTop = body.scrollTop;
|
||||
if (deltaY < 0 && currentScrollTop !== 0) {
|
||||
event.preventDefault();
|
||||
}
|
||||
if (deltaY > 0 && body.scrollHeight - body.clientHeight > currentScrollTop) {
|
||||
event.preventDefault();
|
||||
}
|
||||
//body.scrollTop += deltaY;
|
||||
let step = 0;
|
||||
let timeId = setInterval(()=>{
|
||||
step += 5;
|
||||
if(deltaY>0){
|
||||
body.scrollTop += 2;
|
||||
}
|
||||
else{
|
||||
body.scrollTop -= 2;
|
||||
}
|
||||
if(step >= Math.abs(deltaY)){
|
||||
clearInterval(timeId);
|
||||
}
|
||||
}, 5);
|
||||
},
|
||||
handleMouseWheel (event) {
|
||||
const deltaX = event.deltaX;
|
||||
const $body = this.$refs.body;
|
||||
|
@ -544,7 +696,7 @@
|
|||
this.cloneColumns[index]._sortType = type;
|
||||
|
||||
this.$emit('on-sort-change', {
|
||||
column: JSON.parse(JSON.stringify(this.columns[this.cloneColumns[index]._index])),
|
||||
column: JSON.parse(JSON.stringify(this.allColumns[this.cloneColumns[index]._index])),
|
||||
key: key,
|
||||
order: type
|
||||
});
|
||||
|
@ -680,8 +832,17 @@
|
|||
});
|
||||
return data;
|
||||
},
|
||||
makeColumns () {
|
||||
let columns = deepCopy(this.columns);
|
||||
// 修改列,设置一个隐藏的 id,便于后面的多级表头寻找对应的列,否则找不到
|
||||
makeColumnsId (columns) {
|
||||
return columns.map(item => {
|
||||
if ('children' in item) item.children = this.makeColumnsId(item.children);
|
||||
item.__id = getRandomStr(6);
|
||||
return item;
|
||||
});
|
||||
},
|
||||
makeColumns (cols) {
|
||||
// 在 data 时,this.allColumns 暂时为 undefined
|
||||
let columns = deepCopy(getAllColumns(cols));
|
||||
let left = [];
|
||||
let right = [];
|
||||
let center = [];
|
||||
|
@ -719,6 +880,10 @@
|
|||
});
|
||||
return left.concat(center).concat(right);
|
||||
},
|
||||
// create a multiple table-head
|
||||
makeColumnRows (fixedType, cols) {
|
||||
return convertToRows(cols, fixedType);
|
||||
},
|
||||
exportCsv (params) {
|
||||
if (params.filename) {
|
||||
if (params.filename.indexOf('.csv') === -1) {
|
||||
|
@ -734,7 +899,7 @@
|
|||
columns = params.columns;
|
||||
datas = params.data;
|
||||
} else {
|
||||
columns = this.columns;
|
||||
columns = this.allColumns;
|
||||
if (!('original' in params)) params.original = true;
|
||||
datas = params.original ? this.data : this.rebuildData;
|
||||
}
|
||||
|
@ -758,7 +923,6 @@
|
|||
},
|
||||
mounted () {
|
||||
this.handleResize();
|
||||
this.fixedHeader();
|
||||
this.$nextTick(() => this.ready = true);
|
||||
|
||||
on(window, 'resize', this.handleResize);
|
||||
|
@ -768,7 +932,6 @@
|
|||
this.$on('on-visible-change', (val) => {
|
||||
if (val) {
|
||||
this.handleResize();
|
||||
this.fixedHeader();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
@ -796,14 +959,26 @@
|
|||
columns: {
|
||||
handler () {
|
||||
// todo 这里有性能问题,可能是左右固定计算属性影响的
|
||||
this.cloneColumns = this.makeColumns();
|
||||
const colsWithId = this.makeColumnsId(this.columns);
|
||||
this.allColumns = getAllColumns(colsWithId);
|
||||
this.cloneColumns = this.makeColumns(colsWithId);
|
||||
|
||||
this.columnRows = this.makeColumnRows(false, colsWithId);
|
||||
this.leftFixedColumnRows = this.makeColumnRows('left', colsWithId);
|
||||
this.rightFixedColumnRows = this.makeColumnRows('right', colsWithId);
|
||||
this.rebuildData = this.makeDataWithSortAndFilter();
|
||||
this.handleResize();
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
height () {
|
||||
this.fixedHeader();
|
||||
this.handleResize();
|
||||
},
|
||||
showHorizontalScrollBar () {
|
||||
this.handleResize();
|
||||
},
|
||||
showVerticalScrollBar () {
|
||||
this.handleResize();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
93
src/components/table/util.js
Normal file
93
src/components/table/util.js
Normal file
|
@ -0,0 +1,93 @@
|
|||
import { deepCopy } from '../../utils/assist';
|
||||
|
||||
const convertColumnOrder = (columns, fixedType) => {
|
||||
let list = [];
|
||||
let other = [];
|
||||
columns.forEach((col) => {
|
||||
if (col.fixed && col.fixed === fixedType) {
|
||||
list.push(col);
|
||||
} else {
|
||||
other.push(col);
|
||||
}
|
||||
});
|
||||
return list.concat(other);
|
||||
};
|
||||
|
||||
export {convertColumnOrder};
|
||||
|
||||
// set forTableHead to true when convertToRows, false in normal cases like table.vue
|
||||
const getAllColumns = (cols, forTableHead = false) => {
|
||||
const columns = deepCopy(cols);
|
||||
const result = [];
|
||||
columns.forEach((column) => {
|
||||
if (column.children) {
|
||||
if (forTableHead) result.push(column);
|
||||
result.push.apply(result, getAllColumns(column.children, forTableHead));
|
||||
} else {
|
||||
result.push(column);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
export {getAllColumns};
|
||||
|
||||
const convertToRows = (columns, fixedType = false) => {
|
||||
const originColumns = fixedType ? fixedType === 'left' ? deepCopy(convertColumnOrder(columns, 'left')) : deepCopy(convertColumnOrder(columns, 'right')) : deepCopy(columns);
|
||||
let maxLevel = 1;
|
||||
const traverse = (column, parent) => {
|
||||
if (parent) {
|
||||
column.level = parent.level + 1;
|
||||
if (maxLevel < column.level) {
|
||||
maxLevel = column.level;
|
||||
}
|
||||
}
|
||||
if (column.children) {
|
||||
let colSpan = 0;
|
||||
column.children.forEach((subColumn) => {
|
||||
traverse(subColumn, column);
|
||||
colSpan += subColumn.colSpan;
|
||||
});
|
||||
column.colSpan = colSpan;
|
||||
} else {
|
||||
column.colSpan = 1;
|
||||
}
|
||||
};
|
||||
|
||||
originColumns.forEach((column) => {
|
||||
column.level = 1;
|
||||
traverse(column);
|
||||
});
|
||||
|
||||
const rows = [];
|
||||
for (let i = 0; i < maxLevel; i++) {
|
||||
rows.push([]);
|
||||
}
|
||||
|
||||
const allColumns = getAllColumns(originColumns, true);
|
||||
|
||||
allColumns.forEach((column) => {
|
||||
if (!column.children) {
|
||||
column.rowSpan = maxLevel - column.level + 1;
|
||||
} else {
|
||||
column.rowSpan = 1;
|
||||
}
|
||||
rows[column.level - 1].push(column);
|
||||
});
|
||||
|
||||
return rows;
|
||||
};
|
||||
|
||||
export {convertToRows};
|
||||
|
||||
const getRandomStr = function (len = 32) {
|
||||
const $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
|
||||
const maxPos = $chars.length;
|
||||
let str = '';
|
||||
for (let i = 0; i < len; i++) {
|
||||
str += $chars.charAt(Math.floor(Math.random() * maxPos));
|
||||
}
|
||||
return str;
|
||||
};
|
||||
|
||||
export {getRandomStr};
|
Loading…
Add table
Add a link
Reference in a new issue