ivue-material-plus
Version:
A high quality UI components Library with Vue.js
334 lines (301 loc) • 7.33 kB
text/typescript
import { h } from 'vue';
import { hasOwn } from '@vue/shared';
import IvueCheckbox from '../ivue-checkbox/index.vue';
import IvueIcon from '../ivue-icon/index.vue';
import Loading from './loading.vue';
import { getProp } from '../../utils/objects';
// ts
import type { VNode } from 'vue';
import type { TableColumnCtx } from './table-column/defaults';
import type { RenderRowData } from './table/defaults';
import type { Store } from './store';
const defaultClassNames = {
selection: 'ivue-table-column--selection',
expand: 'ivue-table--expand-column',
};
// 行样式
export const cellStyles = {
default: {
order: '',
},
selection: {
width: 48,
minWidth: 48,
columnWidth: 48,
order: '',
},
expand: {
width: 48,
minWidth: 48,
columnWidth: 48,
order: '',
},
index: {
width: 48,
minWidth: 48,
columnWidth: 48,
order: '',
},
};
// 合并选项
export function mergeOptions<T, K>(defaults: T, config: K): T & K {
const options = {} as T & K;
let key;
// 复制对象
for (key in defaults) {
options[key] = defaults[key];
}
// config
for (key in config) {
if (hasOwn(config as unknown as Record<string, any>, key)) {
const value = config[key];
if (typeof value !== 'undefined') {
options[key] = value;
}
}
}
return options;
}
// https://github.com/reduxjs/redux/blob/master/src/compose.js
// 函数执行的顺序是从右到左
export function compose(...funcs) {
if (funcs.length === 0) {
return (arg) => arg;
}
if (funcs.length === 1) {
return funcs[0];
}
return funcs.reduce(
(a, b) =>
(...args) =>
a(b(...args))
);
}
// 渲染行
export function defaultRenderCell({
row,
column,
$index,
}: {
row: any;
column: TableColumnCtx;
$index: number;
}) {
// 字段名称 对应列内容的字段名
const property = column.property;
const value = property && getProp(row, property).value;
// 是否有格式化内容
if (column && column.formatter) {
return column.formatter(row, column, value, $index);
}
// 普通渲染
return value?.toString?.() || '';
}
// 列
export function treeCellPrefix(
{ row, treeNode, store }: RenderRowData,
createPlaceholder = false
) {
// 不是树节点
if (!treeNode) {
// 创建占位符
if (createPlaceholder) {
return [
h('span', {
class: 'ivue-table-indent--placeholder',
}),
];
}
return null;
}
// ele
const ele: VNode[] = [];
const callback = (event) => {
event.stopPropagation();
// 加载中
if (treeNode.loading) {
return;
}
// 树形数据与懒加载
store.loadOrToggle(row);
};
// 展示树形数据时,树节点的缩进
if (treeNode.indent) {
ele.push(
h('span', {
class: 'ivue-table-indent',
style: {
'padding-left': `${treeNode.indent}px`,
},
})
);
}
// 展开行
if (typeof treeNode.expanded === 'boolean' && !treeNode.noLazyChildren) {
const expandClasses = [
'ivue-table--expand-icon',
{
['ivue-table--expand-icon__expandend']: treeNode.expanded,
},
];
let icon = 'chevron_right';
// 加载中
if (treeNode.loading) {
icon = '';
}
// 解析指令
ele.push(
h(
'div',
{
class: expandClasses,
onClick: callback,
},
{
default: () => {
return [
icon
? h(IvueIcon, null, {
default: () => icon,
})
: h(Loading),
];
},
}
)
);
}
// 其他
else {
ele.push(
h('span', {
class: 'ivue-table-indent--placeholder',
})
);
}
return ele;
}
// 需要替换的渲染函数
export const cellForced = {
// 多选
selection: {
// 渲染头部
renderHeader({ store }: { store: Store }) {
return h(IvueCheckbox, {
// 没有数据禁用
disabled:
store.states.data.value && store.states.data.value.length === 0,
// 是否选择了全部
modelValue: store.states.isAllSelected.value,
// 更新modelValue
'onUpdate:modelValue': store.toggleAllSelection,
// 中间状态
indeterminate:
store.states.selection.value.length > 0 &&
!store.states.isAllSelected.value,
// onClick
onClick: (event: Event) => {
event.stopPropagation();
},
});
},
// 渲染单元格
renderCell({
row,
column,
store,
$index,
}: {
row: any;
column: TableColumnCtx;
store: Store;
$index: string;
}) {
return h(IvueCheckbox, {
disabled: column.selectable
? !column.selectable.call(null, row, $index)
: false,
modelValue: store.isSelected(row),
onChange: () => {
store.commit('rowSelectedChanged', row);
},
// 阻止捕获和冒泡阶段中当前事件
onClick: (event: Event) => event.stopPropagation(),
});
},
// 对应列是否可以排序
sortable: false,
// 对应列是否可以通过拖动改变宽度
resizable: false,
},
// 索引
index: {
// 渲染头部
renderHeader({ column }: { column: TableColumnCtx }) {
return column.label || '#';
},
// 渲染单元格
renderCell({ column, $index }: { column: TableColumnCtx; $index: number }) {
let i = $index + 1;
const index = column.index;
// number
if (typeof index === 'number') {
i = $index + index;
}
// function
else if (typeof index === 'function') {
i = index($index);
}
return h('div', {}, [i]);
},
},
expand: {
// 渲染头部
renderHeader({ column }: { column: TableColumnCtx }) {
return column.label || '';
},
renderCell({
row,
store,
expanded,
}: {
row: TableColumnCtx;
store: Store;
expanded: boolean;
}) {
// 切换展开
const handleToggleRowExpansion = (event: Event) => {
event.stopPropagation();
// 切换行展开
store.toggleRowExpansion(row);
};
return h(
'div',
{
class: [
'ivue-table--expand-icon',
{
['ivue-table--expand-icon__expandend']: expanded,
},
],
onClick: handleToggleRowExpansion,
},
{
default: () => {
return [
h(IvueIcon, null, {
default: () => 'chevron_right',
}),
];
},
}
);
},
sortable: false,
resizable: false,
},
};
// 获取默认的class
export const getDefaultClassName = (type) => {
return defaultClassNames[type] || '';
};