element-nice-ui
Version:
A Component Library for Vue.js.
433 lines (380 loc) • 11.9 kB
JavaScript
import Vue from 'vue'
import merge from 'element-nice-ui/src/utils/merge'
import {
getKeysMap,
getRowIdentity,
getColumnById,
getColumnByKey,
orderBy,
toggleRowStatus
} from '../util'
import expand from './expand'
import current from './current'
import tree from './tree'
const sortData = (data, states) => {
if (!data) return []
const sortingColumn = states.sortingColumn
if (!sortingColumn || typeof sortingColumn.sortable === 'string') {
return data
}
return orderBy(
data,
states.sortProp,
states.sortOrder,
sortingColumn.sortMethod,
sortingColumn.sortBy
)
}
const doFlattenColumns = columns => {
const result = []
columns.forEach(column => {
if (column.children) {
result.push.apply(result, doFlattenColumns(column.children))
} else {
result.push(column)
}
})
return result
}
export default Vue.extend({
data() {
return {
states: {
// 3.0 版本后要求必须设置该属性
rowKey: null,
// 渲染的数据来源,是对 table 中的 data 过滤排序后的结果
data: [],
// 值为空时的默认占位置
placeholder: null,
// 是否包含固定列
isComplex: false,
// 列
_columns: [], // 不可响应的
originColumns: [],
columns: [],
fixedColumns: [],
rightFixedColumns: [],
leafColumns: [],
fixedLeafColumns: [],
rightFixedLeafColumns: [],
leafColumnsLength: 0,
fixedLeafColumnsLength: 0,
rightFixedLeafColumnsLength: 0,
// 选择
isAllSelected: false,
selection: [],
reserveSelection: false,
selectOnIndeterminate: false,
selectable: null,
// 过滤
filters: {}, // 不可响应的
filteredData: null,
// 排序
sortingColumn: null,
sortProp: null,
sortOrder: null,
hoverRow: null
}
}
},
mixins: [expand, current, tree],
methods: {
// 检查 rowKey 是否存在
assertRowKey() {
const rowKey = this.states.rowKey
if (!rowKey) throw new Error('[ElTable] prop row-key is required')
},
// 更新列
updateColumns() {
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
},
// 更新 DOM
scheduleLayout(needUpdateColumns) {
if (needUpdateColumns) {
this.updateColumns()
}
this.table.debouncedUpdateLayout()
},
// 选择
isSelected(row) {
const { selection = [] } = this.states
return selection.indexOf(row) > -1
},
clearSelection() {
const states = this.states
states.isAllSelected = false
const oldSelection = states.selection
if (oldSelection.length) {
states.selection = []
this.table.$emit('selection-change', [])
}
},
cleanSelection() {
const states = this.states
const { data, rowKey, selection } = states
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 => data.indexOf(item) === -1)
}
if (deleted.length) {
const newSelection = selection.filter(
item => deleted.indexOf(item) === -1
)
states.selection = newSelection
this.table.$emit('selection-change', newSelection.slice())
}
},
toggleRowSelection(row, selected, emitChange = true) {
const changed = toggleRowStatus(this.states.selection, row, selected)
if (changed) {
const newSelection = (this.states.selection || []).slice()
// 调用 API 修改选中值,不触发 select 事件
if (emitChange) {
this.table.$emit('select', newSelection, row, selected)
}
this.table.$emit('selection-change', newSelection)
}
},
setSelection(rows) {
this.states.selection = rows
},
_toggleAllSelection() {
const states = this.states
const { data = [], selection } = states
// 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)
states.isAllSelected = value
let selectionChanged = false
data.forEach((row, index) => {
if (states.selectable) {
if (
states.selectable.call(null, row, index) &&
toggleRowStatus(selection, row, value)
) {
selectionChanged = true
}
} else {
if (toggleRowStatus(selection, row, value)) {
selectionChanged = true
}
}
})
if (selectionChanged) {
this.table.$emit('selection-change', selection ? selection.slice() : [])
}
this.table.$emit('select-all', selection)
},
updateSelectionByRowKey() {
const states = this.states
const { selection, rowKey, data } = states
const selectedMap = getKeysMap(selection, rowKey)
data.forEach(row => {
const rowId = getRowIdentity(row, rowKey)
const rowInfo = selectedMap[rowId]
if (rowInfo) {
selection[rowInfo.index] = row
}
})
},
updateAllSelected() {
const states = this.states
const { selection, rowKey, selectable } = states
// data 为 null 时,解构时的默认值会被忽略
const data = states.data || []
if (data.length === 0) {
states.isAllSelected = false
return
}
let selectedMap
if (rowKey) {
selectedMap = getKeysMap(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
},
// 过滤与排序
updateFilters(columns, values) {
if (!Array.isArray(columns)) {
columns = [columns]
}
const states = this.states
const filters = {}
columns.forEach(col => {
states.filters[col.id] = values
filters[col.columnKey || col.id] = values
})
return filters
},
updateSort(column, prop, order) {
if (this.states.sortingColumn && this.states.sortingColumn !== column) {
this.states.sortingColumn.order = null
}
this.states.sortingColumn = column
this.states.sortProp = prop
this.states.sortOrder = order
},
execFilter() {
const states = this.states
const { _data, filters } = states
let data = _data || []
Object.keys(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
},
execSort() {
const states = this.states
states.data = sortData(states.filteredData, states)
},
// 根据 filters 与 sort 去过滤 data
execQuery(ignore) {
if (!(ignore && ignore.filter)) {
this.execFilter()
}
this.execSort()
},
clearFilter(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) {
// TODO: 优化这里的代码
panels[key].filteredValue = []
}
})
this.commit('filterChange', {
column: columns,
values: [],
silent: true,
multi: true
})
} else {
keys.forEach(key => {
// TODO: 优化这里的代码
panels[key].filteredValue = []
})
states.filters = {}
this.commit('filterChange', {
column: {},
values: [],
silent: true
})
}
},
clearSort() {
const states = this.states
if (!states.sortingColumn) return
this.updateSort(null, null, null)
this.commit('changeSortCondition', {
silent: true
})
},
// 适配层,expand-row-keys 在 Expand 与 TreeTable 中都有使用
setExpandRowKeysAdapter(val) {
// 这里会触发额外的计算,但为了兼容性,暂时这么做
this.setExpandRowKeys(val)
this.updateTreeExpandKeys(val)
},
// 展开行与 TreeTable 都要使用
toggleRowExpansionAdapter(row, expanded) {
const hasExpandColumn = this.states.columns.some(
({ type }) => type === 'expand'
)
if (hasExpandColumn) {
this.toggleRowExpansion(row, expanded)
} else {
this.toggleTreeExpansion(row, expanded)
}
}
}
})