說明
table-column
是較為重要的一部分曾掂,但是代碼相對較少,比較復(fù)雜的地方請查看大佬的Vue 2 的動(dòng)態(tài)添加模板方法前酿,現(xiàn)在已不推薦使用蜗元。
源碼解讀
import ElCheckbox from 'element-ui/packages/checkbox';
import ElTag from 'element-ui/packages/tag';
import objectAssign from 'element-ui/src/utils/merge';
import { getValueByPath } from './util';
// 用來生成列的 id
let columnIdSeed = 1;
// 默認(rèn)屬性
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: ''
}
};
// 三種不同類型列的渲染,會(huì)強(qiáng)制按如下渲染
const forced = {
selection: {
renderHeader: function(h) {
return <el-checkbox
nativeOn-click={ this.toggleAllSelection }
domProps-value={ this.isAllSelected } />;
},
renderCell: function(h, { row, column, store, $index }) {
return <el-checkbox
domProps-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 }) {
return <div>{ $index + 1 }</div>;
},
sortable: false
},
expand: {
renderHeader: function(h, {}) {
return '';
},
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={ () => proxy.handleExpandClick(row) }>
<i class='el-icon el-icon-arrow-right'></i>
</div>;
},
sortable: false,
resizable: false,
className: 'el-table__expand-column'
}
};
/**
* 獲取默認(rèn)的列的信息
* @param type 列的烈性
* @param options 相關(guān)選項(xiàng)
* @return 列
*/
const getDefaultColumn = function(type, options) {
const column = {};
// 獲取默認(rèn)的基本信息
objectAssign(column, defaults[type || 'default']);
// 應(yīng)用新的選項(xiàng)信息
for (let name in options) {
if (options.hasOwnProperty(name)) {
const value = options[name];
if (typeof value !== 'undefined') {
column[name] = value;
}
}
}
// 設(shè)置一個(gè)最小寬度
if (!column.minWidth) {
column.minWidth = 80;
}
// 實(shí)際寬度
column.realWidth = column.width || column.minWidth;
return column;
};
/**
* 默認(rèn)的渲染單元格的方式
* @param h createElement
* @param options.row 行信息
* @param options.column 列信息
*/
const DEFAULT_RENDER_CELL = function(h, { row, column }) {
// 列的相關(guān)屬性
const property = column.property;
// 格式化內(nèi)容
if (column && column.formatter) {
return column.formatter(row, column);
}
// 如果是直接的屬性旺罢,沒有嵌套
if (property && property.indexOf('.') === -1) {
return row[property];
}
// 尋找多層的屬性
return getValueByPath(row, property);
};
export default {
name: 'ElTableColumn',
props: {
type: {
type: String,
default: 'default'
},
label: String,
className: String,
property: String,
prop: String,
width: {},
minWidth: {},
renderHeader: Function,
sortable: {
type: [String, Boolean],
default: false
},
sortMethod: Function,
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,
filterMultiple: {
type: Boolean,
default: true
}
},
data() {
return {
isSubColumn: false,
columns: []
};
},
// 進(jìn)行初始化
beforeCreate() {
this.row = {};
this.column = {};
this.$index = 0;
},
components: {
ElCheckbox,
ElTag
},
computed: {
// 尋找到 table
owner() {
let parent = this.$parent;
while (parent && !parent.tableId) {
parent = parent.$parent;
}
return parent;
}
},
created() {
this.customRender = this.$options.render;
this.$options.render = h => h('div', this.$slots.default);
this.columnId = (this.$parent.tableId || (this.$parent.columnId + '_')) + 'column_' + columnIdSeed++;
// 如果父級不是 table斯棒, 說明是嵌套的列
let parent = this.$parent;
let owner = this.owner;
this.isSubColumn = owner !== parent;
// 列的類型
let type = this.type;
// 指定寬度
let width = this.width;
if (width !== undefined) {
width = parseInt(width, 10);
if (isNaN(width)) {
width = null;
}
}
// 指定最小寬度
let minWidth = this.minWidth;
if (minWidth !== undefined) {
minWidth = parseInt(minWidth, 10);
if (isNaN(minWidth)) {
minWidth = 80;
}
}
let isColumnGroup = false;
// 獲取列
let column = getDefaultColumn(type, {
id: this.columnId,
columnKey: this.columnKey,
label: this.label,
className: this.className,
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,
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 || []
});
// 根據(jù)類型設(shè)置需要強(qiáng)制渲染的部分
objectAssign(column, forced[type] || {});
this.columnConfig = column;
let renderCell = column.renderCell;
let _self = this;
// 如果是 expand,需要對內(nèi)容進(jìn)行特殊處理
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.$vnode.data.inlineTemplate) {
renderCell = function() {
data._self = _self.context || data._self;
if (Object.prototype.toString.call(data._self) === '[object Object]') {
for (let prop in data._self) {
if (!data.hasOwnProperty(prop)) {
data[prop] = data._self[prop];
}
}
}
// 靜態(tài)內(nèi)容會(huì)緩存到 _staticTrees 內(nèi)主经,不改的話獲取的靜態(tài)數(shù)據(jù)就不是內(nèi)部 context
data._staticTrees = _self._staticTrees;
data.$options.staticRenderFns = _self.$options.staticRenderFns;
return _self.customRender.call(data);
};
} else if (_self.$scopedSlots.default) {
renderCell = () => _self.$scopedSlots.default(data);
}
if (!renderCell) {
renderCell = DEFAULT_RENDER_CELL;
}
return _self.showOverflowTooltip || _self.showTooltipWhenOverflow
? <el-tooltip
effect={ this.effect }
placement="top"
disabled={ this.tooltipDisabled }>
<div class="cell">{ renderCell(h, data) }</div>
<span slot="content">{ renderCell(h, data) }</span>
</el-tooltip>
: <div class="cell">{ renderCell(h, data) }</div>;
};
},
destroyed() {
if (!this.$parent) return;
this.owner.store.commit('removeColumn', this.columnConfig);
},
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 = newVal;
this.owner.store.scheduleLayout();
}
},
minWidth(newVal) {
if (this.columnConfig) {
this.columnConfig.minWidth = newVal;
this.owner.store.scheduleLayout();
}
},
fixed(newVal) {
if (this.columnConfig) {
this.columnConfig.fixed = newVal;
this.owner.store.scheduleLayout();
}
}
},
mounted() {
const owner = this.owner;
const parent = this.$parent;
let columnIndex;
if (!this.isSubColumn) { // 如果不是嵌套列荣暮,序號就是在 table 中的位置
columnIndex = [].indexOf.call(parent.$refs.hiddenColumns.children, this.$el);
} else { // 否則是在父級列的位置
columnIndex = [].indexOf.call(parent.$el.children, this.$el);
}
owner.store.commit('insertColumn', this.columnConfig, columnIndex, this.isSubColumn ? parent.columnConfig : null);
}
};