UNPKG

@fesjs/fes-design

Version:
160 lines (156 loc) 5.73 kB
import _defineProperty from '@babel/runtime/helpers/esm/defineProperty'; import { reactive, ref, watch, computed, nextTick } from 'vue'; import { isEmpty, isArray, isNil } from 'lodash-es'; import { ROOT_MENU_KEY } from './const'; function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function useData(_ref) { let { props, currentExpandedKeys } = _ref; const nodeList = reactive({}); const transformData = ref([]); const initialLoaded = ref(true); const initLoadingKeys = ref([]); watch([currentExpandedKeys, transformData, initLoadingKeys], () => { // 缓存每个节点的状态,性能更优 transformData.value.forEach(key => { const node = nodeList[key]; node.isExpanded = currentExpandedKeys.value.includes(key); node.isInitLoading = initLoadingKeys.value.includes(key); }); }, { deep: true }); const menuKeys = computed(() => { return [].concat(ROOT_MENU_KEY, currentExpandedKeys.value.filter(value => { // 已加载且非叶子节点 return nodeList[value] && !nodeList[value].isLeaf; })); }); const transformNode = function (item, indexPath, level) { let path = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : []; const value = item[props.valueField]; const label = item[props.labelField]; const children = item[props.childrenField]; const hasChildren = !!(Array.isArray(children) && children.length); let isLeaf; if (!isNil(item.isLeaf)) { isLeaf = item.isLeaf; } else if (hasChildren) { isLeaf = false; } else if (props.remote) { isLeaf = false; } else { isLeaf = true; } let copy; const newItem = { origin: item, prefix: item.prefix, suffix: item.suffix, disabled: item.disabled, selectable: item.selectable, checkable: item.checkable, value, label, isLeaf, children, hasChildren, level, indexPath: [...indexPath, value], path: [...path, { value, label }], childrenValues: hasChildren ? children === null || children === void 0 ? void 0 : children.map(node => node[props.valueField]) : [] }; // Object.assign 比解构快很多 if (!nodeList[value]) { copy = Object.assign({}, newItem); } else { copy = nodeList[value]; Object.assign(copy, newItem); } return copy; }; const flatNodes = function () { let nodes = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; let indexPath = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; let level = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1; let path = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : []; return nodes.reduce((res, node) => { const copy = transformNode(node, indexPath, level, path); // 扁平化 nodeList[copy.value] = copy; res.push(copy.value); if (copy.hasChildren) { res = res.concat(flatNodes(copy.children, copy.indexPath, level + 1, copy.path)); } return res; }, []); }; watch(() => props.data, async () => { // 初始化加载,仅支持 props.data 为响应式空数组的场景 if (props.remote && props.loadData && isEmpty(props.data)) { initialLoaded.value = false; try { const children = await props.loadData(null); if (isArray(children)) { children.forEach(item => props.data.push(item)); } await nextTick(); } catch (e) { console.error(e); } initialLoaded.value = true; } else { transformData.value = flatNodes(props.data); } }, { immediate: true, deep: true }); const syncLoadNode = async function () { let loadedKeys = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; const needLoadNodes = props.initLoadKeys.map(key => nodeList[key]).filter(node => !!node && !node.isLeaf && !node.hasChildren && !loadedKeys.includes(node.value) // 避免因为加载失败而死循环 ); // 继续递归处理 if (needLoadNodes.length) { needLoadNodes.forEach(async node => { initLoadingKeys.value.push(node.value); try { const children = await props.loadData(_objectSpread({}, node.origin)); if (isArray(children)) { node.origin[props.childrenField] = children; } await nextTick(); } catch (e) { console.error(e); } initLoadingKeys.value = initLoadingKeys.value.filter(value => value !== node.value); loadedKeys.push(node.value); syncLoadNode(loadedKeys); }); } }; watch([initialLoaded, () => props.initLoadKeys], () => { if (!initialLoaded.value) { return; } if (!(props.remote && props.loadData)) { return; } syncLoadNode(); }, { immediate: true }); return { transformData, nodeList, menuKeys, initialLoaded }; } export { useData as default };