element/packages/table/src/table-column.js

495 lines
12 KiB
JavaScript
Raw Normal View History

2016-10-25 13:35:41 +00:00
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';
2016-08-16 08:07:18 +00:00
let columnIdSeed = 1;
const defaults = {
default: {
2016-10-27 17:24:13 +00:00
order: ''
2016-08-16 08:07:18 +00:00
},
selection: {
width: 48,
minWidth: 48,
realWidth: 48,
order: '',
className: 'el-table-column--selection'
2016-08-16 08:07:18 +00:00
},
2016-11-12 15:08:17 +00:00
expand: {
width: 48,
minWidth: 48,
realWidth: 48,
order: ''
},
2016-08-16 08:07:18 +00:00
index: {
width: 48,
minWidth: 48,
realWidth: 48,
2016-10-27 17:24:13 +00:00
order: ''
2016-08-16 08:07:18 +00:00
}
};
const forced = {
selection: {
renderHeader: function(h, { store }) {
2016-10-27 13:45:21 +00:00
return <el-checkbox
disabled={ store.states.data && store.states.data.length === 0 }
indeterminate={ store.states.selection.length > 0 && !this.isAllSelected }
nativeOn-click={ this.toggleAllSelection }
2017-04-28 06:03:42 +00:00
value={ this.isAllSelected } />;
},
2016-11-04 23:30:23 +00:00
renderCell: function(h, { row, column, store, $index }) {
return <el-checkbox
nativeOn-click={ (event) => event.stopPropagation() }
2017-04-28 06:03:42 +00:00
value={ store.isSelected(row) }
disabled={ column.selectable ? !column.selectable.call(null, row, $index) : false }
2016-11-04 23:30:23 +00:00
on-input={ () => { store.commit('rowSelectedChanged', row); } } />;
},
2016-08-16 08:07:18 +00:00
sortable: false,
resizable: false
},
index: {
2016-11-04 23:30:23 +00:00
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>;
},
2016-08-16 08:07:18 +00:00
sortable: false
2016-11-12 15:08:17 +00:00
},
expand: {
2017-11-27 10:14:27 +00:00
renderHeader: function(h, { column }) {
return column.label || '';
2016-11-12 15:08:17 +00:00
},
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) }>
2016-11-12 15:08:17 +00:00
<i class='el-icon el-icon-arrow-right'></i>
</div>;
},
sortable: false,
resizable: false,
className: 'el-table__expand-column'
2016-08-16 08:07:18 +00:00
}
};
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;
2016-08-16 08:07:18 +00:00
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;
2016-11-04 23:30:23 +00:00
};
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;
};
2016-08-16 08:07:18 +00:00
export default {
name: 'ElTableColumn',
2016-08-16 08:07:18 +00:00
props: {
type: {
type: String,
default: 'default'
},
label: String,
className: String,
2017-03-08 11:14:36 +00:00
labelClassName: String,
2016-08-16 08:07:18 +00:00
property: String,
prop: String,
2016-08-16 08:07:18 +00:00
width: {},
minWidth: {},
2016-11-04 23:30:23 +00:00
renderHeader: Function,
2016-08-16 08:07:18 +00:00
sortable: {
type: [String, Boolean],
2016-08-16 08:07:18 +00:00
default: false
},
2016-10-27 17:24:13 +00:00
sortMethod: Function,
2017-10-30 02:26:25 +00:00
sortBy: [String, Function, Array],
2016-08-16 08:07:18 +00:00
resizable: {
type: Boolean,
default: true
},
2016-11-18 07:00:22 +00:00
context: {},
columnKey: String,
align: String,
2016-12-21 03:03:22 +00:00
headerAlign: String,
showTooltipWhenOverflow: Boolean,
showOverflowTooltip: Boolean,
fixed: [Boolean, String],
formatter: Function,
selectable: Function,
2016-10-27 13:45:21 +00:00
reserveSelection: Boolean,
filterMethod: Function,
filteredValue: Array,
2016-10-27 13:45:21 +00:00
filters: Array,
filterPlacement: String,
2016-10-27 13:45:21 +00:00
filterMultiple: {
type: Boolean,
default: true
},
2018-05-22 10:20:04 +00:00
index: [Number, Function],
sortOrders: {
type: Array,
default() {
return ['ascending', 'descending', null];
},
validator(val) {
return val.every(order => ['ascending', 'descending', null].indexOf(order) > -1);
}
}
2016-08-16 08:07:18 +00:00
},
data() {
return {
isSubColumn: false,
2016-08-30 07:36:21 +00:00
columns: []
2016-08-16 08:07:18 +00:00
};
},
2016-08-30 07:36:21 +00:00
beforeCreate() {
this.row = {};
this.column = {};
this.$index = 0;
},
2016-08-16 08:07:18 +00:00
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;
}
},
2016-08-16 08:07:18 +00:00
created() {
2016-09-02 11:12:00 +00:00
this.customRender = this.$options.render;
this.$options.render = h => h('div', this.$slots.default);
2016-08-16 08:07:18 +00:00
let parent = this.columnOrTableParent;
let owner = this.owner;
this.isSubColumn = owner !== parent;
this.columnId = (parent.tableId || parent.columnId) + '_column_' + columnIdSeed++;
2016-08-16 08:07:18 +00:00
let type = this.type;
const width = parseWidth(this.width);
const minWidth = parseMinWidth(this.minWidth);
2016-08-16 08:07:18 +00:00
let isColumnGroup = false;
let column = getDefaultColumn(type, {
2017-01-17 09:59:00 +00:00
id: this.columnId,
columnKey: this.columnKey,
2016-08-16 08:07:18 +00:00
label: this.label,
className: this.className,
2017-03-08 11:14:36 +00:00
labelClassName: this.labelClassName,
2016-11-04 23:30:23 +00:00
property: this.prop || this.property,
2016-08-16 08:07:18 +00:00
type,
renderCell: null,
2016-11-04 23:30:23 +00:00
renderHeader: this.renderHeader,
2016-08-16 08:07:18 +00:00
minWidth,
width,
isColumnGroup,
2016-11-18 07:00:22 +00:00
context: this.context,
align: this.align ? 'is-' + this.align : null,
2016-12-21 03:03:22 +00:00
headerAlign: this.headerAlign ? 'is-' + this.headerAlign : (this.align ? 'is-' + this.align : null),
sortable: this.sortable === '' ? true : this.sortable,
2016-10-27 17:24:13 +00:00
sortMethod: this.sortMethod,
2017-10-30 02:26:25 +00:00
sortBy: this.sortBy,
2016-08-16 08:07:18 +00:00
resizable: this.resizable,
showOverflowTooltip: this.showOverflowTooltip || this.showTooltipWhenOverflow,
formatter: this.formatter,
selectable: this.selectable,
reserveSelection: this.reserveSelection,
fixed: this.fixed === '' ? true : this.fixed,
2016-10-27 13:45:21 +00:00
filterMethod: this.filterMethod,
filters: this.filters,
2018-08-29 10:45:56 +00:00
filterable: this.filters || this.filterMethod,
2016-10-27 13:45:21 +00:00
filterMultiple: this.filterMultiple,
filterOpened: false,
filteredValue: this.filteredValue || [],
filterPlacement: this.filterPlacement || '',
2018-05-22 10:20:04 +00:00
index: this.index,
sortOrders: this.sortOrders
2016-08-16 08:07:18 +00:00
});
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;
}
});
2016-08-16 08:07:18 +00:00
// Deprecation warning for renderHeader property
if (this.renderHeader) {
2018-10-26 03:59:02 +00:00
console.warn('[Element Warn][TableColumn]Comparing to render-header, scoped-slot header is easier to use. We recommend users to use scoped-slot header.');
}
2016-11-12 15:08:17 +00:00
this.columnConfig = column;
2016-11-04 23:30:23 +00:00
let renderCell = column.renderCell;
2016-08-16 08:07:18 +00:00
let _self = this;
2016-08-30 07:36:21 +00:00
2016-11-12 15:08:17 +00:00
if (type === 'expand') {
owner.renderExpanded = function(h, data) {
return _self.$scopedSlots.default
? _self.$scopedSlots.default(data)
: _self.$slots.default;
2016-11-12 15:08:17 +00:00
};
column.renderCell = function(h, data) {
return <div class="cell">{ renderCell(h, data, this._renderProxy) }</div>;
};
return;
}
2016-11-04 23:30:23 +00:00
column.renderCell = function(h, data) {
if (_self.$scopedSlots.default) {
renderCell = () => _self.$scopedSlots.default(data);
}
2016-08-16 08:07:18 +00:00
if (!renderCell) {
renderCell = DEFAULT_RENDER_CELL;
}
const children = [
_self.renderTreeCell(data),
renderCell(h, data)
];
return _self.showOverflowTooltip || _self.showTooltipWhenOverflow
? <div class="cell el-tooltip" style={ {width: (data.column.realWidth || data.column.width) - 1 + 'px'} }>{ children }</div>
: (<div class="cell">
{ children }
</div>);
2016-08-16 08:07:18 +00:00
};
},
destroyed() {
if (!this.$parent) return;
const parent = this.$parent;
this.owner.store.commit('removeColumn', this.columnConfig, this.isSubColumn ? parent.columnConfig : null);
2016-08-16 08:07:18 +00:00
},
watch: {
label(newVal) {
if (this.columnConfig) {
this.columnConfig.label = newVal;
}
},
prop(newVal) {
if (this.columnConfig) {
this.columnConfig.property = newVal;
}
},
2016-08-16 08:07:18 +00:00
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) {
2016-11-24 10:34:02 +00:00
this.columnConfig.align = newVal ? 'is-' + newVal : null;
2017-01-06 02:28:01 +00:00
if (!this.headerAlign) {
this.columnConfig.headerAlign = newVal ? 'is-' + newVal : null;
}
}
},
2016-12-21 03:03:22 +00:00
headerAlign(newVal) {
if (this.columnConfig) {
2017-01-06 02:28:01 +00:00
this.columnConfig.headerAlign = 'is-' + (newVal ? newVal : this.align);
2016-12-21 03:03:22 +00:00
}
},
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;
}
2016-08-16 08:07:18 +00:00
}
},
methods: {
renderTreeCell(data) {
if (!data.treeNode) return null;
const ele = [];
ele.push(<span class="el-table__indent" style={{'padding-left': data.treeNode.indent + 'px'}}></span>);
if (data.treeNode.hasChildren) {
ele.push(<div class={ ['el-table__expand-icon', data.treeNode.expanded ? 'el-table__expand-icon--expanded' : '']}
on-click={this.handleTreeExpandIconClick.bind(this, data)}>
<i class='el-icon el-icon-arrow-right'></i>
</div>);
} else {
ele.push(<span class="el-table__placeholder"></span>);
}
return ele;
},
handleTreeExpandIconClick(data, e) {
e.stopPropagation();
if (data.store.states.lazy && !data.treeNode.loaded) {
data.store.loadData(data.row, data.treeNode);
} else {
data.store.toggleTreeExpansion(data.treeNode.rowKey);
}
}
},
2016-08-16 08:07:18 +00:00
mounted() {
const owner = this.owner;
const parent = this.columnOrTableParent;
2016-08-16 08:07:18 +00:00
let columnIndex;
if (!this.isSubColumn) {
2016-08-16 08:07:18 +00:00
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') {
2018-10-26 03:59:02 +00:00
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);
2016-08-16 08:07:18 +00:00
}
};