chushihua
This commit is contained in:
+28
@@ -0,0 +1,28 @@
|
||||
import Vue from 'vue';
|
||||
var dropdowns = [];
|
||||
|
||||
!Vue.prototype.$isServer && document.addEventListener('click', function(event) {
|
||||
dropdowns.forEach(function(dropdown) {
|
||||
var target = event.target;
|
||||
if (!dropdown || !dropdown.$el) return;
|
||||
if (target === dropdown.$el || dropdown.$el.contains(target)) {
|
||||
return;
|
||||
}
|
||||
dropdown.handleOutsideClick && dropdown.handleOutsideClick(event);
|
||||
});
|
||||
});
|
||||
|
||||
export default {
|
||||
open(instance) {
|
||||
if (instance) {
|
||||
dropdowns.push(instance);
|
||||
}
|
||||
},
|
||||
|
||||
close(instance) {
|
||||
var index = dropdowns.indexOf(instance);
|
||||
if (index !== -1) {
|
||||
dropdowns.splice(instance, 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
+203
@@ -0,0 +1,203 @@
|
||||
<template>
|
||||
<transition name="el-zoom-in-top">
|
||||
<div
|
||||
class="el-table-filter"
|
||||
v-if="multiple"
|
||||
v-clickoutside="handleOutsideClick"
|
||||
v-show="showPopper">
|
||||
<div class="el-table-filter__content">
|
||||
<el-scrollbar wrap-class="el-table-filter__wrap">
|
||||
<el-checkbox-group class="el-table-filter__checkbox-group" v-model="filteredValue">
|
||||
<el-checkbox
|
||||
v-for="filter in filters"
|
||||
:key="filter.value"
|
||||
:label="filter.value">{{ filter.text }}</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
<div class="el-table-filter__bottom">
|
||||
<button @click="handleConfirm"
|
||||
:class="{ 'is-disabled': filteredValue.length === 0 }"
|
||||
:disabled="filteredValue.length === 0">{{ t('el.table.confirmFilter') }}</button>
|
||||
<button @click="handleReset">{{ t('el.table.resetFilter') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="el-table-filter"
|
||||
v-else
|
||||
v-clickoutside="handleOutsideClick"
|
||||
v-show="showPopper">
|
||||
<ul class="el-table-filter__list">
|
||||
<li class="el-table-filter__list-item"
|
||||
:class="{ 'is-active': filterValue === undefined || filterValue === null }"
|
||||
@click="handleSelect(null)">{{ t('el.table.clearFilter') }}</li>
|
||||
<li class="el-table-filter__list-item"
|
||||
v-for="filter in filters"
|
||||
:label="filter.value"
|
||||
:key="filter.value"
|
||||
:class="{ 'is-active': isActive(filter) }"
|
||||
@click="handleSelect(filter.value)" >{{ filter.text }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script type="text/babel">
|
||||
import Popper from 'element-ui/src/utils/vue-popper';
|
||||
import { PopupManager } from 'element-ui/src/utils/popup';
|
||||
import Locale from 'element-ui/src/mixins/locale';
|
||||
import Clickoutside from 'element-ui/src/utils/clickoutside';
|
||||
import Dropdown from './dropdown';
|
||||
import ElCheckbox from 'element-ui/packages/checkbox';
|
||||
import ElCheckboxGroup from 'element-ui/packages/checkbox-group';
|
||||
|
||||
export default {
|
||||
name: 'ElTableFilterPanel',
|
||||
|
||||
mixins: [Popper, Locale],
|
||||
|
||||
directives: {
|
||||
Clickoutside
|
||||
},
|
||||
|
||||
components: {
|
||||
ElCheckbox,
|
||||
ElCheckboxGroup
|
||||
},
|
||||
|
||||
props: {
|
||||
placement: {
|
||||
type: String,
|
||||
default: 'bottom-end'
|
||||
}
|
||||
},
|
||||
|
||||
customRender(h) {
|
||||
return (<div class="el-table-filter">
|
||||
<div class="el-table-filter__content">
|
||||
</div>
|
||||
<div class="el-table-filter__bottom">
|
||||
<button on-click={ this.handleConfirm }>{ this.t('el.table.confirmFilter') }</button>
|
||||
<button on-click={ this.handleReset }>{ this.t('el.table.resetFilter') }</button>
|
||||
</div>
|
||||
</div>);
|
||||
},
|
||||
|
||||
methods: {
|
||||
isActive(filter) {
|
||||
return filter.value === this.filterValue;
|
||||
},
|
||||
|
||||
handleOutsideClick() {
|
||||
setTimeout(() => {
|
||||
this.showPopper = false;
|
||||
}, 16);
|
||||
},
|
||||
|
||||
handleConfirm() {
|
||||
this.confirmFilter(this.filteredValue);
|
||||
this.handleOutsideClick();
|
||||
},
|
||||
|
||||
handleReset() {
|
||||
this.filteredValue = [];
|
||||
this.confirmFilter(this.filteredValue);
|
||||
this.handleOutsideClick();
|
||||
},
|
||||
|
||||
handleSelect(filterValue) {
|
||||
this.filterValue = filterValue;
|
||||
|
||||
if ((typeof filterValue !== 'undefined') && (filterValue !== null)) {
|
||||
this.confirmFilter(this.filteredValue);
|
||||
} else {
|
||||
this.confirmFilter([]);
|
||||
}
|
||||
|
||||
this.handleOutsideClick();
|
||||
},
|
||||
|
||||
confirmFilter(filteredValue) {
|
||||
this.table.store.commit('filterChange', {
|
||||
column: this.column,
|
||||
values: filteredValue
|
||||
});
|
||||
this.table.store.updateAllSelected();
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
table: null,
|
||||
cell: null,
|
||||
column: null
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
filters() {
|
||||
return this.column && this.column.filters;
|
||||
},
|
||||
|
||||
filterValue: {
|
||||
get() {
|
||||
return (this.column.filteredValue || [])[0];
|
||||
},
|
||||
set(value) {
|
||||
if (this.filteredValue) {
|
||||
if ((typeof value !== 'undefined') && (value !== null)) {
|
||||
this.filteredValue.splice(0, 1, value);
|
||||
} else {
|
||||
this.filteredValue.splice(0, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
filteredValue: {
|
||||
get() {
|
||||
if (this.column) {
|
||||
return this.column.filteredValue || [];
|
||||
}
|
||||
return [];
|
||||
},
|
||||
set(value) {
|
||||
if (this.column) {
|
||||
this.column.filteredValue = value;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
multiple() {
|
||||
if (this.column) {
|
||||
return this.column.filterMultiple;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.popperElm = this.$el;
|
||||
this.referenceElm = this.cell;
|
||||
this.table.bodyWrapper.addEventListener('scroll', () => {
|
||||
this.updatePopper();
|
||||
});
|
||||
|
||||
this.$watch('showPopper', (value) => {
|
||||
if (this.column) this.column.filterOpened = value;
|
||||
if (value) {
|
||||
Dropdown.open(this);
|
||||
} else {
|
||||
Dropdown.close(this);
|
||||
}
|
||||
});
|
||||
},
|
||||
watch: {
|
||||
showPopper(val) {
|
||||
if (val === true && parseInt(this.popperJS._popper.style.zIndex, 10) < PopupManager.zIndex) {
|
||||
this.popperJS._popper.style.zIndex = PopupManager.nextZIndex();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
export default {
|
||||
created() {
|
||||
this.tableLayout.addObserver(this);
|
||||
},
|
||||
|
||||
destroyed() {
|
||||
this.tableLayout.removeObserver(this);
|
||||
},
|
||||
|
||||
computed: {
|
||||
tableLayout() {
|
||||
let layout = this.layout;
|
||||
if (!layout && this.table) {
|
||||
layout = this.table.layout;
|
||||
}
|
||||
if (!layout) {
|
||||
throw new Error('Can not find table layout.');
|
||||
}
|
||||
return layout;
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.onColumnsChange(this.tableLayout);
|
||||
this.onScrollableChange(this.tableLayout);
|
||||
},
|
||||
|
||||
updated() {
|
||||
if (this.__updated__) return;
|
||||
this.onColumnsChange(this.tableLayout);
|
||||
this.onScrollableChange(this.tableLayout);
|
||||
this.__updated__ = true;
|
||||
},
|
||||
|
||||
methods: {
|
||||
onColumnsChange() {
|
||||
const cols = this.$el.querySelectorAll('colgroup > col');
|
||||
if (!cols.length) return;
|
||||
const flattenColumns = this.tableLayout.getFlattenColumns();
|
||||
const columnsMap = {};
|
||||
flattenColumns.forEach((column) => {
|
||||
columnsMap[column.id] = column;
|
||||
});
|
||||
for (let i = 0, j = cols.length; i < j; i++) {
|
||||
const col = cols[i];
|
||||
const name = col.getAttribute('name');
|
||||
const column = columnsMap[name];
|
||||
if (column) {
|
||||
col.setAttribute('width', column.realWidth || column.width);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onScrollableChange(layout) {
|
||||
const cols = this.$el.querySelectorAll('colgroup > col[name=gutter]');
|
||||
for (let i = 0, j = cols.length; i < j; i++) {
|
||||
const col = cols[i];
|
||||
col.setAttribute('width', layout.scrollY ? layout.gutterWidth : '0');
|
||||
}
|
||||
const ths = this.$el.querySelectorAll('th.gutter');
|
||||
for (let i = 0, j = ths.length; i < j; i++) {
|
||||
const th = ths[i];
|
||||
th.style.width = layout.scrollY ? layout.gutterWidth + 'px' : '0';
|
||||
th.style.display = layout.scrollY ? '' : 'none';
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
+360
@@ -0,0 +1,360 @@
|
||||
import { getCell, getColumnByCell, getRowIdentity } from './util';
|
||||
import { getStyle, hasClass } from 'element-ui/src/utils/dom';
|
||||
import ElCheckbox from 'element-ui/packages/checkbox';
|
||||
import ElTooltip from 'element-ui/packages/tooltip';
|
||||
import debounce from 'throttle-debounce/debounce';
|
||||
import LayoutObserver from './layout-observer';
|
||||
|
||||
export default {
|
||||
name: 'ElTableBody',
|
||||
|
||||
mixins: [LayoutObserver],
|
||||
|
||||
components: {
|
||||
ElCheckbox,
|
||||
ElTooltip
|
||||
},
|
||||
|
||||
props: {
|
||||
store: {
|
||||
required: true
|
||||
},
|
||||
stripe: Boolean,
|
||||
context: {},
|
||||
rowClassName: [String, Function],
|
||||
rowStyle: [Object, Function],
|
||||
fixed: String,
|
||||
highlight: Boolean
|
||||
},
|
||||
|
||||
render(h) {
|
||||
const columnsHidden = this.columns.map((column, index) => this.isColumnHidden(index));
|
||||
return (
|
||||
<table
|
||||
class="el-table__body"
|
||||
cellspacing="0"
|
||||
cellpadding="0"
|
||||
border="0">
|
||||
<colgroup>
|
||||
{
|
||||
this._l(this.columns, column => <col name={ column.id } />)
|
||||
}
|
||||
</colgroup>
|
||||
<tbody>
|
||||
{
|
||||
this._l(this.data, (row, $index) =>
|
||||
[<tr
|
||||
style={ this.rowStyle ? this.getRowStyle(row, $index) : null }
|
||||
key={ this.table.rowKey ? this.getKeyOfRow(row, $index) : $index }
|
||||
on-dblclick={ ($event) => this.handleDoubleClick($event, row) }
|
||||
on-click={ ($event) => this.handleClick($event, row) }
|
||||
on-contextmenu={ ($event) => this.handleContextMenu($event, row) }
|
||||
on-mouseenter={ _ => this.handleMouseEnter($index) }
|
||||
on-mouseleave={ _ => this.handleMouseLeave() }
|
||||
class={ [this.getRowClass(row, $index)] }>
|
||||
{
|
||||
this._l(this.columns, (column, cellIndex) => {
|
||||
const { rowspan, colspan } = this.getSpan(row, column, $index, cellIndex);
|
||||
if (!rowspan || !colspan) {
|
||||
return '';
|
||||
} else {
|
||||
return (
|
||||
<td
|
||||
style={ this.getCellStyle($index, cellIndex, row, column) }
|
||||
class={ this.getCellClass($index, cellIndex, row, column) }
|
||||
rowspan={ rowspan }
|
||||
colspan={ colspan }
|
||||
on-mouseenter={ ($event) => this.handleCellMouseEnter($event, row) }
|
||||
on-mouseleave={ this.handleCellMouseLeave }>
|
||||
{
|
||||
column.renderCell.call(
|
||||
this._renderProxy,
|
||||
h,
|
||||
{
|
||||
row,
|
||||
column,
|
||||
$index,
|
||||
store: this.store,
|
||||
_self: this.context || this.table.$vnode.context
|
||||
},
|
||||
columnsHidden[cellIndex]
|
||||
)
|
||||
}
|
||||
</td>
|
||||
);
|
||||
}
|
||||
})
|
||||
}
|
||||
</tr>,
|
||||
this.store.isRowExpanded(row)
|
||||
? (<tr>
|
||||
<td colspan={ this.columns.length } class="el-table__expanded-cell">
|
||||
{ this.table.renderExpanded ? this.table.renderExpanded(h, { row, $index, store: this.store }) : ''}
|
||||
</td>
|
||||
</tr>)
|
||||
: ''
|
||||
]
|
||||
).concat(
|
||||
<el-tooltip effect={ this.table.tooltipEffect } placement="top" ref="tooltip" content={ this.tooltipContent }></el-tooltip>
|
||||
)
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
},
|
||||
|
||||
computed: {
|
||||
table() {
|
||||
return this.$parent;
|
||||
},
|
||||
|
||||
data() {
|
||||
return this.store.states.data;
|
||||
},
|
||||
|
||||
columnsCount() {
|
||||
return this.store.states.columns.length;
|
||||
},
|
||||
|
||||
leftFixedLeafCount() {
|
||||
return this.store.states.fixedLeafColumnsLength;
|
||||
},
|
||||
|
||||
rightFixedLeafCount() {
|
||||
return this.store.states.rightFixedLeafColumnsLength;
|
||||
},
|
||||
|
||||
leftFixedCount() {
|
||||
return this.store.states.fixedColumns.length;
|
||||
},
|
||||
|
||||
rightFixedCount() {
|
||||
return this.store.states.rightFixedColumns.length;
|
||||
},
|
||||
|
||||
columns() {
|
||||
return this.store.states.columns;
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
tooltipContent: ''
|
||||
};
|
||||
},
|
||||
|
||||
created() {
|
||||
this.activateTooltip = debounce(50, tooltip => tooltip.handleShowPopper());
|
||||
},
|
||||
|
||||
methods: {
|
||||
getKeyOfRow(row, index) {
|
||||
const rowKey = this.table.rowKey;
|
||||
if (rowKey) {
|
||||
return getRowIdentity(row, rowKey);
|
||||
}
|
||||
return index;
|
||||
},
|
||||
|
||||
isColumnHidden(index) {
|
||||
if (this.fixed === true || this.fixed === 'left') {
|
||||
return index >= this.leftFixedLeafCount;
|
||||
} else if (this.fixed === 'right') {
|
||||
return index < this.columnsCount - this.rightFixedLeafCount;
|
||||
} else {
|
||||
return (index < this.leftFixedLeafCount) || (index >= this.columnsCount - this.rightFixedLeafCount);
|
||||
}
|
||||
},
|
||||
|
||||
getSpan(row, column, rowIndex, columnIndex) {
|
||||
let rowspan = 1;
|
||||
let colspan = 1;
|
||||
|
||||
const fn = this.table.spanMethod;
|
||||
if (typeof fn === 'function') {
|
||||
const result = fn({
|
||||
row,
|
||||
column,
|
||||
rowIndex,
|
||||
columnIndex
|
||||
});
|
||||
|
||||
if (Array.isArray(result)) {
|
||||
rowspan = result[0];
|
||||
colspan = result[1];
|
||||
} else if (typeof result === 'object') {
|
||||
rowspan = result.rowspan;
|
||||
colspan = result.colspan;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
rowspan,
|
||||
colspan
|
||||
};
|
||||
},
|
||||
|
||||
getRowStyle(row, rowIndex) {
|
||||
const rowStyle = this.table.rowStyle;
|
||||
if (typeof rowStyle === 'function') {
|
||||
return rowStyle.call(null, {
|
||||
row,
|
||||
rowIndex
|
||||
});
|
||||
}
|
||||
return rowStyle;
|
||||
},
|
||||
|
||||
getRowClass(row, rowIndex) {
|
||||
const classes = ['el-table__row'];
|
||||
if (this.table.highlightCurrentRow && row === this.store.states.currentRow) {
|
||||
classes.push('current-row');
|
||||
}
|
||||
|
||||
if (rowIndex === this.store.states.hoverRow) {
|
||||
classes.push('hover-row');
|
||||
}
|
||||
|
||||
if (this.stripe && rowIndex % 2 === 1) {
|
||||
classes.push('el-table__row--striped');
|
||||
}
|
||||
const rowClassName = this.table.rowClassName;
|
||||
if (typeof rowClassName === 'string') {
|
||||
classes.push(rowClassName);
|
||||
} else if (typeof rowClassName === 'function') {
|
||||
classes.push(rowClassName.call(null, {
|
||||
row,
|
||||
rowIndex
|
||||
}));
|
||||
}
|
||||
|
||||
if (this.store.states.expandRows.indexOf(row) > -1) {
|
||||
classes.push('expanded');
|
||||
}
|
||||
|
||||
return classes.join(' ');
|
||||
},
|
||||
|
||||
getCellStyle(rowIndex, columnIndex, row, column) {
|
||||
const cellStyle = this.table.cellStyle;
|
||||
if (typeof cellStyle === 'function') {
|
||||
return cellStyle.call(null, {
|
||||
rowIndex,
|
||||
columnIndex,
|
||||
row,
|
||||
column
|
||||
});
|
||||
}
|
||||
return cellStyle;
|
||||
},
|
||||
|
||||
getCellClass(rowIndex, columnIndex, row, column) {
|
||||
const classes = [column.id, column.align, column.className];
|
||||
|
||||
if (this.isColumnHidden(columnIndex)) {
|
||||
classes.push('is-hidden');
|
||||
}
|
||||
|
||||
const cellClassName = this.table.cellClassName;
|
||||
if (typeof cellClassName === 'string') {
|
||||
classes.push(cellClassName);
|
||||
} else if (typeof cellClassName === 'function') {
|
||||
classes.push(cellClassName.call(null, {
|
||||
rowIndex,
|
||||
columnIndex,
|
||||
row,
|
||||
column
|
||||
}));
|
||||
}
|
||||
|
||||
return classes.join(' ');
|
||||
},
|
||||
|
||||
handleCellMouseEnter(event, row) {
|
||||
const table = this.table;
|
||||
const cell = getCell(event);
|
||||
|
||||
if (cell) {
|
||||
const column = getColumnByCell(table, cell);
|
||||
const hoverState = table.hoverState = {cell, column, row};
|
||||
table.$emit('cell-mouse-enter', hoverState.row, hoverState.column, hoverState.cell, event);
|
||||
}
|
||||
|
||||
// 判断是否text-overflow, 如果是就显示tooltip
|
||||
const cellChild = event.target.querySelector('.cell');
|
||||
if (!(hasClass(cellChild, 'el-tooltip') && cellChild.childNodes.length)) {
|
||||
return;
|
||||
}
|
||||
// use range width instead of scrollWidth to determine whether the text is overflowing
|
||||
// to address a potential FireFox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1074543#c3
|
||||
const range = document.createRange();
|
||||
range.setStart(cellChild, 0);
|
||||
range.setEnd(cellChild, cellChild.childNodes.length);
|
||||
const rangeWidth = range.getBoundingClientRect().width;
|
||||
const padding = (parseInt(getStyle(cellChild, 'paddingLeft'), 10) || 0) +
|
||||
(parseInt(getStyle(cellChild, 'paddingRight'), 10) || 0);
|
||||
if ((rangeWidth + padding > cellChild.offsetWidth || cellChild.scrollWidth > cellChild.offsetWidth) && this.$refs.tooltip) {
|
||||
const tooltip = this.$refs.tooltip;
|
||||
// TODO 会引起整个 Table 的重新渲染,需要优化
|
||||
this.tooltipContent = cell.innerText || cell.textContent;
|
||||
tooltip.referenceElm = cell;
|
||||
tooltip.$refs.popper && (tooltip.$refs.popper.style.display = 'none');
|
||||
tooltip.doDestroy();
|
||||
tooltip.setExpectedState(true);
|
||||
this.activateTooltip(tooltip);
|
||||
}
|
||||
},
|
||||
|
||||
handleCellMouseLeave(event) {
|
||||
const tooltip = this.$refs.tooltip;
|
||||
if (tooltip) {
|
||||
tooltip.setExpectedState(false);
|
||||
tooltip.handleClosePopper();
|
||||
}
|
||||
const cell = getCell(event);
|
||||
if (!cell) return;
|
||||
|
||||
const oldHoverState = this.table.hoverState || {};
|
||||
this.table.$emit('cell-mouse-leave', oldHoverState.row, oldHoverState.column, oldHoverState.cell, event);
|
||||
},
|
||||
|
||||
handleMouseEnter(index) {
|
||||
this.store.commit('setHoverRow', index);
|
||||
},
|
||||
|
||||
handleMouseLeave() {
|
||||
this.store.commit('setHoverRow', null);
|
||||
},
|
||||
|
||||
handleContextMenu(event, row) {
|
||||
this.handleEvent(event, row, 'contextmenu');
|
||||
},
|
||||
|
||||
handleDoubleClick(event, row) {
|
||||
this.handleEvent(event, row, 'dblclick');
|
||||
},
|
||||
|
||||
handleClick(event, row) {
|
||||
this.store.commit('setCurrentRow', row);
|
||||
this.handleEvent(event, row, 'click');
|
||||
},
|
||||
|
||||
handleEvent(event, row, name) {
|
||||
const table = this.table;
|
||||
const cell = getCell(event);
|
||||
let column;
|
||||
if (cell) {
|
||||
column = getColumnByCell(table, cell);
|
||||
if (column) {
|
||||
table.$emit(`cell-${name}`, row, column, cell, event);
|
||||
}
|
||||
}
|
||||
table.$emit(`row-${name}`, row, column, event);
|
||||
},
|
||||
|
||||
handleExpandClick(row, e) {
|
||||
e.stopPropagation();
|
||||
this.store.toggleRowExpansion(row);
|
||||
}
|
||||
}
|
||||
};
|
||||
+462
@@ -0,0 +1,462 @@
|
||||
import ElCheckbox from 'element-ui/packages/checkbox';
|
||||
import ElTag from 'element-ui/packages/tag';
|
||||
import objectAssign from 'element-ui/src/utils/merge';
|
||||
import { getPropByPath } from 'element-ui/src/utils/util';
|
||||
|
||||
let columnIdSeed = 1;
|
||||
|
||||
const defaults = {
|
||||
default: {
|
||||
order: ''
|
||||
},
|
||||
selection: {
|
||||
width: 48,
|
||||
minWidth: 48,
|
||||
realWidth: 48,
|
||||
order: '',
|
||||
className: 'el-table-column--selection'
|
||||
},
|
||||
expand: {
|
||||
width: 48,
|
||||
minWidth: 48,
|
||||
realWidth: 48,
|
||||
order: ''
|
||||
},
|
||||
index: {
|
||||
width: 48,
|
||||
minWidth: 48,
|
||||
realWidth: 48,
|
||||
order: ''
|
||||
}
|
||||
};
|
||||
|
||||
const forced = {
|
||||
selection: {
|
||||
renderHeader: function(h, { store }) {
|
||||
return <el-checkbox
|
||||
disabled={ store.states.data && store.states.data.length === 0 }
|
||||
indeterminate={ store.states.selection.length > 0 && !this.isAllSelected }
|
||||
nativeOn-click={ this.toggleAllSelection }
|
||||
value={ this.isAllSelected } />;
|
||||
},
|
||||
renderCell: function(h, { row, column, store, $index }) {
|
||||
return <el-checkbox
|
||||
nativeOn-click={ (event) => event.stopPropagation() }
|
||||
value={ store.isSelected(row) }
|
||||
disabled={ column.selectable ? !column.selectable.call(null, row, $index) : false }
|
||||
on-input={ () => { store.commit('rowSelectedChanged', row); } } />;
|
||||
},
|
||||
sortable: false,
|
||||
resizable: false
|
||||
},
|
||||
index: {
|
||||
renderHeader: function(h, { column }) {
|
||||
return column.label || '#';
|
||||
},
|
||||
renderCell: function(h, { $index, column }) {
|
||||
let i = $index + 1;
|
||||
const index = column.index;
|
||||
|
||||
if (typeof index === 'number') {
|
||||
i = $index + index;
|
||||
} else if (typeof index === 'function') {
|
||||
i = index($index);
|
||||
}
|
||||
|
||||
return <div>{ i }</div>;
|
||||
},
|
||||
sortable: false
|
||||
},
|
||||
expand: {
|
||||
renderHeader: function(h, { column }) {
|
||||
return column.label || '';
|
||||
},
|
||||
renderCell: function(h, { row, store }, proxy) {
|
||||
const expanded = store.states.expandRows.indexOf(row) > -1;
|
||||
return <div class={ 'el-table__expand-icon ' + (expanded ? 'el-table__expand-icon--expanded' : '') }
|
||||
on-click={ e => proxy.handleExpandClick(row, e) }>
|
||||
<i class='el-icon el-icon-arrow-right'></i>
|
||||
</div>;
|
||||
},
|
||||
sortable: false,
|
||||
resizable: false,
|
||||
className: 'el-table__expand-column'
|
||||
}
|
||||
};
|
||||
|
||||
const getDefaultColumn = function(type, options) {
|
||||
const column = {};
|
||||
|
||||
objectAssign(column, defaults[type || 'default']);
|
||||
|
||||
for (let name in options) {
|
||||
if (options.hasOwnProperty(name)) {
|
||||
const value = options[name];
|
||||
if (typeof value !== 'undefined') {
|
||||
column[name] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!column.minWidth) {
|
||||
column.minWidth = 80;
|
||||
}
|
||||
|
||||
column.realWidth = column.width === undefined ? column.minWidth : column.width;
|
||||
|
||||
return column;
|
||||
};
|
||||
|
||||
const DEFAULT_RENDER_CELL = function(h, { row, column, $index }) {
|
||||
const property = column.property;
|
||||
const value = property && getPropByPath(row, property).v;
|
||||
if (column && column.formatter) {
|
||||
return column.formatter(row, column, value, $index);
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
const parseWidth = (width) => {
|
||||
if (width !== undefined) {
|
||||
width = parseInt(width, 10);
|
||||
if (isNaN(width)) {
|
||||
width = null;
|
||||
}
|
||||
}
|
||||
return width;
|
||||
};
|
||||
|
||||
const parseMinWidth = (minWidth) => {
|
||||
if (minWidth !== undefined) {
|
||||
minWidth = parseInt(minWidth, 10);
|
||||
if (isNaN(minWidth)) {
|
||||
minWidth = 80;
|
||||
}
|
||||
}
|
||||
return minWidth;
|
||||
};
|
||||
|
||||
export default {
|
||||
name: 'ElTableColumn',
|
||||
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
default: 'default'
|
||||
},
|
||||
label: String,
|
||||
className: String,
|
||||
labelClassName: String,
|
||||
property: String,
|
||||
prop: String,
|
||||
width: {},
|
||||
minWidth: {},
|
||||
renderHeader: Function,
|
||||
sortable: {
|
||||
type: [String, Boolean],
|
||||
default: false
|
||||
},
|
||||
sortMethod: Function,
|
||||
sortBy: [String, Function, Array],
|
||||
resizable: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
context: {},
|
||||
columnKey: String,
|
||||
align: String,
|
||||
headerAlign: String,
|
||||
showTooltipWhenOverflow: Boolean,
|
||||
showOverflowTooltip: Boolean,
|
||||
fixed: [Boolean, String],
|
||||
formatter: Function,
|
||||
selectable: Function,
|
||||
reserveSelection: Boolean,
|
||||
filterMethod: Function,
|
||||
filteredValue: Array,
|
||||
filters: Array,
|
||||
filterPlacement: String,
|
||||
filterMultiple: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
index: [Number, Function],
|
||||
sortOrders: {
|
||||
type: Array,
|
||||
default() {
|
||||
return ['ascending', 'descending', null];
|
||||
},
|
||||
validator(val) {
|
||||
return val.every(order => ['ascending', 'descending', null].indexOf(order) > -1);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
isSubColumn: false,
|
||||
columns: []
|
||||
};
|
||||
},
|
||||
|
||||
beforeCreate() {
|
||||
this.row = {};
|
||||
this.column = {};
|
||||
this.$index = 0;
|
||||
},
|
||||
|
||||
components: {
|
||||
ElCheckbox,
|
||||
ElTag
|
||||
},
|
||||
|
||||
computed: {
|
||||
owner() {
|
||||
let parent = this.$parent;
|
||||
while (parent && !parent.tableId) {
|
||||
parent = parent.$parent;
|
||||
}
|
||||
return parent;
|
||||
},
|
||||
columnOrTableParent() {
|
||||
let parent = this.$parent;
|
||||
while (parent && !parent.tableId && !parent.columnId) {
|
||||
parent = parent.$parent;
|
||||
}
|
||||
return parent;
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
this.customRender = this.$options.render;
|
||||
this.$options.render = h => h('div', this.$slots.default);
|
||||
|
||||
let parent = this.columnOrTableParent;
|
||||
let owner = this.owner;
|
||||
this.isSubColumn = owner !== parent;
|
||||
this.columnId = (parent.tableId || parent.columnId) + '_column_' + columnIdSeed++;
|
||||
|
||||
let type = this.type;
|
||||
|
||||
const width = parseWidth(this.width);
|
||||
const minWidth = parseMinWidth(this.minWidth);
|
||||
|
||||
let isColumnGroup = false;
|
||||
|
||||
let column = getDefaultColumn(type, {
|
||||
id: this.columnId,
|
||||
columnKey: this.columnKey,
|
||||
label: this.label,
|
||||
className: this.className,
|
||||
labelClassName: this.labelClassName,
|
||||
property: this.prop || this.property,
|
||||
type,
|
||||
renderCell: null,
|
||||
renderHeader: this.renderHeader,
|
||||
minWidth,
|
||||
width,
|
||||
isColumnGroup,
|
||||
context: this.context,
|
||||
align: this.align ? 'is-' + this.align : null,
|
||||
headerAlign: this.headerAlign ? 'is-' + this.headerAlign : (this.align ? 'is-' + this.align : null),
|
||||
sortable: this.sortable === '' ? true : this.sortable,
|
||||
sortMethod: this.sortMethod,
|
||||
sortBy: this.sortBy,
|
||||
resizable: this.resizable,
|
||||
showOverflowTooltip: this.showOverflowTooltip || this.showTooltipWhenOverflow,
|
||||
formatter: this.formatter,
|
||||
selectable: this.selectable,
|
||||
reserveSelection: this.reserveSelection,
|
||||
fixed: this.fixed === '' ? true : this.fixed,
|
||||
filterMethod: this.filterMethod,
|
||||
filters: this.filters,
|
||||
filterable: this.filters || this.filterMethod,
|
||||
filterMultiple: this.filterMultiple,
|
||||
filterOpened: false,
|
||||
filteredValue: this.filteredValue || [],
|
||||
filterPlacement: this.filterPlacement || '',
|
||||
index: this.index,
|
||||
sortOrders: this.sortOrders
|
||||
});
|
||||
|
||||
let source = forced[type] || {};
|
||||
Object.keys(source).forEach((prop) => {
|
||||
let value = source[prop];
|
||||
if (value !== undefined) {
|
||||
if (prop === 'renderHeader') {
|
||||
if (type === 'selection' && column[prop]) {
|
||||
console.warn('[Element Warn][TableColumn]Selection column doesn\'t allow to set render-header function.');
|
||||
} else {
|
||||
value = column[prop] || value;
|
||||
}
|
||||
}
|
||||
column[prop] = prop === 'className' ? `${column[prop]} ${value}` : value;
|
||||
}
|
||||
});
|
||||
|
||||
// Deprecation warning for renderHeader property
|
||||
if (this.renderHeader) {
|
||||
console.warn('[Element Warn][TableColumn]Comparing to render-header, scoped-slot header is easier to use. We recommend users to use scoped-slot header.');
|
||||
}
|
||||
|
||||
this.columnConfig = column;
|
||||
|
||||
let renderCell = column.renderCell;
|
||||
let _self = this;
|
||||
|
||||
if (type === 'expand') {
|
||||
owner.renderExpanded = function(h, data) {
|
||||
return _self.$scopedSlots.default
|
||||
? _self.$scopedSlots.default(data)
|
||||
: _self.$slots.default;
|
||||
};
|
||||
|
||||
column.renderCell = function(h, data) {
|
||||
return <div class="cell">{ renderCell(h, data, this._renderProxy) }</div>;
|
||||
};
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
column.renderCell = function(h, data) {
|
||||
if (_self.$scopedSlots.default) {
|
||||
renderCell = () => _self.$scopedSlots.default(data);
|
||||
}
|
||||
|
||||
if (!renderCell) {
|
||||
renderCell = DEFAULT_RENDER_CELL;
|
||||
}
|
||||
|
||||
return _self.showOverflowTooltip || _self.showTooltipWhenOverflow
|
||||
? <div class="cell el-tooltip" style={ {width: (data.column.realWidth || data.column.width) - 1 + 'px'} }>{ renderCell(h, data) }</div>
|
||||
: <div class="cell">{ renderCell(h, data) }</div>;
|
||||
};
|
||||
},
|
||||
|
||||
destroyed() {
|
||||
if (!this.$parent) return;
|
||||
const parent = this.$parent;
|
||||
this.owner.store.commit('removeColumn', this.columnConfig, this.isSubColumn ? parent.columnConfig : null);
|
||||
},
|
||||
|
||||
watch: {
|
||||
label(newVal) {
|
||||
if (this.columnConfig) {
|
||||
this.columnConfig.label = newVal;
|
||||
}
|
||||
},
|
||||
|
||||
prop(newVal) {
|
||||
if (this.columnConfig) {
|
||||
this.columnConfig.property = newVal;
|
||||
}
|
||||
},
|
||||
|
||||
property(newVal) {
|
||||
if (this.columnConfig) {
|
||||
this.columnConfig.property = newVal;
|
||||
}
|
||||
},
|
||||
|
||||
filters(newVal) {
|
||||
if (this.columnConfig) {
|
||||
this.columnConfig.filters = newVal;
|
||||
}
|
||||
},
|
||||
|
||||
filterMultiple(newVal) {
|
||||
if (this.columnConfig) {
|
||||
this.columnConfig.filterMultiple = newVal;
|
||||
}
|
||||
},
|
||||
|
||||
align(newVal) {
|
||||
if (this.columnConfig) {
|
||||
this.columnConfig.align = newVal ? 'is-' + newVal : null;
|
||||
|
||||
if (!this.headerAlign) {
|
||||
this.columnConfig.headerAlign = newVal ? 'is-' + newVal : null;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
headerAlign(newVal) {
|
||||
if (this.columnConfig) {
|
||||
this.columnConfig.headerAlign = 'is-' + (newVal ? newVal : this.align);
|
||||
}
|
||||
},
|
||||
|
||||
width(newVal) {
|
||||
if (this.columnConfig) {
|
||||
this.columnConfig.width = parseWidth(newVal);
|
||||
this.owner.store.scheduleLayout();
|
||||
}
|
||||
},
|
||||
|
||||
minWidth(newVal) {
|
||||
if (this.columnConfig) {
|
||||
this.columnConfig.minWidth = parseMinWidth(newVal);
|
||||
this.owner.store.scheduleLayout();
|
||||
}
|
||||
},
|
||||
|
||||
fixed(newVal) {
|
||||
if (this.columnConfig) {
|
||||
this.columnConfig.fixed = newVal;
|
||||
this.owner.store.scheduleLayout(true);
|
||||
}
|
||||
},
|
||||
|
||||
sortable(newVal) {
|
||||
if (this.columnConfig) {
|
||||
this.columnConfig.sortable = newVal;
|
||||
}
|
||||
},
|
||||
|
||||
index(newVal) {
|
||||
if (this.columnConfig) {
|
||||
this.columnConfig.index = newVal;
|
||||
}
|
||||
},
|
||||
|
||||
formatter(newVal) {
|
||||
if (this.columnConfig) {
|
||||
this.columnConfig.formatter = newVal;
|
||||
}
|
||||
},
|
||||
|
||||
className(newVal) {
|
||||
if (this.columnConfig) {
|
||||
this.columnConfig.className = newVal;
|
||||
}
|
||||
},
|
||||
|
||||
labelClassName(newVal) {
|
||||
if (this.columnConfig) {
|
||||
this.columnConfig.labelClassName = newVal;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
const owner = this.owner;
|
||||
const parent = this.columnOrTableParent;
|
||||
let columnIndex;
|
||||
|
||||
if (!this.isSubColumn) {
|
||||
columnIndex = [].indexOf.call(parent.$refs.hiddenColumns.children, this.$el);
|
||||
} else {
|
||||
columnIndex = [].indexOf.call(parent.$el.children, this.$el);
|
||||
}
|
||||
|
||||
if (this.$scopedSlots.header) {
|
||||
if (this.type === 'selection') {
|
||||
console.warn('[Element Warn][TableColumn]Selection column doesn\'t allow to set scoped-slot header.');
|
||||
} else {
|
||||
this.columnConfig.renderHeader = (h, scope) => this.$scopedSlots.header(scope);
|
||||
}
|
||||
}
|
||||
|
||||
owner.store.commit('insertColumn', this.columnConfig, columnIndex, this.isSubColumn ? parent.columnConfig : null);
|
||||
}
|
||||
};
|
||||
+157
@@ -0,0 +1,157 @@
|
||||
import LayoutObserver from './layout-observer';
|
||||
|
||||
export default {
|
||||
name: 'ElTableFooter',
|
||||
|
||||
mixins: [LayoutObserver],
|
||||
|
||||
render(h) {
|
||||
let sums = [];
|
||||
if (this.summaryMethod) {
|
||||
sums = this.summaryMethod({ columns: this.columns, data: this.store.states.data });
|
||||
} else {
|
||||
this.columns.forEach((column, index) => {
|
||||
if (index === 0) {
|
||||
sums[index] = this.sumText;
|
||||
return;
|
||||
}
|
||||
const values = this.store.states.data.map(item => Number(item[column.property]));
|
||||
const precisions = [];
|
||||
let notNumber = true;
|
||||
values.forEach(value => {
|
||||
if (!isNaN(value)) {
|
||||
notNumber = false;
|
||||
let decimal = ('' + value).split('.')[1];
|
||||
precisions.push(decimal ? decimal.length : 0);
|
||||
}
|
||||
});
|
||||
const precision = Math.max.apply(null, precisions);
|
||||
if (!notNumber) {
|
||||
sums[index] = values.reduce((prev, curr) => {
|
||||
const value = Number(curr);
|
||||
if (!isNaN(value)) {
|
||||
return parseFloat((prev + curr).toFixed(Math.min(precision, 20)));
|
||||
} else {
|
||||
return prev;
|
||||
}
|
||||
}, 0);
|
||||
} else {
|
||||
sums[index] = '';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<table
|
||||
class="el-table__footer"
|
||||
cellspacing="0"
|
||||
cellpadding="0"
|
||||
border="0">
|
||||
<colgroup>
|
||||
{
|
||||
this._l(this.columns, column => <col name={ column.id } />)
|
||||
}
|
||||
{
|
||||
this.hasGutter ? <col name="gutter" /> : ''
|
||||
}
|
||||
</colgroup>
|
||||
<tbody class={ [{ 'has-gutter': this.hasGutter }] }>
|
||||
<tr>
|
||||
{
|
||||
this._l(this.columns, (column, cellIndex) =>
|
||||
<td
|
||||
colspan={ column.colSpan }
|
||||
rowspan={ column.rowSpan }
|
||||
class={ [column.id, column.headerAlign, column.className || '', this.isCellHidden(cellIndex, this.columns, column) ? 'is-hidden' : '', !column.children ? 'is-leaf' : '', column.labelClassName] }>
|
||||
<div class={ ['cell', column.labelClassName] }>
|
||||
{
|
||||
sums[cellIndex]
|
||||
}
|
||||
</div>
|
||||
</td>
|
||||
)
|
||||
}
|
||||
{
|
||||
this.hasGutter ? <th class="gutter"></th> : ''
|
||||
}
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
},
|
||||
|
||||
props: {
|
||||
fixed: String,
|
||||
store: {
|
||||
required: true
|
||||
},
|
||||
summaryMethod: Function,
|
||||
sumText: String,
|
||||
border: Boolean,
|
||||
defaultSort: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {
|
||||
prop: '',
|
||||
order: ''
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
table() {
|
||||
return this.$parent;
|
||||
},
|
||||
|
||||
isAllSelected() {
|
||||
return this.store.states.isAllSelected;
|
||||
},
|
||||
|
||||
columnsCount() {
|
||||
return this.store.states.columns.length;
|
||||
},
|
||||
|
||||
leftFixedCount() {
|
||||
return this.store.states.fixedColumns.length;
|
||||
},
|
||||
|
||||
leftFixedLeafCount() {
|
||||
return this.store.states.fixedLeafColumnsLength;
|
||||
},
|
||||
|
||||
rightFixedLeafCount() {
|
||||
return this.store.states.rightFixedLeafColumnsLength;
|
||||
},
|
||||
|
||||
rightFixedCount() {
|
||||
return this.store.states.rightFixedColumns.length;
|
||||
},
|
||||
|
||||
columns() {
|
||||
return this.store.states.columns;
|
||||
},
|
||||
|
||||
hasGutter() {
|
||||
return !this.fixed && this.tableLayout.gutterWidth;
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
isCellHidden(index, columns, column) {
|
||||
if (this.fixed === true || this.fixed === 'left') {
|
||||
return index >= this.leftFixedLeafCount;
|
||||
} else if (this.fixed === 'right') {
|
||||
let before = 0;
|
||||
for (let i = 0; i < index; i++) {
|
||||
before += columns[i].colSpan;
|
||||
}
|
||||
return before < this.columnsCount - this.rightFixedLeafCount;
|
||||
} else if (!this.fixed && column.fixed) { // hide cell when footer instance is not fixed and column is fixed
|
||||
return true;
|
||||
} else {
|
||||
return (index < this.leftFixedCount) || (index >= this.columnsCount - this.rightFixedCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
+524
@@ -0,0 +1,524 @@
|
||||
import { hasClass, addClass, removeClass } from 'element-ui/src/utils/dom';
|
||||
import ElCheckbox from 'element-ui/packages/checkbox';
|
||||
import ElTag from 'element-ui/packages/tag';
|
||||
import Vue from 'vue';
|
||||
import FilterPanel from './filter-panel.vue';
|
||||
import LayoutObserver from './layout-observer';
|
||||
|
||||
const getAllColumns = (columns) => {
|
||||
const result = [];
|
||||
columns.forEach((column) => {
|
||||
if (column.children) {
|
||||
result.push(column);
|
||||
result.push.apply(result, getAllColumns(column.children));
|
||||
} else {
|
||||
result.push(column);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
const convertToRows = (originColumns) => {
|
||||
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);
|
||||
|
||||
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 default {
|
||||
name: 'ElTableHeader',
|
||||
|
||||
mixins: [LayoutObserver],
|
||||
|
||||
render(h) {
|
||||
const originColumns = this.store.states.originColumns;
|
||||
const columnRows = convertToRows(originColumns, this.columns);
|
||||
// 是否拥有多级表头
|
||||
const isGroup = columnRows.length > 1;
|
||||
if (isGroup) this.$parent.isGroup = true;
|
||||
return (
|
||||
<table
|
||||
class="el-table__header"
|
||||
cellspacing="0"
|
||||
cellpadding="0"
|
||||
border="0">
|
||||
<colgroup>
|
||||
{
|
||||
this._l(this.columns, column => <col name={ column.id } />)
|
||||
}
|
||||
{
|
||||
this.hasGutter ? <col name="gutter" /> : ''
|
||||
}
|
||||
</colgroup>
|
||||
<thead class={ [{ 'is-group': isGroup, 'has-gutter': this.hasGutter }] }>
|
||||
{
|
||||
this._l(columnRows, (columns, rowIndex) =>
|
||||
<tr
|
||||
style={ this.getHeaderRowStyle(rowIndex) }
|
||||
class={ this.getHeaderRowClass(rowIndex) }
|
||||
>
|
||||
{
|
||||
this._l(columns, (column, cellIndex) =>
|
||||
<th
|
||||
colspan={ column.colSpan }
|
||||
rowspan={ column.rowSpan }
|
||||
on-mousemove={ ($event) => this.handleMouseMove($event, column) }
|
||||
on-mouseout={ this.handleMouseOut }
|
||||
on-mousedown={ ($event) => this.handleMouseDown($event, column) }
|
||||
on-click={ ($event) => this.handleHeaderClick($event, column) }
|
||||
on-contextmenu={ ($event) => this.handleHeaderContextMenu($event, column) }
|
||||
style={ this.getHeaderCellStyle(rowIndex, cellIndex, columns, column) }
|
||||
class={ this.getHeaderCellClass(rowIndex, cellIndex, columns, column) }
|
||||
key={ column.id }>
|
||||
<div class={ ['cell', column.filteredValue && column.filteredValue.length > 0 ? 'highlight' : '', column.labelClassName] }>
|
||||
{
|
||||
column.renderHeader
|
||||
? column.renderHeader.call(this._renderProxy, h, { column, $index: cellIndex, store: this.store, _self: this.$parent.$vnode.context })
|
||||
: column.label
|
||||
}
|
||||
{
|
||||
column.sortable
|
||||
? <span class="caret-wrapper" on-click={ ($event) => this.handleSortClick($event, column) }>
|
||||
<i class="sort-caret ascending" on-click={ ($event) => this.handleSortClick($event, column, 'ascending') }>
|
||||
</i>
|
||||
<i class="sort-caret descending" on-click={ ($event) => this.handleSortClick($event, column, 'descending') }>
|
||||
</i>
|
||||
</span>
|
||||
: ''
|
||||
}
|
||||
{
|
||||
column.filterable
|
||||
? <span class="el-table__column-filter-trigger" on-click={ ($event) => this.handleFilterClick($event, column) }><i class={ ['el-icon-arrow-down', column.filterOpened ? 'el-icon-arrow-up' : ''] }></i></span>
|
||||
: ''
|
||||
}
|
||||
</div>
|
||||
</th>
|
||||
)
|
||||
}
|
||||
{
|
||||
this.hasGutter ? <th class="gutter"></th> : ''
|
||||
}
|
||||
</tr>
|
||||
)
|
||||
}
|
||||
</thead>
|
||||
</table>
|
||||
);
|
||||
},
|
||||
|
||||
props: {
|
||||
fixed: String,
|
||||
store: {
|
||||
required: true
|
||||
},
|
||||
border: Boolean,
|
||||
defaultSort: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {
|
||||
prop: '',
|
||||
order: ''
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
components: {
|
||||
ElCheckbox,
|
||||
ElTag
|
||||
},
|
||||
|
||||
computed: {
|
||||
table() {
|
||||
return this.$parent;
|
||||
},
|
||||
|
||||
isAllSelected() {
|
||||
return this.store.states.isAllSelected;
|
||||
},
|
||||
|
||||
columnsCount() {
|
||||
return this.store.states.columns.length;
|
||||
},
|
||||
|
||||
leftFixedCount() {
|
||||
return this.store.states.fixedColumns.length;
|
||||
},
|
||||
|
||||
rightFixedCount() {
|
||||
return this.store.states.rightFixedColumns.length;
|
||||
},
|
||||
|
||||
leftFixedLeafCount() {
|
||||
return this.store.states.fixedLeafColumnsLength;
|
||||
},
|
||||
|
||||
rightFixedLeafCount() {
|
||||
return this.store.states.rightFixedLeafColumnsLength;
|
||||
},
|
||||
|
||||
columns() {
|
||||
return this.store.states.columns;
|
||||
},
|
||||
|
||||
hasGutter() {
|
||||
return !this.fixed && this.tableLayout.gutterWidth;
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
this.filterPanels = {};
|
||||
},
|
||||
|
||||
mounted() {
|
||||
const { prop, order } = this.defaultSort;
|
||||
this.store.commit('sort', { prop, order });
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
const panels = this.filterPanels;
|
||||
for (let prop in panels) {
|
||||
if (panels.hasOwnProperty(prop) && panels[prop]) {
|
||||
panels[prop].$destroy(true);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
isCellHidden(index, columns) {
|
||||
let start = 0;
|
||||
for (let i = 0; i < index; i++) {
|
||||
start += columns[i].colSpan;
|
||||
}
|
||||
const after = start + columns[index].colSpan - 1;
|
||||
if (this.fixed === true || this.fixed === 'left') {
|
||||
return after >= this.leftFixedLeafCount;
|
||||
} else if (this.fixed === 'right') {
|
||||
return start < this.columnsCount - this.rightFixedLeafCount;
|
||||
} else {
|
||||
return (after < this.leftFixedLeafCount) || (start >= this.columnsCount - this.rightFixedLeafCount);
|
||||
}
|
||||
},
|
||||
|
||||
getHeaderRowStyle(rowIndex) {
|
||||
const headerRowStyle = this.table.headerRowStyle;
|
||||
if (typeof headerRowStyle === 'function') {
|
||||
return headerRowStyle.call(null, { rowIndex });
|
||||
}
|
||||
return headerRowStyle;
|
||||
},
|
||||
|
||||
getHeaderRowClass(rowIndex) {
|
||||
const classes = [];
|
||||
|
||||
const headerRowClassName = this.table.headerRowClassName;
|
||||
if (typeof headerRowClassName === 'string') {
|
||||
classes.push(headerRowClassName);
|
||||
} else if (typeof headerRowClassName === 'function') {
|
||||
classes.push(headerRowClassName.call(null, { rowIndex }));
|
||||
}
|
||||
|
||||
return classes.join(' ');
|
||||
},
|
||||
|
||||
getHeaderCellStyle(rowIndex, columnIndex, row, column) {
|
||||
const headerCellStyle = this.table.headerCellStyle;
|
||||
if (typeof headerCellStyle === 'function') {
|
||||
return headerCellStyle.call(null, {
|
||||
rowIndex,
|
||||
columnIndex,
|
||||
row,
|
||||
column
|
||||
});
|
||||
}
|
||||
return headerCellStyle;
|
||||
},
|
||||
|
||||
getHeaderCellClass(rowIndex, columnIndex, row, column) {
|
||||
const classes = [column.id, column.order, column.headerAlign, column.className, column.labelClassName];
|
||||
|
||||
if (rowIndex === 0 && this.isCellHidden(columnIndex, row)) {
|
||||
classes.push('is-hidden');
|
||||
}
|
||||
|
||||
if (!column.children) {
|
||||
classes.push('is-leaf');
|
||||
}
|
||||
|
||||
if (column.sortable) {
|
||||
classes.push('is-sortable');
|
||||
}
|
||||
|
||||
const headerCellClassName = this.table.headerCellClassName;
|
||||
if (typeof headerCellClassName === 'string') {
|
||||
classes.push(headerCellClassName);
|
||||
} else if (typeof headerCellClassName === 'function') {
|
||||
classes.push(headerCellClassName.call(null, {
|
||||
rowIndex,
|
||||
columnIndex,
|
||||
row,
|
||||
column
|
||||
}));
|
||||
}
|
||||
|
||||
return classes.join(' ');
|
||||
},
|
||||
|
||||
toggleAllSelection(event) {
|
||||
event.stopPropagation();
|
||||
this.store.commit('toggleAllSelection');
|
||||
},
|
||||
|
||||
handleFilterClick(event, column) {
|
||||
event.stopPropagation();
|
||||
const target = event.target;
|
||||
let cell = target.tagName === 'TH' ? target : target.parentNode;
|
||||
cell = cell.querySelector('.el-table__column-filter-trigger') || cell;
|
||||
const table = this.$parent;
|
||||
|
||||
let filterPanel = this.filterPanels[column.id];
|
||||
|
||||
if (filterPanel && column.filterOpened) {
|
||||
filterPanel.showPopper = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!filterPanel) {
|
||||
filterPanel = new Vue(FilterPanel);
|
||||
this.filterPanels[column.id] = filterPanel;
|
||||
if (column.filterPlacement) {
|
||||
filterPanel.placement = column.filterPlacement;
|
||||
}
|
||||
filterPanel.table = table;
|
||||
filterPanel.cell = cell;
|
||||
filterPanel.column = column;
|
||||
!this.$isServer && filterPanel.$mount(document.createElement('div'));
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
filterPanel.showPopper = true;
|
||||
}, 16);
|
||||
},
|
||||
|
||||
handleHeaderClick(event, column) {
|
||||
if (!column.filters && column.sortable) {
|
||||
this.handleSortClick(event, column);
|
||||
} else if (column.filterable && !column.sortable) {
|
||||
this.handleFilterClick(event, column);
|
||||
}
|
||||
|
||||
this.$parent.$emit('header-click', column, event);
|
||||
},
|
||||
|
||||
handleHeaderContextMenu(event, column) {
|
||||
this.$parent.$emit('header-contextmenu', column, event);
|
||||
},
|
||||
|
||||
handleMouseDown(event, column) {
|
||||
if (this.$isServer) return;
|
||||
if (column.children && column.children.length > 0) return;
|
||||
/* istanbul ignore if */
|
||||
if (this.draggingColumn && this.border) {
|
||||
this.dragging = true;
|
||||
|
||||
this.$parent.resizeProxyVisible = true;
|
||||
|
||||
const table = this.$parent;
|
||||
const tableEl = table.$el;
|
||||
const tableLeft = tableEl.getBoundingClientRect().left;
|
||||
const columnEl = this.$el.querySelector(`th.${column.id}`);
|
||||
const columnRect = columnEl.getBoundingClientRect();
|
||||
const minLeft = columnRect.left - tableLeft + 30;
|
||||
|
||||
addClass(columnEl, 'noclick');
|
||||
|
||||
this.dragState = {
|
||||
startMouseLeft: event.clientX,
|
||||
startLeft: columnRect.right - tableLeft,
|
||||
startColumnLeft: columnRect.left - tableLeft,
|
||||
tableLeft
|
||||
};
|
||||
|
||||
const resizeProxy = table.$refs.resizeProxy;
|
||||
resizeProxy.style.left = this.dragState.startLeft + 'px';
|
||||
|
||||
document.onselectstart = function() { return false; };
|
||||
document.ondragstart = function() { return false; };
|
||||
|
||||
const handleMouseMove = (event) => {
|
||||
const deltaLeft = event.clientX - this.dragState.startMouseLeft;
|
||||
const proxyLeft = this.dragState.startLeft + deltaLeft;
|
||||
|
||||
resizeProxy.style.left = Math.max(minLeft, proxyLeft) + 'px';
|
||||
};
|
||||
|
||||
const handleMouseUp = () => {
|
||||
if (this.dragging) {
|
||||
const {
|
||||
startColumnLeft,
|
||||
startLeft
|
||||
} = this.dragState;
|
||||
const finalLeft = parseInt(resizeProxy.style.left, 10);
|
||||
const columnWidth = finalLeft - startColumnLeft;
|
||||
column.width = column.realWidth = columnWidth;
|
||||
table.$emit('header-dragend', column.width, startLeft - startColumnLeft, column, event);
|
||||
|
||||
this.store.scheduleLayout();
|
||||
|
||||
document.body.style.cursor = '';
|
||||
this.dragging = false;
|
||||
this.draggingColumn = null;
|
||||
this.dragState = {};
|
||||
|
||||
table.resizeProxyVisible = false;
|
||||
}
|
||||
|
||||
document.removeEventListener('mousemove', handleMouseMove);
|
||||
document.removeEventListener('mouseup', handleMouseUp);
|
||||
document.onselectstart = null;
|
||||
document.ondragstart = null;
|
||||
|
||||
setTimeout(function() {
|
||||
removeClass(columnEl, 'noclick');
|
||||
}, 0);
|
||||
};
|
||||
|
||||
document.addEventListener('mousemove', handleMouseMove);
|
||||
document.addEventListener('mouseup', handleMouseUp);
|
||||
}
|
||||
},
|
||||
|
||||
handleMouseMove(event, column) {
|
||||
if (column.children && column.children.length > 0) return;
|
||||
let target = event.target;
|
||||
while (target && target.tagName !== 'TH') {
|
||||
target = target.parentNode;
|
||||
}
|
||||
|
||||
if (!column || !column.resizable) return;
|
||||
|
||||
if (!this.dragging && this.border) {
|
||||
let rect = target.getBoundingClientRect();
|
||||
|
||||
const bodyStyle = document.body.style;
|
||||
if (rect.width > 12 && rect.right - event.pageX < 8) {
|
||||
bodyStyle.cursor = 'col-resize';
|
||||
if (hasClass(target, 'is-sortable')) {
|
||||
target.style.cursor = 'col-resize';
|
||||
}
|
||||
this.draggingColumn = column;
|
||||
} else if (!this.dragging) {
|
||||
bodyStyle.cursor = '';
|
||||
if (hasClass(target, 'is-sortable')) {
|
||||
target.style.cursor = 'pointer';
|
||||
}
|
||||
this.draggingColumn = null;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
handleMouseOut() {
|
||||
if (this.$isServer) return;
|
||||
document.body.style.cursor = '';
|
||||
},
|
||||
|
||||
toggleOrder({ order, sortOrders }) {
|
||||
if (order === '') return sortOrders[0];
|
||||
const index = sortOrders.indexOf(order || null);
|
||||
return sortOrders[index > sortOrders.length - 2 ? 0 : index + 1];
|
||||
},
|
||||
|
||||
handleSortClick(event, column, givenOrder) {
|
||||
event.stopPropagation();
|
||||
let order = column.order === givenOrder
|
||||
? null
|
||||
: (givenOrder || this.toggleOrder(column));
|
||||
|
||||
let target = event.target;
|
||||
while (target && target.tagName !== 'TH') {
|
||||
target = target.parentNode;
|
||||
}
|
||||
|
||||
if (target && target.tagName === 'TH') {
|
||||
if (hasClass(target, 'noclick')) {
|
||||
removeClass(target, 'noclick');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!column.sortable) return;
|
||||
|
||||
const states = this.store.states;
|
||||
let sortProp = states.sortProp;
|
||||
let sortOrder;
|
||||
const sortingColumn = states.sortingColumn;
|
||||
|
||||
if (sortingColumn !== column || (sortingColumn === column && sortingColumn.order === null)) {
|
||||
if (sortingColumn) {
|
||||
sortingColumn.order = null;
|
||||
}
|
||||
states.sortingColumn = column;
|
||||
sortProp = column.property;
|
||||
}
|
||||
|
||||
if (!order) {
|
||||
sortOrder = column.order = null;
|
||||
states.sortingColumn = null;
|
||||
sortProp = null;
|
||||
} else {
|
||||
sortOrder = column.order = order;
|
||||
}
|
||||
|
||||
states.sortProp = sortProp;
|
||||
states.sortOrder = sortOrder;
|
||||
|
||||
this.store.commit('changeSortCondition');
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
draggingColumn: null,
|
||||
dragging: false,
|
||||
dragState: {}
|
||||
};
|
||||
}
|
||||
};
|
||||
+231
@@ -0,0 +1,231 @@
|
||||
import scrollbarWidth from 'element-ui/src/utils/scrollbar-width';
|
||||
import Vue from 'vue';
|
||||
|
||||
class TableLayout {
|
||||
constructor(options) {
|
||||
this.observers = [];
|
||||
this.table = null;
|
||||
this.store = null;
|
||||
this.columns = null;
|
||||
this.fit = true;
|
||||
this.showHeader = true;
|
||||
|
||||
this.height = null;
|
||||
this.scrollX = false;
|
||||
this.scrollY = false;
|
||||
this.bodyWidth = null;
|
||||
this.fixedWidth = null;
|
||||
this.rightFixedWidth = null;
|
||||
this.tableHeight = null;
|
||||
this.headerHeight = 44; // Table Header Height
|
||||
this.appendHeight = 0; // Append Slot Height
|
||||
this.footerHeight = 44; // Table Footer Height
|
||||
this.viewportHeight = null; // Table Height - Scroll Bar Height
|
||||
this.bodyHeight = null; // Table Height - Table Header Height
|
||||
this.fixedBodyHeight = null; // Table Height - Table Header Height - Scroll Bar Height
|
||||
this.gutterWidth = scrollbarWidth();
|
||||
|
||||
for (let name in options) {
|
||||
if (options.hasOwnProperty(name)) {
|
||||
this[name] = options[name];
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.table) {
|
||||
throw new Error('table is required for Table Layout');
|
||||
}
|
||||
if (!this.store) {
|
||||
throw new Error('store is required for Table Layout');
|
||||
}
|
||||
}
|
||||
|
||||
updateScrollY() {
|
||||
const height = this.height;
|
||||
if (typeof height !== 'string' && typeof height !== 'number') return;
|
||||
const bodyWrapper = this.table.bodyWrapper;
|
||||
if (this.table.$el && bodyWrapper) {
|
||||
const body = bodyWrapper.querySelector('.el-table__body');
|
||||
this.scrollY = body.offsetHeight > this.bodyHeight;
|
||||
}
|
||||
}
|
||||
|
||||
setHeight(value, prop = 'height') {
|
||||
if (Vue.prototype.$isServer) return;
|
||||
const el = this.table.$el;
|
||||
if (typeof value === 'string' && /^\d+$/.test(value)) {
|
||||
value = Number(value);
|
||||
}
|
||||
this.height = value;
|
||||
|
||||
if (!el && (value || value === 0)) return Vue.nextTick(() => this.setHeight(value, prop));
|
||||
|
||||
if (typeof value === 'number') {
|
||||
el.style[prop] = value + 'px';
|
||||
|
||||
this.updateElsHeight();
|
||||
} else if (typeof value === 'string') {
|
||||
el.style[prop] = value;
|
||||
this.updateElsHeight();
|
||||
}
|
||||
}
|
||||
|
||||
setMaxHeight(value) {
|
||||
return this.setHeight(value, 'max-height');
|
||||
}
|
||||
|
||||
updateElsHeight() {
|
||||
if (!this.table.$ready) return Vue.nextTick(() => this.updateElsHeight());
|
||||
const { headerWrapper, appendWrapper, footerWrapper } = this.table.$refs;
|
||||
this.appendHeight = appendWrapper ? appendWrapper.offsetHeight : 0;
|
||||
|
||||
if (this.showHeader && !headerWrapper) return;
|
||||
const headerHeight = this.headerHeight = !this.showHeader ? 0 : headerWrapper.offsetHeight;
|
||||
if (this.showHeader && headerWrapper.offsetWidth > 0 && (this.table.columns || []).length > 0 && headerHeight < 2) {
|
||||
return Vue.nextTick(() => this.updateElsHeight());
|
||||
}
|
||||
const tableHeight = this.tableHeight = this.table.$el.clientHeight;
|
||||
if (this.height !== null && (!isNaN(this.height) || typeof this.height === 'string')) {
|
||||
const footerHeight = this.footerHeight = footerWrapper ? footerWrapper.offsetHeight : 0;
|
||||
this.bodyHeight = tableHeight - headerHeight - footerHeight + (footerWrapper ? 1 : 0);
|
||||
}
|
||||
this.fixedBodyHeight = this.scrollX ? this.bodyHeight - this.gutterWidth : this.bodyHeight;
|
||||
|
||||
const noData = !this.table.data || this.table.data.length === 0;
|
||||
this.viewportHeight = this.scrollX ? tableHeight - (noData ? 0 : this.gutterWidth) : tableHeight;
|
||||
|
||||
this.updateScrollY();
|
||||
this.notifyObservers('scrollable');
|
||||
}
|
||||
|
||||
getFlattenColumns() {
|
||||
const flattenColumns = [];
|
||||
const columns = this.table.columns;
|
||||
columns.forEach((column) => {
|
||||
if (column.isColumnGroup) {
|
||||
flattenColumns.push.apply(flattenColumns, column.columns);
|
||||
} else {
|
||||
flattenColumns.push(column);
|
||||
}
|
||||
});
|
||||
|
||||
return flattenColumns;
|
||||
}
|
||||
|
||||
updateColumnsWidth() {
|
||||
if (Vue.prototype.$isServer) return;
|
||||
const fit = this.fit;
|
||||
const bodyWidth = this.table.$el.clientWidth;
|
||||
let bodyMinWidth = 0;
|
||||
|
||||
const flattenColumns = this.getFlattenColumns();
|
||||
let flexColumns = flattenColumns.filter((column) => typeof column.width !== 'number');
|
||||
|
||||
flattenColumns.forEach((column) => { // Clean those columns whose width changed from flex to unflex
|
||||
if (typeof column.width === 'number' && column.realWidth) column.realWidth = null;
|
||||
});
|
||||
|
||||
if (flexColumns.length > 0 && fit) {
|
||||
flattenColumns.forEach((column) => {
|
||||
bodyMinWidth += column.width || column.minWidth || 80;
|
||||
});
|
||||
|
||||
const scrollYWidth = this.scrollY ? this.gutterWidth : 0;
|
||||
|
||||
if (bodyMinWidth <= bodyWidth - scrollYWidth) { // DON'T HAVE SCROLL BAR
|
||||
this.scrollX = false;
|
||||
|
||||
const totalFlexWidth = bodyWidth - scrollYWidth - bodyMinWidth;
|
||||
|
||||
if (flexColumns.length === 1) {
|
||||
flexColumns[0].realWidth = (flexColumns[0].minWidth || 80) + totalFlexWidth;
|
||||
} else {
|
||||
const allColumnsWidth = flexColumns.reduce((prev, column) => prev + (column.minWidth || 80), 0);
|
||||
const flexWidthPerPixel = totalFlexWidth / allColumnsWidth;
|
||||
let noneFirstWidth = 0;
|
||||
|
||||
flexColumns.forEach((column, index) => {
|
||||
if (index === 0) return;
|
||||
const flexWidth = Math.floor((column.minWidth || 80) * flexWidthPerPixel);
|
||||
noneFirstWidth += flexWidth;
|
||||
column.realWidth = (column.minWidth || 80) + flexWidth;
|
||||
});
|
||||
|
||||
flexColumns[0].realWidth = (flexColumns[0].minWidth || 80) + totalFlexWidth - noneFirstWidth;
|
||||
}
|
||||
} else { // HAVE HORIZONTAL SCROLL BAR
|
||||
this.scrollX = true;
|
||||
flexColumns.forEach(function(column) {
|
||||
column.realWidth = column.minWidth;
|
||||
});
|
||||
}
|
||||
|
||||
this.bodyWidth = Math.max(bodyMinWidth, bodyWidth);
|
||||
this.table.resizeState.width = this.bodyWidth;
|
||||
} else {
|
||||
flattenColumns.forEach((column) => {
|
||||
if (!column.width && !column.minWidth) {
|
||||
column.realWidth = 80;
|
||||
} else {
|
||||
column.realWidth = column.width || column.minWidth;
|
||||
}
|
||||
|
||||
bodyMinWidth += column.realWidth;
|
||||
});
|
||||
this.scrollX = bodyMinWidth > bodyWidth;
|
||||
|
||||
this.bodyWidth = bodyMinWidth;
|
||||
}
|
||||
|
||||
const fixedColumns = this.store.states.fixedColumns;
|
||||
|
||||
if (fixedColumns.length > 0) {
|
||||
let fixedWidth = 0;
|
||||
fixedColumns.forEach(function(column) {
|
||||
fixedWidth += column.realWidth || column.width;
|
||||
});
|
||||
|
||||
this.fixedWidth = fixedWidth;
|
||||
}
|
||||
|
||||
const rightFixedColumns = this.store.states.rightFixedColumns;
|
||||
if (rightFixedColumns.length > 0) {
|
||||
let rightFixedWidth = 0;
|
||||
rightFixedColumns.forEach(function(column) {
|
||||
rightFixedWidth += column.realWidth || column.width;
|
||||
});
|
||||
|
||||
this.rightFixedWidth = rightFixedWidth;
|
||||
}
|
||||
|
||||
this.notifyObservers('columns');
|
||||
}
|
||||
|
||||
addObserver(observer) {
|
||||
this.observers.push(observer);
|
||||
}
|
||||
|
||||
removeObserver(observer) {
|
||||
const index = this.observers.indexOf(observer);
|
||||
if (index !== -1) {
|
||||
this.observers.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
notifyObservers(event) {
|
||||
const observers = this.observers;
|
||||
observers.forEach((observer) => {
|
||||
switch (event) {
|
||||
case 'columns':
|
||||
observer.onColumnsChange(this);
|
||||
break;
|
||||
case 'scrollable':
|
||||
observer.onScrollableChange(this);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Table Layout don't have event ${event}.`);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default TableLayout;
|
||||
+647
@@ -0,0 +1,647 @@
|
||||
import Vue from 'vue';
|
||||
import debounce from 'throttle-debounce/debounce';
|
||||
import merge from 'element-ui/src/utils/merge';
|
||||
import { orderBy, getColumnById, getRowIdentity, getColumnByKey } from './util';
|
||||
|
||||
const sortData = (data, states) => {
|
||||
const sortingColumn = states.sortingColumn;
|
||||
if (!sortingColumn || typeof sortingColumn.sortable === 'string') {
|
||||
return data;
|
||||
}
|
||||
return orderBy(data, states.sortProp, states.sortOrder, sortingColumn.sortMethod, sortingColumn.sortBy);
|
||||
};
|
||||
|
||||
const getKeysMap = function(array, rowKey) {
|
||||
const arrayMap = {};
|
||||
(array || []).forEach((row, index) => {
|
||||
arrayMap[getRowIdentity(row, rowKey)] = { row, index };
|
||||
});
|
||||
return arrayMap;
|
||||
};
|
||||
|
||||
const toggleRowSelection = function(states, row, selected) {
|
||||
let changed = false;
|
||||
const selection = states.selection;
|
||||
const index = selection.indexOf(row);
|
||||
if (typeof selected === 'undefined') {
|
||||
if (index === -1) {
|
||||
selection.push(row);
|
||||
changed = true;
|
||||
} else {
|
||||
selection.splice(index, 1);
|
||||
changed = true;
|
||||
}
|
||||
} else {
|
||||
if (selected && index === -1) {
|
||||
selection.push(row);
|
||||
changed = true;
|
||||
} else if (!selected && index > -1) {
|
||||
selection.splice(index, 1);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
};
|
||||
|
||||
const toggleRowExpansion = function(states, row, expanded) {
|
||||
let changed = false;
|
||||
const expandRows = states.expandRows;
|
||||
if (typeof expanded !== 'undefined') {
|
||||
const index = expandRows.indexOf(row);
|
||||
if (expanded) {
|
||||
if (index === -1) {
|
||||
expandRows.push(row);
|
||||
changed = true;
|
||||
}
|
||||
} else {
|
||||
if (index !== -1) {
|
||||
expandRows.splice(index, 1);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const index = expandRows.indexOf(row);
|
||||
if (index === -1) {
|
||||
expandRows.push(row);
|
||||
changed = true;
|
||||
} else {
|
||||
expandRows.splice(index, 1);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
};
|
||||
|
||||
const TableStore = function(table, initialState = {}) {
|
||||
if (!table) {
|
||||
throw new Error('Table is required.');
|
||||
}
|
||||
this.table = table;
|
||||
|
||||
this.states = {
|
||||
rowKey: null,
|
||||
_columns: [],
|
||||
originColumns: [],
|
||||
columns: [],
|
||||
fixedColumns: [],
|
||||
rightFixedColumns: [],
|
||||
leafColumns: [],
|
||||
fixedLeafColumns: [],
|
||||
rightFixedLeafColumns: [],
|
||||
leafColumnsLength: 0,
|
||||
fixedLeafColumnsLength: 0,
|
||||
rightFixedLeafColumnsLength: 0,
|
||||
isComplex: false,
|
||||
filteredData: null,
|
||||
data: null,
|
||||
sortingColumn: null,
|
||||
sortProp: null,
|
||||
sortOrder: null,
|
||||
isAllSelected: false,
|
||||
selection: [],
|
||||
reserveSelection: false,
|
||||
selectable: null,
|
||||
currentRow: null,
|
||||
hoverRow: null,
|
||||
filters: {},
|
||||
expandRows: [],
|
||||
defaultExpandAll: false,
|
||||
selectOnIndeterminate: false
|
||||
};
|
||||
|
||||
this._toggleAllSelection = debounce(10, function(states) {
|
||||
const data = states.data || [];
|
||||
if (data.length === 0) return;
|
||||
const selection = this.states.selection;
|
||||
// when only some rows are selected (but not all), select or deselect all of them
|
||||
// depending on the value of selectOnIndeterminate
|
||||
const value = states.selectOnIndeterminate
|
||||
? !states.isAllSelected
|
||||
: !(states.isAllSelected || selection.length);
|
||||
let selectionChanged = false;
|
||||
data.forEach((item, index) => {
|
||||
if (states.selectable) {
|
||||
if (states.selectable.call(null, item, index) && toggleRowSelection(states, item, value)) {
|
||||
selectionChanged = true;
|
||||
}
|
||||
} else {
|
||||
if (toggleRowSelection(states, item, value)) {
|
||||
selectionChanged = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
const table = this.table;
|
||||
if (selectionChanged) {
|
||||
table.$emit('selection-change', selection ? selection.slice() : []);
|
||||
}
|
||||
table.$emit('select-all', selection);
|
||||
states.isAllSelected = value;
|
||||
});
|
||||
|
||||
for (let prop in initialState) {
|
||||
if (initialState.hasOwnProperty(prop) && this.states.hasOwnProperty(prop)) {
|
||||
this.states[prop] = initialState[prop];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TableStore.prototype.mutations = {
|
||||
setData(states, data) {
|
||||
const dataInstanceChanged = states._data !== data;
|
||||
states._data = data;
|
||||
|
||||
Object.keys(states.filters).forEach((columnId) => {
|
||||
const values = states.filters[columnId];
|
||||
if (!values || values.length === 0) return;
|
||||
const column = getColumnById(this.states, columnId);
|
||||
if (column && column.filterMethod) {
|
||||
data = data.filter((row) => {
|
||||
return values.some(value => column.filterMethod.call(null, value, row, column));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
states.filteredData = data;
|
||||
states.data = sortData((data || []), states);
|
||||
|
||||
this.updateCurrentRow();
|
||||
|
||||
const rowKey = states.rowKey;
|
||||
|
||||
if (!states.reserveSelection) {
|
||||
if (dataInstanceChanged) {
|
||||
this.clearSelection();
|
||||
} else {
|
||||
this.cleanSelection();
|
||||
}
|
||||
this.updateAllSelected();
|
||||
} else {
|
||||
if (rowKey) {
|
||||
const selection = states.selection;
|
||||
const selectedMap = getKeysMap(selection, rowKey);
|
||||
|
||||
states.data.forEach((row) => {
|
||||
const rowId = getRowIdentity(row, rowKey);
|
||||
const rowInfo = selectedMap[rowId];
|
||||
if (rowInfo) {
|
||||
selection[rowInfo.index] = row;
|
||||
}
|
||||
});
|
||||
|
||||
this.updateAllSelected();
|
||||
} else {
|
||||
console.warn('WARN: rowKey is required when reserve-selection is enabled.');
|
||||
}
|
||||
}
|
||||
|
||||
const defaultExpandAll = states.defaultExpandAll;
|
||||
if (defaultExpandAll) {
|
||||
this.states.expandRows = (states.data || []).slice(0);
|
||||
} else if (rowKey) {
|
||||
// update expandRows to new rows according to rowKey
|
||||
const ids = getKeysMap(this.states.expandRows, rowKey);
|
||||
let expandRows = [];
|
||||
for (const row of states.data) {
|
||||
const rowId = getRowIdentity(row, rowKey);
|
||||
if (ids[rowId]) {
|
||||
expandRows.push(row);
|
||||
}
|
||||
}
|
||||
this.states.expandRows = expandRows;
|
||||
} else {
|
||||
// clear the old rows
|
||||
this.states.expandRows = [];
|
||||
}
|
||||
|
||||
Vue.nextTick(() => this.table.updateScrollY());
|
||||
},
|
||||
|
||||
changeSortCondition(states, options) {
|
||||
states.data = sortData((states.filteredData || states._data || []), states);
|
||||
|
||||
if (!options || !options.silent) {
|
||||
this.table.$emit('sort-change', {
|
||||
column: this.states.sortingColumn,
|
||||
prop: this.states.sortProp,
|
||||
order: this.states.sortOrder
|
||||
});
|
||||
}
|
||||
|
||||
Vue.nextTick(() => this.table.updateScrollY());
|
||||
},
|
||||
|
||||
sort(states, options) {
|
||||
const { prop, order } = options;
|
||||
if (prop) {
|
||||
states.sortProp = prop;
|
||||
states.sortOrder = order || 'ascending';
|
||||
Vue.nextTick(() => {
|
||||
for (let i = 0, length = states.columns.length; i < length; i++) {
|
||||
let column = states.columns[i];
|
||||
if (column.property === states.sortProp) {
|
||||
column.order = states.sortOrder;
|
||||
states.sortingColumn = column;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (states.sortingColumn) {
|
||||
this.commit('changeSortCondition');
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
filterChange(states, options) {
|
||||
let { column, values, silent, multi } = options;
|
||||
if (values && !Array.isArray(values)) {
|
||||
values = [values];
|
||||
}
|
||||
const filters = {};
|
||||
|
||||
if (multi) {
|
||||
column.forEach(col => {
|
||||
states.filters[col.id] = values;
|
||||
filters[col.columnKey || col.id] = values;
|
||||
});
|
||||
} else {
|
||||
const prop = column.property;
|
||||
|
||||
if (prop) {
|
||||
states.filters[column.id] = values;
|
||||
filters[column.columnKey || column.id] = values;
|
||||
}
|
||||
}
|
||||
|
||||
let data = states._data;
|
||||
|
||||
Object.keys(states.filters).forEach((columnId) => {
|
||||
const values = states.filters[columnId];
|
||||
if (!values || values.length === 0) return;
|
||||
const column = getColumnById(this.states, columnId);
|
||||
if (column && column.filterMethod) {
|
||||
data = data.filter((row) => {
|
||||
return values.some(value => column.filterMethod.call(null, value, row, column));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
states.filteredData = data;
|
||||
states.data = sortData(data, states);
|
||||
|
||||
if (!silent) {
|
||||
this.table.$emit('filter-change', filters);
|
||||
}
|
||||
|
||||
Vue.nextTick(() => this.table.updateScrollY());
|
||||
},
|
||||
|
||||
insertColumn(states, column, index, parent) {
|
||||
let array = states._columns;
|
||||
if (parent) {
|
||||
array = parent.children;
|
||||
if (!array) array = parent.children = [];
|
||||
}
|
||||
|
||||
if (typeof index !== 'undefined') {
|
||||
array.splice(index, 0, column);
|
||||
} else {
|
||||
array.push(column);
|
||||
}
|
||||
|
||||
if (column.type === 'selection') {
|
||||
states.selectable = column.selectable;
|
||||
states.reserveSelection = column.reserveSelection;
|
||||
}
|
||||
|
||||
if (this.table.$ready) {
|
||||
this.updateColumns(); // hack for dynamics insert column
|
||||
this.scheduleLayout();
|
||||
}
|
||||
},
|
||||
|
||||
removeColumn(states, column, parent) {
|
||||
let array = states._columns;
|
||||
if (parent) {
|
||||
array = parent.children;
|
||||
if (!array) array = parent.children = [];
|
||||
}
|
||||
if (array) {
|
||||
array.splice(array.indexOf(column), 1);
|
||||
}
|
||||
|
||||
if (this.table.$ready) {
|
||||
this.updateColumns(); // hack for dynamics remove column
|
||||
this.scheduleLayout();
|
||||
}
|
||||
},
|
||||
|
||||
setHoverRow(states, row) {
|
||||
states.hoverRow = row;
|
||||
},
|
||||
|
||||
setCurrentRow(states, row) {
|
||||
const oldCurrentRow = states.currentRow;
|
||||
states.currentRow = row;
|
||||
|
||||
if (oldCurrentRow !== row) {
|
||||
this.table.$emit('current-change', row, oldCurrentRow);
|
||||
}
|
||||
},
|
||||
|
||||
rowSelectedChanged(states, row) {
|
||||
const changed = toggleRowSelection(states, row);
|
||||
const selection = states.selection;
|
||||
|
||||
if (changed) {
|
||||
const table = this.table;
|
||||
table.$emit('selection-change', selection ? selection.slice() : []);
|
||||
table.$emit('select', selection, row);
|
||||
}
|
||||
|
||||
this.updateAllSelected();
|
||||
},
|
||||
|
||||
toggleAllSelection(state) {
|
||||
this._toggleAllSelection(state);
|
||||
}
|
||||
};
|
||||
|
||||
const doFlattenColumns = (columns) => {
|
||||
const result = [];
|
||||
columns.forEach((column) => {
|
||||
if (column.children) {
|
||||
result.push.apply(result, doFlattenColumns(column.children));
|
||||
} else {
|
||||
result.push(column);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
TableStore.prototype.updateColumns = function() {
|
||||
const states = this.states;
|
||||
const _columns = states._columns || [];
|
||||
states.fixedColumns = _columns.filter((column) => column.fixed === true || column.fixed === 'left');
|
||||
states.rightFixedColumns = _columns.filter((column) => column.fixed === 'right');
|
||||
|
||||
if (states.fixedColumns.length > 0 && _columns[0] && _columns[0].type === 'selection' && !_columns[0].fixed) {
|
||||
_columns[0].fixed = true;
|
||||
states.fixedColumns.unshift(_columns[0]);
|
||||
}
|
||||
|
||||
const notFixedColumns = _columns.filter(column => !column.fixed);
|
||||
states.originColumns = [].concat(states.fixedColumns).concat(notFixedColumns).concat(states.rightFixedColumns);
|
||||
|
||||
const leafColumns = doFlattenColumns(notFixedColumns);
|
||||
const fixedLeafColumns = doFlattenColumns(states.fixedColumns);
|
||||
const rightFixedLeafColumns = doFlattenColumns(states.rightFixedColumns);
|
||||
|
||||
states.leafColumnsLength = leafColumns.length;
|
||||
states.fixedLeafColumnsLength = fixedLeafColumns.length;
|
||||
states.rightFixedLeafColumnsLength = rightFixedLeafColumns.length;
|
||||
|
||||
states.columns = [].concat(fixedLeafColumns).concat(leafColumns).concat(rightFixedLeafColumns);
|
||||
states.isComplex = states.fixedColumns.length > 0 || states.rightFixedColumns.length > 0;
|
||||
};
|
||||
|
||||
TableStore.prototype.isSelected = function(row) {
|
||||
return (this.states.selection || []).indexOf(row) > -1;
|
||||
};
|
||||
|
||||
TableStore.prototype.clearSelection = function() {
|
||||
const states = this.states;
|
||||
states.isAllSelected = false;
|
||||
const oldSelection = states.selection;
|
||||
if (states.selection.length) {
|
||||
states.selection = [];
|
||||
}
|
||||
if (oldSelection.length > 0) {
|
||||
this.table.$emit('selection-change', states.selection ? states.selection.slice() : []);
|
||||
}
|
||||
};
|
||||
|
||||
TableStore.prototype.setExpandRowKeys = function(rowKeys) {
|
||||
const expandRows = [];
|
||||
const data = this.states.data;
|
||||
const rowKey = this.states.rowKey;
|
||||
if (!rowKey) throw new Error('[Table] prop row-key should not be empty.');
|
||||
const keysMap = getKeysMap(data, rowKey);
|
||||
rowKeys.forEach((key) => {
|
||||
const info = keysMap[key];
|
||||
if (info) {
|
||||
expandRows.push(info.row);
|
||||
}
|
||||
});
|
||||
|
||||
this.states.expandRows = expandRows;
|
||||
};
|
||||
|
||||
TableStore.prototype.toggleRowSelection = function(row, selected) {
|
||||
const changed = toggleRowSelection(this.states, row, selected);
|
||||
if (changed) {
|
||||
this.table.$emit('selection-change', this.states.selection ? this.states.selection.slice() : []);
|
||||
}
|
||||
};
|
||||
|
||||
TableStore.prototype.toggleRowExpansion = function(row, expanded) {
|
||||
const changed = toggleRowExpansion(this.states, row, expanded);
|
||||
if (changed) {
|
||||
this.table.$emit('expand-change', row, this.states.expandRows);
|
||||
this.scheduleLayout();
|
||||
}
|
||||
};
|
||||
|
||||
TableStore.prototype.isRowExpanded = function(row) {
|
||||
const { expandRows = [], rowKey } = this.states;
|
||||
if (rowKey) {
|
||||
const expandMap = getKeysMap(expandRows, rowKey);
|
||||
return !!expandMap[getRowIdentity(row, rowKey)];
|
||||
}
|
||||
return expandRows.indexOf(row) !== -1;
|
||||
};
|
||||
|
||||
TableStore.prototype.cleanSelection = function() {
|
||||
const selection = this.states.selection || [];
|
||||
const data = this.states.data;
|
||||
const rowKey = this.states.rowKey;
|
||||
let deleted;
|
||||
if (rowKey) {
|
||||
deleted = [];
|
||||
const selectedMap = getKeysMap(selection, rowKey);
|
||||
const dataMap = getKeysMap(data, rowKey);
|
||||
for (let key in selectedMap) {
|
||||
if (selectedMap.hasOwnProperty(key) && !dataMap[key]) {
|
||||
deleted.push(selectedMap[key].row);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
deleted = selection.filter((item) => {
|
||||
return data.indexOf(item) === -1;
|
||||
});
|
||||
}
|
||||
|
||||
deleted.forEach((deletedItem) => {
|
||||
selection.splice(selection.indexOf(deletedItem), 1);
|
||||
});
|
||||
|
||||
if (deleted.length) {
|
||||
this.table.$emit('selection-change', selection ? selection.slice() : []);
|
||||
}
|
||||
};
|
||||
|
||||
TableStore.prototype.clearFilter = function(columnKeys) {
|
||||
const states = this.states;
|
||||
const { tableHeader, fixedTableHeader, rightFixedTableHeader } = this.table.$refs;
|
||||
let panels = {};
|
||||
|
||||
if (tableHeader) panels = merge(panels, tableHeader.filterPanels);
|
||||
if (fixedTableHeader) panels = merge(panels, fixedTableHeader.filterPanels);
|
||||
if (rightFixedTableHeader) panels = merge(panels, rightFixedTableHeader.filterPanels);
|
||||
|
||||
const keys = Object.keys(panels);
|
||||
if (!keys.length) return;
|
||||
|
||||
if (typeof columnKeys === 'string') {
|
||||
columnKeys = [columnKeys];
|
||||
}
|
||||
if (Array.isArray(columnKeys)) {
|
||||
const columns = columnKeys.map(key => getColumnByKey(states, key));
|
||||
keys.forEach(key => {
|
||||
const column = columns.find(col => col.id === key);
|
||||
if (column) {
|
||||
panels[key].filteredValue = [];
|
||||
}
|
||||
});
|
||||
this.commit('filterChange', {
|
||||
column: columns,
|
||||
value: [],
|
||||
silent: true,
|
||||
multi: true
|
||||
});
|
||||
} else {
|
||||
keys.forEach(key => {
|
||||
panels[key].filteredValue = [];
|
||||
});
|
||||
|
||||
states.filters = {};
|
||||
|
||||
this.commit('filterChange', {
|
||||
column: {},
|
||||
values: [],
|
||||
silent: true
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
TableStore.prototype.clearSort = function() {
|
||||
const states = this.states;
|
||||
if (!states.sortingColumn) return;
|
||||
states.sortingColumn.order = null;
|
||||
states.sortProp = null;
|
||||
states.sortOrder = null;
|
||||
|
||||
this.commit('changeSortCondition', {
|
||||
silent: true
|
||||
});
|
||||
};
|
||||
|
||||
TableStore.prototype.updateAllSelected = function() {
|
||||
const states = this.states;
|
||||
const { selection, rowKey, selectable, data } = states;
|
||||
if (!data || data.length === 0) {
|
||||
states.isAllSelected = false;
|
||||
return;
|
||||
}
|
||||
|
||||
let selectedMap;
|
||||
if (rowKey) {
|
||||
selectedMap = getKeysMap(states.selection, rowKey);
|
||||
}
|
||||
|
||||
const isSelected = function(row) {
|
||||
if (selectedMap) {
|
||||
return !!selectedMap[getRowIdentity(row, rowKey)];
|
||||
} else {
|
||||
return selection.indexOf(row) !== -1;
|
||||
}
|
||||
};
|
||||
|
||||
let isAllSelected = true;
|
||||
let selectedCount = 0;
|
||||
for (let i = 0, j = data.length; i < j; i++) {
|
||||
const item = data[i];
|
||||
const isRowSelectable = selectable && selectable.call(null, item, i);
|
||||
if (!isSelected(item)) {
|
||||
if (!selectable || isRowSelectable) {
|
||||
isAllSelected = false;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
selectedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedCount === 0) isAllSelected = false;
|
||||
|
||||
states.isAllSelected = isAllSelected;
|
||||
};
|
||||
|
||||
TableStore.prototype.scheduleLayout = function(updateColumns) {
|
||||
if (updateColumns) {
|
||||
this.updateColumns();
|
||||
}
|
||||
this.table.debouncedUpdateLayout();
|
||||
};
|
||||
|
||||
TableStore.prototype.setCurrentRowKey = function(key) {
|
||||
const states = this.states;
|
||||
const rowKey = states.rowKey;
|
||||
if (!rowKey) throw new Error('[Table] row-key should not be empty.');
|
||||
const data = states.data || [];
|
||||
const keysMap = getKeysMap(data, rowKey);
|
||||
const info = keysMap[key];
|
||||
states.currentRow = info ? info.row : null;
|
||||
};
|
||||
|
||||
TableStore.prototype.updateCurrentRow = function() {
|
||||
const states = this.states;
|
||||
const table = this.table;
|
||||
const data = states.data || [];
|
||||
const oldCurrentRow = states.currentRow;
|
||||
|
||||
if (data.indexOf(oldCurrentRow) === -1) {
|
||||
if (states.rowKey && oldCurrentRow) {
|
||||
let newCurrentRow = null;
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
const item = data[i];
|
||||
if (item && item[states.rowKey] === oldCurrentRow[states.rowKey]) {
|
||||
newCurrentRow = item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (newCurrentRow) {
|
||||
states.currentRow = newCurrentRow;
|
||||
return;
|
||||
}
|
||||
}
|
||||
states.currentRow = null;
|
||||
|
||||
if (states.currentRow !== oldCurrentRow) {
|
||||
table.$emit('current-change', null, oldCurrentRow);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TableStore.prototype.commit = function(name, ...args) {
|
||||
const mutations = this.mutations;
|
||||
if (mutations[name]) {
|
||||
mutations[name].apply(this, [this.states].concat(args));
|
||||
} else {
|
||||
throw new Error(`Action not found: ${name}`);
|
||||
}
|
||||
};
|
||||
|
||||
export default TableStore;
|
||||
+660
@@ -0,0 +1,660 @@
|
||||
<template>
|
||||
<div class="el-table"
|
||||
:class="[{
|
||||
'el-table--fit': fit,
|
||||
'el-table--striped': stripe,
|
||||
'el-table--border': border || isGroup,
|
||||
'el-table--hidden': isHidden,
|
||||
'el-table--group': isGroup,
|
||||
'el-table--fluid-height': maxHeight,
|
||||
'el-table--scrollable-x': layout.scrollX,
|
||||
'el-table--scrollable-y': layout.scrollY,
|
||||
'el-table--enable-row-hover': !store.states.isComplex,
|
||||
'el-table--enable-row-transition': (store.states.data || []).length !== 0 && (store.states.data || []).length < 100
|
||||
}, tableSize ? `el-table--${ tableSize }` : '']"
|
||||
@mouseleave="handleMouseLeave($event)">
|
||||
<div class="hidden-columns" ref="hiddenColumns"><slot></slot></div>
|
||||
<div
|
||||
v-if="showHeader"
|
||||
v-mousewheel="handleHeaderFooterMousewheel"
|
||||
class="el-table__header-wrapper"
|
||||
ref="headerWrapper">
|
||||
<table-header
|
||||
ref="tableHeader"
|
||||
:store="store"
|
||||
:border="border"
|
||||
:default-sort="defaultSort"
|
||||
:style="{
|
||||
width: layout.bodyWidth ? layout.bodyWidth + 'px' : ''
|
||||
}">
|
||||
</table-header>
|
||||
</div>
|
||||
<div
|
||||
class="el-table__body-wrapper"
|
||||
ref="bodyWrapper"
|
||||
:class="[layout.scrollX ? `is-scrolling-${scrollPosition}` : 'is-scrolling-none']"
|
||||
:style="[bodyHeight]">
|
||||
<table-body
|
||||
:context="context"
|
||||
:store="store"
|
||||
:stripe="stripe"
|
||||
:row-class-name="rowClassName"
|
||||
:row-style="rowStyle"
|
||||
:highlight="highlightCurrentRow"
|
||||
:style="{
|
||||
width: bodyWidth
|
||||
}">
|
||||
</table-body>
|
||||
<div
|
||||
v-if="!data || data.length === 0"
|
||||
class="el-table__empty-block"
|
||||
ref="emptyBlock"
|
||||
:style="{
|
||||
width: bodyWidth
|
||||
}">
|
||||
<span class="el-table__empty-text">
|
||||
<slot name="empty">{{ emptyText || t('el.table.emptyText') }}</slot>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="$slots.append"
|
||||
class="el-table__append-wrapper"
|
||||
ref="appendWrapper">
|
||||
<slot name="append"></slot>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="showSummary"
|
||||
v-show="data && data.length > 0"
|
||||
v-mousewheel="handleHeaderFooterMousewheel"
|
||||
class="el-table__footer-wrapper"
|
||||
ref="footerWrapper">
|
||||
<table-footer
|
||||
:store="store"
|
||||
:border="border"
|
||||
:sum-text="sumText || t('el.table.sumText')"
|
||||
:summary-method="summaryMethod"
|
||||
:default-sort="defaultSort"
|
||||
:style="{
|
||||
width: layout.bodyWidth ? layout.bodyWidth + 'px' : ''
|
||||
}">
|
||||
</table-footer>
|
||||
</div>
|
||||
<div
|
||||
v-if="fixedColumns.length > 0"
|
||||
v-mousewheel="handleFixedMousewheel"
|
||||
class="el-table__fixed"
|
||||
ref="fixedWrapper"
|
||||
:style="[{
|
||||
width: layout.fixedWidth ? layout.fixedWidth + 'px' : ''
|
||||
},
|
||||
fixedHeight]">
|
||||
<div
|
||||
v-if="showHeader"
|
||||
class="el-table__fixed-header-wrapper"
|
||||
ref="fixedHeaderWrapper" >
|
||||
<table-header
|
||||
ref="fixedTableHeader"
|
||||
fixed="left"
|
||||
:border="border"
|
||||
:store="store"
|
||||
:style="{
|
||||
width: bodyWidth
|
||||
}"></table-header>
|
||||
</div>
|
||||
<div
|
||||
class="el-table__fixed-body-wrapper"
|
||||
ref="fixedBodyWrapper"
|
||||
:style="[{
|
||||
top: layout.headerHeight + 'px'
|
||||
},
|
||||
fixedBodyHeight]">
|
||||
<table-body
|
||||
fixed="left"
|
||||
:store="store"
|
||||
:stripe="stripe"
|
||||
:highlight="highlightCurrentRow"
|
||||
:row-class-name="rowClassName"
|
||||
:row-style="rowStyle"
|
||||
:style="{
|
||||
width: bodyWidth
|
||||
}">
|
||||
</table-body>
|
||||
<div
|
||||
v-if="$slots.append"
|
||||
class="el-table__append-gutter"
|
||||
:style="{
|
||||
height: layout.appendHeight + 'px'
|
||||
}"></div>
|
||||
</div>
|
||||
<div
|
||||
v-if="showSummary"
|
||||
v-show="data && data.length > 0"
|
||||
class="el-table__fixed-footer-wrapper"
|
||||
ref="fixedFooterWrapper">
|
||||
<table-footer
|
||||
fixed="left"
|
||||
:border="border"
|
||||
:sum-text="sumText || t('el.table.sumText')"
|
||||
:summary-method="summaryMethod"
|
||||
:store="store"
|
||||
:style="{
|
||||
width: bodyWidth
|
||||
}"></table-footer>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="rightFixedColumns.length > 0"
|
||||
v-mousewheel="handleFixedMousewheel"
|
||||
class="el-table__fixed-right"
|
||||
ref="rightFixedWrapper"
|
||||
:style="[{
|
||||
width: layout.rightFixedWidth ? layout.rightFixedWidth + 'px' : '',
|
||||
right: layout.scrollY ? (border ? layout.gutterWidth : (layout.gutterWidth || 0)) + 'px' : ''
|
||||
},
|
||||
fixedHeight]">
|
||||
<div v-if="showHeader"
|
||||
class="el-table__fixed-header-wrapper"
|
||||
ref="rightFixedHeaderWrapper">
|
||||
<table-header
|
||||
ref="rightFixedTableHeader"
|
||||
fixed="right"
|
||||
:border="border"
|
||||
:store="store"
|
||||
:style="{
|
||||
width: bodyWidth
|
||||
}"></table-header>
|
||||
</div>
|
||||
<div
|
||||
class="el-table__fixed-body-wrapper"
|
||||
ref="rightFixedBodyWrapper"
|
||||
:style="[{
|
||||
top: layout.headerHeight + 'px'
|
||||
},
|
||||
fixedBodyHeight]">
|
||||
<table-body
|
||||
fixed="right"
|
||||
:store="store"
|
||||
:stripe="stripe"
|
||||
:row-class-name="rowClassName"
|
||||
:row-style="rowStyle"
|
||||
:highlight="highlightCurrentRow"
|
||||
:style="{
|
||||
width: bodyWidth
|
||||
}">
|
||||
</table-body>
|
||||
</div>
|
||||
<div
|
||||
v-if="showSummary"
|
||||
v-show="data && data.length > 0"
|
||||
class="el-table__fixed-footer-wrapper"
|
||||
ref="rightFixedFooterWrapper">
|
||||
<table-footer
|
||||
fixed="right"
|
||||
:border="border"
|
||||
:sum-text="sumText || t('el.table.sumText')"
|
||||
:summary-method="summaryMethod"
|
||||
:store="store"
|
||||
:style="{
|
||||
width: bodyWidth
|
||||
}"></table-footer>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="rightFixedColumns.length > 0"
|
||||
class="el-table__fixed-right-patch"
|
||||
ref="rightFixedPatch"
|
||||
:style="{
|
||||
width: layout.scrollY ? layout.gutterWidth + 'px' : '0',
|
||||
height: layout.headerHeight + 'px'
|
||||
}"></div>
|
||||
<div class="el-table__column-resize-proxy" ref="resizeProxy" v-show="resizeProxyVisible"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script type="text/babel">
|
||||
import ElCheckbox from 'element-ui/packages/checkbox';
|
||||
import debounce from 'throttle-debounce/debounce';
|
||||
import { addResizeListener, removeResizeListener } from 'element-ui/src/utils/resize-event';
|
||||
import Mousewheel from 'element-ui/src/directives/mousewheel';
|
||||
import Locale from 'element-ui/src/mixins/locale';
|
||||
import Migrating from 'element-ui/src/mixins/migrating';
|
||||
import TableStore from './table-store';
|
||||
import TableLayout from './table-layout';
|
||||
import TableBody from './table-body';
|
||||
import TableHeader from './table-header';
|
||||
import TableFooter from './table-footer';
|
||||
|
||||
let tableIdSeed = 1;
|
||||
|
||||
export default {
|
||||
name: 'ElTable',
|
||||
|
||||
mixins: [Locale, Migrating],
|
||||
|
||||
directives: {
|
||||
Mousewheel
|
||||
},
|
||||
|
||||
props: {
|
||||
data: {
|
||||
type: Array,
|
||||
default: function() {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
|
||||
size: String,
|
||||
|
||||
width: [String, Number],
|
||||
|
||||
height: [String, Number],
|
||||
|
||||
maxHeight: [String, Number],
|
||||
|
||||
fit: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
|
||||
stripe: Boolean,
|
||||
|
||||
border: Boolean,
|
||||
|
||||
rowKey: [String, Function],
|
||||
|
||||
context: {},
|
||||
|
||||
showHeader: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
|
||||
showSummary: Boolean,
|
||||
|
||||
sumText: String,
|
||||
|
||||
summaryMethod: Function,
|
||||
|
||||
rowClassName: [String, Function],
|
||||
|
||||
rowStyle: [Object, Function],
|
||||
|
||||
cellClassName: [String, Function],
|
||||
|
||||
cellStyle: [Object, Function],
|
||||
|
||||
headerRowClassName: [String, Function],
|
||||
|
||||
headerRowStyle: [Object, Function],
|
||||
|
||||
headerCellClassName: [String, Function],
|
||||
|
||||
headerCellStyle: [Object, Function],
|
||||
|
||||
highlightCurrentRow: Boolean,
|
||||
|
||||
currentRowKey: [String, Number],
|
||||
|
||||
emptyText: String,
|
||||
|
||||
expandRowKeys: Array,
|
||||
|
||||
defaultExpandAll: Boolean,
|
||||
|
||||
defaultSort: Object,
|
||||
|
||||
tooltipEffect: String,
|
||||
|
||||
spanMethod: Function,
|
||||
|
||||
selectOnIndeterminate: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
|
||||
components: {
|
||||
TableHeader,
|
||||
TableFooter,
|
||||
TableBody,
|
||||
ElCheckbox
|
||||
},
|
||||
|
||||
methods: {
|
||||
getMigratingConfig() {
|
||||
return {
|
||||
events: {
|
||||
expand: 'expand is renamed to expand-change'
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
setCurrentRow(row) {
|
||||
this.store.commit('setCurrentRow', row);
|
||||
},
|
||||
|
||||
toggleRowSelection(row, selected) {
|
||||
this.store.toggleRowSelection(row, selected);
|
||||
this.store.updateAllSelected();
|
||||
},
|
||||
|
||||
toggleRowExpansion(row, expanded) {
|
||||
this.store.toggleRowExpansion(row, expanded);
|
||||
},
|
||||
|
||||
clearSelection() {
|
||||
this.store.clearSelection();
|
||||
},
|
||||
|
||||
clearFilter(columnKeys) {
|
||||
this.store.clearFilter(columnKeys);
|
||||
},
|
||||
|
||||
clearSort() {
|
||||
this.store.clearSort();
|
||||
},
|
||||
|
||||
handleMouseLeave() {
|
||||
this.store.commit('setHoverRow', null);
|
||||
if (this.hoverState) this.hoverState = null;
|
||||
},
|
||||
|
||||
updateScrollY() {
|
||||
this.layout.updateScrollY();
|
||||
this.layout.updateColumnsWidth();
|
||||
},
|
||||
|
||||
handleFixedMousewheel(event, data) {
|
||||
const bodyWrapper = this.bodyWrapper;
|
||||
if (Math.abs(data.spinY) > 0) {
|
||||
const currentScrollTop = bodyWrapper.scrollTop;
|
||||
if (data.pixelY < 0 && currentScrollTop !== 0) {
|
||||
event.preventDefault();
|
||||
}
|
||||
if (data.pixelY > 0 && bodyWrapper.scrollHeight - bodyWrapper.clientHeight > currentScrollTop) {
|
||||
event.preventDefault();
|
||||
}
|
||||
bodyWrapper.scrollTop += Math.ceil(data.pixelY / 5);
|
||||
} else {
|
||||
bodyWrapper.scrollLeft += Math.ceil(data.pixelX / 5);
|
||||
}
|
||||
},
|
||||
|
||||
handleHeaderFooterMousewheel(event, data) {
|
||||
const { pixelX, pixelY } = data;
|
||||
if (Math.abs(pixelX) >= Math.abs(pixelY)) {
|
||||
event.preventDefault();
|
||||
this.bodyWrapper.scrollLeft += data.pixelX / 5;
|
||||
}
|
||||
},
|
||||
|
||||
bindEvents() {
|
||||
const { headerWrapper, footerWrapper } = this.$refs;
|
||||
const refs = this.$refs;
|
||||
let self = this;
|
||||
|
||||
this.bodyWrapper.addEventListener('scroll', function() {
|
||||
if (headerWrapper) headerWrapper.scrollLeft = this.scrollLeft;
|
||||
if (footerWrapper) footerWrapper.scrollLeft = this.scrollLeft;
|
||||
if (refs.fixedBodyWrapper) refs.fixedBodyWrapper.scrollTop = this.scrollTop;
|
||||
if (refs.rightFixedBodyWrapper) refs.rightFixedBodyWrapper.scrollTop = this.scrollTop;
|
||||
const maxScrollLeftPosition = this.scrollWidth - this.offsetWidth - 1;
|
||||
const scrollLeft = this.scrollLeft;
|
||||
if (scrollLeft >= maxScrollLeftPosition) {
|
||||
self.scrollPosition = 'right';
|
||||
} else if (scrollLeft === 0) {
|
||||
self.scrollPosition = 'left';
|
||||
} else {
|
||||
self.scrollPosition = 'middle';
|
||||
}
|
||||
});
|
||||
|
||||
if (this.fit) {
|
||||
addResizeListener(this.$el, this.resizeListener);
|
||||
}
|
||||
},
|
||||
|
||||
resizeListener() {
|
||||
if (!this.$ready) return;
|
||||
let shouldUpdateLayout = false;
|
||||
const el = this.$el;
|
||||
const { width: oldWidth, height: oldHeight } = this.resizeState;
|
||||
|
||||
const width = el.offsetWidth;
|
||||
if (oldWidth !== width) {
|
||||
shouldUpdateLayout = true;
|
||||
}
|
||||
|
||||
const height = el.offsetHeight;
|
||||
if ((this.height || this.shouldUpdateHeight) && oldHeight !== height) {
|
||||
shouldUpdateLayout = true;
|
||||
}
|
||||
|
||||
if (shouldUpdateLayout) {
|
||||
this.resizeState.width = width;
|
||||
this.resizeState.height = height;
|
||||
this.doLayout();
|
||||
}
|
||||
},
|
||||
|
||||
doLayout() {
|
||||
this.layout.updateColumnsWidth();
|
||||
if (this.shouldUpdateHeight) {
|
||||
this.layout.updateElsHeight();
|
||||
}
|
||||
},
|
||||
|
||||
sort(prop, order) {
|
||||
this.store.commit('sort', { prop, order });
|
||||
},
|
||||
|
||||
toggleAllSelection() {
|
||||
this.store.commit('toggleAllSelection');
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
this.tableId = 'el-table_' + tableIdSeed++;
|
||||
this.debouncedUpdateLayout = debounce(50, () => this.doLayout());
|
||||
},
|
||||
|
||||
computed: {
|
||||
tableSize() {
|
||||
return this.size || (this.$ELEMENT || {}).size;
|
||||
},
|
||||
|
||||
bodyWrapper() {
|
||||
return this.$refs.bodyWrapper;
|
||||
},
|
||||
|
||||
shouldUpdateHeight() {
|
||||
return this.height ||
|
||||
this.maxHeight ||
|
||||
this.fixedColumns.length > 0 ||
|
||||
this.rightFixedColumns.length > 0;
|
||||
},
|
||||
|
||||
selection() {
|
||||
return this.store.states.selection;
|
||||
},
|
||||
|
||||
columns() {
|
||||
return this.store.states.columns;
|
||||
},
|
||||
|
||||
tableData() {
|
||||
return this.store.states.data;
|
||||
},
|
||||
|
||||
fixedColumns() {
|
||||
return this.store.states.fixedColumns;
|
||||
},
|
||||
|
||||
rightFixedColumns() {
|
||||
return this.store.states.rightFixedColumns;
|
||||
},
|
||||
|
||||
bodyWidth() {
|
||||
const { bodyWidth, scrollY, gutterWidth } = this.layout;
|
||||
return bodyWidth ? bodyWidth - (scrollY ? gutterWidth : 0) + 'px' : '';
|
||||
},
|
||||
|
||||
bodyHeight() {
|
||||
if (this.height) {
|
||||
return {
|
||||
height: this.layout.bodyHeight ? this.layout.bodyHeight + 'px' : ''
|
||||
};
|
||||
} else if (this.maxHeight) {
|
||||
return {
|
||||
'max-height': (this.showHeader
|
||||
? this.maxHeight - this.layout.headerHeight - this.layout.footerHeight
|
||||
: this.maxHeight - this.layout.footerHeight) + 'px'
|
||||
};
|
||||
}
|
||||
return {};
|
||||
},
|
||||
|
||||
fixedBodyHeight() {
|
||||
if (this.height) {
|
||||
return {
|
||||
height: this.layout.fixedBodyHeight ? this.layout.fixedBodyHeight + 'px' : ''
|
||||
};
|
||||
} else if (this.maxHeight) {
|
||||
let maxHeight = this.layout.scrollX ? this.maxHeight - this.layout.gutterWidth : this.maxHeight;
|
||||
|
||||
if (this.showHeader) {
|
||||
maxHeight -= this.layout.headerHeight;
|
||||
}
|
||||
|
||||
maxHeight -= this.layout.footerHeight;
|
||||
|
||||
return {
|
||||
'max-height': maxHeight + 'px'
|
||||
};
|
||||
}
|
||||
|
||||
return {};
|
||||
},
|
||||
|
||||
fixedHeight() {
|
||||
if (this.maxHeight) {
|
||||
if (this.showSummary) {
|
||||
return {
|
||||
bottom: 0
|
||||
};
|
||||
}
|
||||
return {
|
||||
bottom: (this.layout.scrollX && this.data.length) ? this.layout.gutterWidth + 'px' : ''
|
||||
};
|
||||
} else {
|
||||
if (this.showSummary) {
|
||||
return {
|
||||
height: this.layout.tableHeight ? this.layout.tableHeight + 'px' : ''
|
||||
};
|
||||
}
|
||||
return {
|
||||
height: this.layout.viewportHeight ? this.layout.viewportHeight + 'px' : ''
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
height: {
|
||||
immediate: true,
|
||||
handler(value) {
|
||||
this.layout.setHeight(value);
|
||||
}
|
||||
},
|
||||
|
||||
maxHeight: {
|
||||
immediate: true,
|
||||
handler(value) {
|
||||
this.layout.setMaxHeight(value);
|
||||
}
|
||||
},
|
||||
|
||||
currentRowKey(newVal) {
|
||||
this.store.setCurrentRowKey(newVal);
|
||||
},
|
||||
|
||||
data: {
|
||||
immediate: true,
|
||||
handler(value) {
|
||||
this.store.commit('setData', value);
|
||||
if (this.$ready) {
|
||||
this.$nextTick(() => {
|
||||
this.doLayout();
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
expandRowKeys: {
|
||||
immediate: true,
|
||||
handler(newVal) {
|
||||
if (newVal) {
|
||||
this.store.setExpandRowKeys(newVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
destroyed() {
|
||||
if (this.resizeListener) removeResizeListener(this.$el, this.resizeListener);
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.bindEvents();
|
||||
this.store.updateColumns();
|
||||
this.doLayout();
|
||||
|
||||
this.resizeState = {
|
||||
width: this.$el.offsetWidth,
|
||||
height: this.$el.offsetHeight
|
||||
};
|
||||
|
||||
// init filters
|
||||
this.store.states.columns.forEach(column => {
|
||||
if (column.filteredValue && column.filteredValue.length) {
|
||||
this.store.commit('filterChange', {
|
||||
column,
|
||||
values: column.filteredValue,
|
||||
silent: true
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
this.$ready = true;
|
||||
},
|
||||
|
||||
data() {
|
||||
const store = new TableStore(this, {
|
||||
rowKey: this.rowKey,
|
||||
defaultExpandAll: this.defaultExpandAll,
|
||||
selectOnIndeterminate: this.selectOnIndeterminate
|
||||
});
|
||||
const layout = new TableLayout({
|
||||
store,
|
||||
table: this,
|
||||
fit: this.fit,
|
||||
showHeader: this.showHeader
|
||||
});
|
||||
return {
|
||||
layout,
|
||||
store,
|
||||
isHidden: false,
|
||||
renderExpanded: null,
|
||||
resizeProxyVisible: false,
|
||||
resizeState: {
|
||||
width: null,
|
||||
height: null
|
||||
},
|
||||
// 是否拥有多级表头
|
||||
isGroup: false,
|
||||
scrollPosition: 'left'
|
||||
};
|
||||
}
|
||||
};
|
||||
</script>
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
import { getValueByPath } from 'element-ui/src/utils/util';
|
||||
|
||||
export const getCell = function(event) {
|
||||
let cell = event.target;
|
||||
|
||||
while (cell && cell.tagName.toUpperCase() !== 'HTML') {
|
||||
if (cell.tagName.toUpperCase() === 'TD') {
|
||||
return cell;
|
||||
}
|
||||
cell = cell.parentNode;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const isObject = function(obj) {
|
||||
return obj !== null && typeof obj === 'object';
|
||||
};
|
||||
|
||||
export const orderBy = function(array, sortKey, reverse, sortMethod, sortBy) {
|
||||
if (!sortKey && !sortMethod && (!sortBy || Array.isArray(sortBy) && !sortBy.length)) {
|
||||
return array;
|
||||
}
|
||||
if (typeof reverse === 'string') {
|
||||
reverse = reverse === 'descending' ? -1 : 1;
|
||||
} else {
|
||||
reverse = (reverse && reverse < 0) ? -1 : 1;
|
||||
}
|
||||
const getKey = sortMethod ? null : function(value, index) {
|
||||
if (sortBy) {
|
||||
if (!Array.isArray(sortBy)) {
|
||||
sortBy = [sortBy];
|
||||
}
|
||||
return sortBy.map(function(by) {
|
||||
if (typeof by === 'string') {
|
||||
return getValueByPath(value, by);
|
||||
} else {
|
||||
return by(value, index, array);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (sortKey !== '$key') {
|
||||
if (isObject(value) && '$value' in value) value = value.$value;
|
||||
}
|
||||
return [isObject(value) ? getValueByPath(value, sortKey) : value];
|
||||
};
|
||||
const compare = function(a, b) {
|
||||
if (sortMethod) {
|
||||
return sortMethod(a.value, b.value);
|
||||
}
|
||||
for (let i = 0, len = a.key.length; i < len; i++) {
|
||||
if (a.key[i] < b.key[i]) {
|
||||
return -1;
|
||||
}
|
||||
if (a.key[i] > b.key[i]) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
return array.map(function(value, index) {
|
||||
return {
|
||||
value: value,
|
||||
index: index,
|
||||
key: getKey ? getKey(value, index) : null
|
||||
};
|
||||
}).sort(function(a, b) {
|
||||
let order = compare(a, b);
|
||||
if (!order) {
|
||||
// make stable https://en.wikipedia.org/wiki/Sorting_algorithm#Stability
|
||||
order = a.index - b.index;
|
||||
}
|
||||
return order * reverse;
|
||||
}).map(item => item.value);
|
||||
};
|
||||
|
||||
export const getColumnById = function(table, columnId) {
|
||||
let column = null;
|
||||
table.columns.forEach(function(item) {
|
||||
if (item.id === columnId) {
|
||||
column = item;
|
||||
}
|
||||
});
|
||||
return column;
|
||||
};
|
||||
|
||||
export const getColumnByKey = function(table, columnKey) {
|
||||
let column = null;
|
||||
for (let i = 0; i < table.columns.length; i++) {
|
||||
const item = table.columns[i];
|
||||
if (item.columnKey === columnKey) {
|
||||
column = item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return column;
|
||||
};
|
||||
|
||||
export const getColumnByCell = function(table, cell) {
|
||||
const matches = (cell.className || '').match(/el-table_[^\s]+/gm);
|
||||
if (matches) {
|
||||
return getColumnById(table, matches[0]);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export const getRowIdentity = (row, rowKey) => {
|
||||
if (!row) throw new Error('row is required when get row identity');
|
||||
if (typeof rowKey === 'string') {
|
||||
if (rowKey.indexOf('.') < 0) {
|
||||
return row[rowKey];
|
||||
}
|
||||
let key = rowKey.split('.');
|
||||
let current = row;
|
||||
for (let i = 0; i < key.length; i++) {
|
||||
current = current[key[i]];
|
||||
}
|
||||
return current;
|
||||
} else if (typeof rowKey === 'function') {
|
||||
return rowKey.call(null, row);
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user