sard-uniapp
Version:
sard-uniapp 是一套基于 Uniapp + Vue3 框架开发的兼容多端的 UI 组件库
194 lines (193 loc) • 6.12 kB
JavaScript
import { computed, inject, reactive, ref, shallowRef, watch, } from 'vue';
import { cascaderOptionsContextSymbol, } from './common';
import { isNumber, isString, setCheckedRecursively, walkAncestor, walkNodes, } from '../../utils';
export function useCascaderTree(props, config) {
const { useOptionKeysReturn: { getValue, getLabel, getDisabled, getIsLeaf, getChildren, }, innerValue, } = config;
const options = computed(() => props.options || []);
const legacyLoadChildren = ref(false);
const treeData = ref([]);
const originalTreeData = shallowRef([]);
const loadStatus = ref('loaded');
const toStateNodes = (options, parent) => {
return options.map((option) => {
const key = getValue(option);
const stateNode = reactive({
label: getLabel(option),
value: getValue(option),
key,
disabled: !!getDisabled(option),
parent,
isLeaf: !!getIsLeaf(option),
depth: parent ? parent.depth + 1 : 0,
indeterminate: false,
checked: false,
selected: false,
loadStatus: 'idle',
option,
});
const children = getChildren(option);
if (children) {
stateNode.children = toStateNodes(children, stateNode);
}
treeMap.value[key] = stateNode;
return stateNode;
});
};
const isLeaf = (node) => {
return node.isLeaf || !Array.isArray(node.children);
};
const clearSelected = () => {
walkNodes(treeData.value, (node) => {
node.selected = false;
});
};
const setAncestorSelected = (node) => {
walkAncestor(node, (node) => {
node.selected = true;
});
};
const setSelectedByNode = (node) => {
clearSelected();
setAncestorSelected(node);
};
const clearChecked = () => {
walkNodes(treeData.value, (node) => {
node.checked = false;
node.indeterminate = false;
});
};
const setCheckedByNode = (node, checked) => {
setCheckedRecursively(node, checked, props.checkStrictly);
};
const getCheckedLeaves = () => {
const nodes = [];
walkNodes(treeData.value, (node) => {
if (node.checked && isLeaf(node)) {
nodes.push(node);
}
});
return nodes;
};
const getCheckedNodes = () => {
const nodes = [];
walkNodes(treeData.value, (node) => {
if (node.checked) {
nodes.push(node);
}
});
return nodes;
};
const getAncestors = (node) => {
const nodes = [];
walkAncestor(node, (node) => {
nodes.unshift(node);
});
return nodes;
};
const updateChecked = (value) => {
clearSelected();
// 多选
if (props.multiple) {
clearChecked();
if (Array.isArray(value)) {
let lastNode;
const maySetChecked = (value) => {
if (isString(value) || isNumber(value)) {
const node = treeMap.value[value];
if (node) {
lastNode = node;
setCheckedByNode(node, true);
}
}
};
// 全路径
if (props.allLevels) {
value.forEach((item) => {
if (Array.isArray(item)) {
maySetChecked(item[item.length - 1]);
}
});
}
// 最后一级
else {
value.forEach(maySetChecked);
}
if (lastNode) {
setAncestorSelected(lastNode);
}
}
}
// 单选
else {
const maySetSelected = (value) => {
if (isString(value) || isNumber(value)) {
const node = treeMap.value[value];
if (node) {
setAncestorSelected(node);
}
}
};
// 全路径
if (props.allLevels) {
if (Array.isArray(value)) {
maySetSelected(value[value.length - 1]);
}
}
// 最后一级
else {
maySetSelected(value);
}
}
};
const initialize = async () => {
if (props.lazy && props.load) {
try {
loadStatus.value = 'loading';
const data = await props.load();
loadStatus.value = 'loaded';
initializeTree(data);
}
catch {
loadStatus.value = 'error';
}
}
else {
initializeTree(options.value);
}
};
const treeMap = shallowRef({});
const initializeTree = (data) => {
if (legacyLoadChildren.value) {
legacyLoadChildren.value = false;
return;
}
treeMap.value = {};
treeData.value = toStateNodes(data, null);
updateChecked(innerValue.value);
originalTreeData.value = data;
};
watch(options, () => {
initializeTree(options.value);
});
const optionsContext = inject(cascaderOptionsContextSymbol, null);
watch(originalTreeData, () => {
if (optionsContext) {
optionsContext.set(originalTreeData.value);
}
});
return {
treeData,
originalTreeData,
loadStatus,
legacyLoadChildren,
toStateNodes,
setSelectedByNode,
updateChecked,
setCheckedByNode,
isLeaf,
getCheckedLeaves,
getCheckedNodes,
getAncestors,
initialize,
};
}