ivue-material-plus
Version:
A high quality UI components Library with Vue.js
307 lines (247 loc) • 7.24 kB
text/typescript
import {
Comment,
computed,
getCurrentInstance,
ref,
watchEffect,
h,
} from 'vue';
import {
defaultRenderCell,
treeCellPrefix,
cellForced,
getDefaultClassName,
} from '../config';
import { parseWidth, parseMinWidth } from '../utils';
// type
import type { TableColumn, TableColumnCtx, ColumnParent } from './defaults';
import type { Table, RenderRowData } from '../table/defaults';
import type { ComputedRef } from 'vue';
const prefixCls = 'ivue-table';
function useRender(
props: TableColumnCtx,
slots,
parentDom: ComputedRef<Table>
) {
const vm = getCurrentInstance() as TableColumn;
// 列id
const columnId = ref<string>('');
// 是否是嵌套的子列
const isSubColumn = ref<boolean>(false);
// 对齐方向
const align = ref<string>();
// 表头对齐方式
const headerAlign = ref<string>();
// 对应列的宽度
const columnWidth = ref<string | number>(parseWidth(props.width));
// 对应列的最小宽度
const columnMinWidth = ref<string | number>(parseMinWidth(props.minWidth));
// computed
// 列的父级
const columnParent = computed(() => {
let parent: ColumnParent = vm.vnode.vParent || vm.parent;
// 没有表格id 没有列id
while (parent && !parent.tableId && !parent.columnId) {
parent = parent.vnode.vParent || parent.parent;
}
return parent;
});
// 是否有列数据
const hasTreeColumn = computed<boolean>(() => {
const { store }: any = vm.parent;
// 没有 store
if (!store) {
return false;
}
const { treeData } = store.states;
const treeDataValue = treeData.value;
return treeDataValue && Object.keys(treeDataValue).length > 0;
});
// methods
// 获取props值
const getPropsData = (...propsKey: unknown[]) => {
return propsKey.reduce((prev: TableColumnCtx, cur) => {
// 数组
if (Array.isArray(cur)) {
cur.forEach((key) => {
prev[key] = props[key];
});
}
return prev;
}, {});
};
// 检查子列表
const checkSubColumn = (children: TableColumn | TableColumn[]) => {
// 数组
if (Array.isArray(children)) {
children.forEach((child) => check(child));
}
// 其他
else {
check(children);
}
// 检查是否是列表组件
function check(item: TableColumn) {
if (item?.type?.name === `${prefixCls}-column`) {
item.vParent = vm;
}
}
};
// 列渲染
const columnRender = (column: TableColumnCtx) => {
// renderHeader 属性不推荐使用。
// 不是多选框
if (
!props.renderHeader &&
column.type !== 'selection' &&
column.type !== 'index'
) {
column.renderHeader = (scope) => {
vm.columnConfig.value['label'];
// 是否有头部插槽
const renderHeader = slots.header;
return renderHeader ? renderHeader(scope) : column.label;
};
}
// 渲染行函数
let originRenderCell = column.renderCell;
const hasTreeColumnValue = hasTreeColumn.value;
// 可展开行
if (column.type === 'expand') {
// 渲染行
column.renderCell = (data) => {
return h(
'div',
{
class: 'cell',
},
[originRenderCell(data)]
);
};
// 展开的内容
parentDom.value.renderExpanded = (data) => {
return slots.default ? slots.default(data) : slots.default;
};
}
// 其他状态
else {
originRenderCell = originRenderCell || defaultRenderCell;
// 渲染行
column.renderCell = (data: RenderRowData) => {
let children = null;
// 有默认插槽
if (slots.default) {
// 设置vnode
const vnode = slots.default(data);
// 判断是否是注释
children = vnode.some((v) => v.type !== Comment)
? vnode
: originRenderCell(data);
}
// 不是插槽
else {
children = originRenderCell(data);
}
// 列数据
const shouldCreatePlaceholder =
hasTreeColumnValue && data.cellIndex === 0;
// 列的占位符-用于展示树形数据时,树节点的缩进
const prefix = treeCellPrefix(data, shouldCreatePlaceholder);
// props
const props = {
class: 'cell',
style: {},
};
// 当内容过长被隐藏时显示 tooltip
if (column.showOverflowTooltip) {
props.class = `${props.class} ${prefixCls}-tooltip`;
props.style = {
width: `${
(data.column.columnWidth || Number(data.column.width)) - 1
}px`,
};
}
// 检查子列表
checkSubColumn(children);
return h('div', props, [prefix, children]);
};
}
return column;
};
// 设置列宽度
const setColumnWidth = (column: TableColumnCtx) => {
if (columnWidth.value) {
column.width = columnWidth.value;
}
// 最小宽度
if (columnMinWidth.value) {
column.minWidth = columnMinWidth.value;
}
// 没有设置最小宽度,默认最小宽度 80
if (!column.minWidth) {
column.minWidth = 80;
}
// 列宽度 minWidth 或者 width
column.columnWidth = Number(
column.width === undefined ? column.minWidth : column.width
);
return column;
};
// 设置列 props
const setColumnProps = (column: TableColumnCtx) => {
// 对应列的类型
const type = column.type;
// 不应覆盖的值
const source = cellForced[type] || {};
// 替换列 column 对象的参数
Object.keys(source).forEach((prop) => {
// 获取值
const value = source[prop];
if (prop !== 'className' && value !== undefined) {
column[prop] = value;
}
});
// 有对应的class 多选 | 展开
const className = getDefaultClassName(type);
// 有对应的class
if (className) {
column.className = column.className
? `${column.className} ${className}`
: className;
}
return column;
};
// 获取列节点index
const getColumnDomIndex = (children: HTMLElement[], el) => {
return Array.prototype.indexOf.call(children, el);
};
// watch
// 同步监听 对齐方向
watchEffect(() => {
align.value = props.align ? `is-${props.align}` : '';
return align.value;
});
// 同步监听 表头对齐方式
watchEffect(() => {
headerAlign.value = props.headerAlign
? `is-${props.headerAlign}`
: align.value;
return headerAlign.value;
});
return {
// data
columnId,
isSubColumn,
align,
headerAlign,
// computed
columnParent,
// methods
getPropsData,
getColumnDomIndex,
columnRender,
setColumnWidth,
setColumnProps,
};
}
export default useRender;