UNPKG

ivue-material-plus

Version:

A high quality UI components Library with Vue.js

294 lines (248 loc) • 7.27 kB
import { defineComponent, h, getCurrentInstance, ref, computed, onMounted, onBeforeMount, Fragment, onBeforeUnmount, } from 'vue'; import { isString } from '@vue/shared'; import defaultProps from './defaults'; import useRender from './render'; import useWatcher from './watcher'; import { cellStyles, mergeOptions, compose } from '../config'; // type import type { TableColumn, TableColumnCtx } from './defaults'; import type { Table } from '../table/defaults'; const prefixCls = 'ivue-table-column'; let columnIdSeed = 1; export default defineComponent({ name: prefixCls, props: defaultProps, setup(props: TableColumnCtx, { slots }) { const vm = getCurrentInstance() as TableColumn; // data // 列参数 const columnConfig = ref<Partial<TableColumnCtx>>({}); // computed // 获取父级元素 const parentDom = computed(() => { let parent = vm.parent as Table; // 没有表格id while (parent && !parent.tableId) { parent = parent.parent; } return parent; }); // methods // 初始化 const initData = () => { // 是否是嵌套的子列 获取 hiddenColumns 节点 const children = isSubColumn.value ? parent.vnode.el.children : parent.refs.hiddenColumns?.children; // 获取当前行index const getColumnIndex = () => { return getColumnDomIndex(children || [], vm.vnode.el); }; // 列参数 columnConfig.value.getColumnIndex = getColumnIndex; // 插入列 const columnIndex = getColumnIndex(); // 存在列组件插入列节点 if (columnIndex > -1) { parentDom.value.store.commit( 'insertColumn', columnConfig.value, isSubColumn.value ? parent.columnConfig.value : null ); } }; // 在挂载开始之前被调用 const initBeforeMount = () => { // 是否是嵌套的子列 父级不相等 isSubColumn.value = parentDom.value !== parent; // 对应列的类型 const type = props.type || 'default'; // 对应列是否可以排序 const sortable = props.sortable === '' ? true : props.sortable; // 默认参数 const defaults = { // 行样式 ...cellStyles[type], // id id: columnId.value, // 对应列的类型 type, // 对应列内容的字段名 property: props.prop || props.property, // 对齐方式 align: align, // 表头对齐方式 headerAlign: headerAlign, // 表头对齐方式 showOverflowTooltip: props.showOverflowTooltip, // filter 相关属性 filterable: props.filters || props.filterMethod, // 过滤弹出框的定位 filterPlacement: '', // 过滤开启 filterOpened: false, // 是否是嵌套的子列 isSubColumn: false, // 对应列是否可以排序 sortable, // index 列 index: props.index, // <column key="xxx" /> // 列 vode key rawColumnKey: vm.vnode.key, // 选中的数据过滤项 filteredValue: [], }; // 基础 props const basicProps = [ 'columnKey', 'label', 'className', 'labelClassName', 'type', 'renderHeader', 'formatter', 'fixed', 'resizable', ]; // 排序 props const sortProps = ['sortMethod', 'sortBy', 'sortOrders']; // 多选 props const selectProps = ['selectable', 'reserveSelection']; // 过滤 props const filterProps = [ 'filterMethod', 'filters', 'filterMultiple', 'filterOpened', 'filteredValue', 'filterPlacement', ]; // 获取props值 let column = getPropsData( basicProps, sortProps, selectProps, filterProps ); // 合并props值 column = mergeOptions(defaults, column); // 合并函数 const chains = compose( // 列渲染函数 columnRender, // 设置列宽度 setColumnWidth, // 设置列 props setColumnProps ); column = chains(column); // 列参数 columnConfig.value = column; // 注册 watcher // 注册普通观察者 registerNormalWatchers(); registerComplexWatchers(); }; // onBeforeMount onBeforeMount(() => { // 在挂载开始之前被调用 initBeforeMount(); }); // onMounted onMounted(() => { // 初始化 initData(); }); // onBeforeUnmount onBeforeUnmount(() => { parentDom.value.store.commit( 'removeColumn', columnConfig.value, isSubColumn.value ? parent.columnConfig.value : null ); }); // 开始渲染 const { // data columnId, isSubColumn, align, headerAlign, // computed columnParent, // methods getPropsData, getColumnDomIndex, columnRender, setColumnWidth, setColumnProps, } = useRender(props, slots, parentDom); const { registerNormalWatchers, registerComplexWatchers } = useWatcher( parentDom, props ); // 获取父级 const parent = columnParent.value; // 设置列id columnId.value = `${ parent.tableId || parent.columnId }-column-${columnIdSeed++}`; // 设置列id vm.columnId = columnId.value; // 列参数 vm.columnConfig = columnConfig; }, render() { try { const slotsList = this.$slots.default?.({ row: {}, column: {}, $index: -1, }); const slot = []; // 有插槽 if (Array.isArray(slotsList)) { for (const childNode of slotsList) { // ivue-table-column 或者 函数组件 ((FUNCTIONAL_COMPONENT = 1 << 1) = 2) & 2 === 1 if (childNode.type?.name === prefixCls || childNode.shapeFlag & 2) { slot.push(childNode); } // 是否是片段 Fragment 多个根节点 else if ( childNode.type === Fragment && Array.isArray(childNode.children) ) { childNode.children.forEach((vnode) => { /** * vnode为动态槽或文本时不渲染 * * 1024 * 表示具有动态插槽的组件(例如,引用 v-for 的插槽 * 迭代值或动态插槽名称)。 * 带有这个标志的组件总是被强制更新。 */ if (vnode?.patchFlag !== 1024 && !isString(vnode?.children)) { slot.push(vnode); } }); } } } const vnode = h('div', slot); return vnode; } catch { return h('div', []); } }, });