UNPKG

ivue-material-plus

Version:

A high quality UI components Library with Vue.js

413 lines (346 loc) • 11.4 kB
useRender; import { h, inject, computed } from 'vue'; import useStyles from './styles'; import useEvents from './events'; import { getRowIdentity } from '../utils'; import { throwError } from '../../../utils/error'; // ts import type { TableProps, RenderRowData, TreeNode } from '../table/defaults'; import type { TableBodyProps } from './defaults'; import type { TableColumnCtx } from '../table-column/defaults'; import { TableContextKey } from '../table/defaults'; function useRender(props: Partial<TableBodyProps>) { // inject const IvueTable = inject(TableContextKey); // 样式 const { getRowClass, getRowStyle, getTableSpan, getCellClass, getCellStyle } = useStyles(props); // 事件 const { handleClickTr, handleCellMouseEnter, handleCellMouseLeave, handleMouseEnter, handleMouseLeave, } = useEvents(props); // computed // 是否是默认索引 const firstDefaultColumnIndex = computed(() => { return props.store?.states.columns.value.findIndex( ({ type }) => type === 'default' ); }); // methods // 获取行key const getRowKey = (row: TableColumnCtx, index: number) => { const rowKey = (IvueTable.props as Partial<TableProps>).rowKey; // 有自定义 rowKey if (rowKey) { // 获取rowKey对应的数据 return getRowIdentity(row, rowKey); } return index; }; // 渲染行 const rowRender = ( row: TableColumnCtx, $index: number, treeRowData?: TreeNode, // 展开状态 expanded = false ) => { const { store } = props; const { columns, indent } = store.states; // 行样式 const rowClasses = getRowClass(row, $index); let display = true; // 是否是子节点数据 if (treeRowData) { rowClasses.push(`ivue-table-level-${treeRowData.level}`); display = treeRowData.display; } // tr 隐藏显示用于树形节点 const displayStyle = display ? null : { display: 'none', }; return h( 'tr', { class: rowClasses, style: [displayStyle, getRowStyle(row, $index)], key: getRowKey(row, $index), onClick: ($event) => { handleClickTr($event, row); }, // 鼠标进入 onMouseenter: () => { handleMouseEnter($index); }, // 鼠标离开 onMouseleave: () => { handleMouseLeave(); }, }, columns.value.map((column, cellIndex) => { // 获取单元格样式 const { rowspan, colspan } = getTableSpan( row, column, $index, cellIndex ); // 是否存在单元格样式 if (!rowspan || !colspan) { return null; } // key const baseKey = `${$index},${cellIndex}`; // 当前列的数据 const columnData = { ...column }; // column 的 key | 列 vode key const patchKey = columnData.columnKey || columnData.rawColumnKey || ''; // data const data: RenderRowData = { store: props?.store, _self: props.context || IvueTable, column: columnData, row, $index, cellIndex, // 展开状态 expanded, }; // 设置子节点数据 if (cellIndex === firstDefaultColumnIndex.value && treeRowData) { data.treeNode = { indent: treeRowData.level * indent.value, level: treeRowData.level, }; // 是否有展开 if (typeof treeRowData.expanded === 'boolean') { data.treeNode.expanded = treeRowData.expanded; // 表明是懒加载 if ('loading' in treeRowData) { data.treeNode.loading = treeRowData.loading; } // 没有懒加载节点 if ('noLazyChildren' in treeRowData) { data.treeNode.noLazyChildren = treeRowData.noLazyChildren; } } } return h( 'td', { // class class: getCellClass($index, cellIndex, row, column), // style style: getCellStyle($index, cellIndex, row, column), rowspan, colspan, // key key: `${patchKey}${baseKey}`, // 鼠标进入 onMouseenter: (event) => { handleCellMouseEnter(event, row); }, // 鼠标离开 onMouseleave: (event) => { handleCellMouseLeave(event); }, }, [ // 渲染单元格 column.renderCell(data), ] ); }) ); }; // 渲染行 const wrappedRowRender = (row: TableColumnCtx, $index: number): any => { const store = props.store; const { isRowExpanded, assertRowKey } = store; const { treeData, lazyTreeNodeMap, childrenColumnName, rowKey } = store.states; const columns = store?.states.columns.value; // 是否是展开行 const hasExpandColumn = columns.some(({ type }) => type === 'expand'); // 是否是展开行 if (hasExpandColumn) { // 是否展开行 const expanded = isRowExpanded(row); // tr const tr = rowRender( row, $index, undefined, // 展开状态 expanded ); // 展开的内容 const renderExpanded = IvueTable.renderExpanded; // 展开 if (expanded) { // 没有展开内容 if (!renderExpanded) { // eslint-disable-next-line no-console console.error('[Error]renderExpanded is required.'); return tr; } return [ [ tr, h( 'tr', { key: `expanded-row__${tr.key as string}`, }, [ h( 'td', { colspan: columns.length, class: ['ivue-table-cell', 'ivue-table--expand-cell'], }, [ renderExpanded({ row, $index, store, // 展开状态 expanded, }), ] ), ] ), ], ]; } // 未展开 else { return [[tr]]; } } // 子节点渲染 else if (Object.keys(treeData.value).length) { // 检查 rowKey 是否存在 assertRowKey(); // TreeTable 时,rowKey 必须由用户设定,不使用 getKeyOfRow 计算 // 在调用 rowRender 函数时,仍然会计算 rowKey, // 获取rowKey对应的数据 const rowKeyData = getRowIdentity(row, rowKey.value); // 子节点数据 let childrenData = treeData.value[rowKeyData]; // 每一行的节点数据 let treeRowData = null; // 子节点数据 if (childrenData) { treeRowData = { expanded: childrenData.expanded, level: childrenData.level, display: true, }; // 懒加载数据 if (typeof childrenData.lazy === 'boolean') { // 加载完成 if (typeof childrenData.loaded === 'boolean' && childrenData.loaded) { // 没有子节点 treeRowData.noLazyChildren = !( childrenData.children && childrenData.children.length ); } // 加载 treeRowData.loading = childrenData.loading; } } const dom = [rowRender(row, $index, treeRowData)]; // 渲染嵌套数据 if (childrenData) { // currentRow 记录的是 index,所以还需主动增加 TreeTable 的 index let i = 0; // 递归方法 const traverse = (children, parent) => { // 没有数据 if (!(children && children.length && parent)) { return; } children.forEach((node) => { // 父节点的 display 状态影响子节点的显示状态 const innerTreeRowData = { display: parent.display && parent.expanded, level: parent.level + 1, expanded: false, noLazyChildren: false, loading: false, }; // 获取rowKey对应的数据 const childKey = getRowIdentity(node, rowKey.value); if (childKey === undefined || childKey === null) { throwError( 'ivue-table', 'For nested data item, row-key is required' ); } childrenData = { ...treeData.value[childKey] }; // 对于当前节点,分成有无子节点两种情况。 // 如果包含子节点的,设置 expanded 属性。 // 对于它子节点的 display 属性由它本身的 expanded 与 display 共同决定。 if (childrenData) { innerTreeRowData.expanded = childrenData.expanded; // 懒加载的某些节点,level 未知 childrenData.level = childrenData.level || innerTreeRowData.level; childrenData.display = !!( childrenData.expanded && innerTreeRowData.display ); // 懒加载 if (typeof childrenData.lazy === 'boolean') { // 加载完成 if ( typeof childrenData.loaded === 'boolean' && childrenData.loaded ) { // 没有子节点 innerTreeRowData.noLazyChildren = !( childrenData.children && childrenData.children.length ); } // 加载中 innerTreeRowData.loading = childrenData.loading; } } i++; // 添加节点 dom.push(rowRender(node, $index + i, innerTreeRowData)); if (childrenData) { // 懒加载节点 | 子节点 = 获取行数据 const nodes = lazyTreeNodeMap.value[childKey] || node[childrenColumnName.value]; traverse(nodes, childrenData); } }); }; // 对于 root 节点,display 一定为 true childrenData.display = true; // 懒加载节点 | 子节点 = 获取行数据 const nodes = lazyTreeNodeMap.value[rowKeyData] || row[childrenColumnName.value]; // 递归方法 traverse(nodes, childrenData); } return dom; } // 普通渲染 else { return rowRender(row, $index); } }; return { wrappedRowRender, }; } export default useRender;