vxe-pc-ui
Version:
A vue based PC component library
1,388 lines (1,387 loc) • 43.2 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _vue = require("vue");
var _ui = require("../../ui");
var _xeUtils = _interopRequireDefault(require("xe-utils"));
var _vn = require("../../ui/src/vn");
var _dom = require("../../ui/src/dom");
var _loading = _interopRequireDefault(require("../../loading/src/loading"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* 生成节点的唯一主键
*/
function getNodeUniqueId() {
return _xeUtils.default.uniqueId('node_');
}
var _default = exports.default = (0, _vue.defineComponent)({
name: 'VxeTree',
props: {
data: Array,
height: [String, Number],
minHeight: {
type: [String, Number],
default: () => (0, _ui.getConfig)().tree.minHeight
},
loading: Boolean,
loadingConfig: Object,
accordion: {
type: Boolean,
default: () => (0, _ui.getConfig)().tree.accordion
},
childrenField: {
type: String,
default: () => (0, _ui.getConfig)().tree.childrenField
},
valueField: {
type: String,
default: () => (0, _ui.getConfig)().tree.valueField
},
keyField: {
type: String,
default: () => (0, _ui.getConfig)().tree.keyField
},
parentField: {
type: String,
default: () => (0, _ui.getConfig)().tree.parentField
},
titleField: {
type: String,
default: () => (0, _ui.getConfig)().tree.titleField
},
hasChildField: {
type: String,
default: () => (0, _ui.getConfig)().tree.hasChildField
},
// mapChildrenField: {
// type: String as PropType<VxeTreePropTypes.MapChildrenField>,
// default: () => getConfig().tree.mapChildrenField
// },
transform: Boolean,
// 已废弃
isCurrent: Boolean,
// 已废弃
isHover: Boolean,
expandAll: Boolean,
showLine: {
type: Boolean,
default: () => (0, _ui.getConfig)().tree.showLine
},
trigger: String,
indent: {
type: Number,
default: () => (0, _ui.getConfig)().tree.indent
},
showRadio: {
type: Boolean,
default: () => (0, _ui.getConfig)().tree.showRadio
},
checkNodeKey: {
type: [String, Number],
default: () => (0, _ui.getConfig)().tree.checkNodeKey
},
radioConfig: Object,
showCheckbox: {
type: Boolean,
default: () => (0, _ui.getConfig)().tree.showCheckbox
},
checkNodeKeys: {
type: Array,
default: () => (0, _ui.getConfig)().tree.checkNodeKeys
},
checkboxConfig: Object,
nodeConfig: Object,
lazy: Boolean,
toggleMethod: Function,
loadMethod: Function,
showIcon: {
type: Boolean,
default: true
},
iconOpen: {
type: String,
default: () => (0, _ui.getConfig)().tree.iconOpen
},
iconClose: {
type: String,
default: () => (0, _ui.getConfig)().tree.iconClose
},
iconLoaded: {
type: String,
default: () => (0, _ui.getConfig)().tree.iconLoaded
},
size: {
type: String,
default: () => (0, _ui.getConfig)().tree.size || (0, _ui.getConfig)().size
}
},
emits: ['update:modelValue', 'update:checkNodeKey', 'update:checkNodeKeys', 'node-click', 'node-dblclick', 'current-change', 'radio-change', 'checkbox-change', 'load-success', 'load-error'],
setup(props, context) {
const {
emit,
slots
} = context;
const xID = _xeUtils.default.uniqueId();
const {
computeSize
} = (0, _ui.useSize)(props);
const refElem = (0, _vue.ref)();
const reactData = (0, _vue.reactive)({
currentNode: null,
nodeMaps: {},
selectRadioKey: props.checkNodeKey,
treeList: [],
treeExpandedMaps: {},
treeExpandLazyLoadedMaps: {},
selectCheckboxMaps: {},
indeterminateCheckboxMaps: {}
});
const internalData = {
// initialized: false
};
const refMaps = {
refElem
};
const computeTitleField = (0, _vue.computed)(() => {
return props.titleField || 'title';
});
const computeKeyField = (0, _vue.computed)(() => {
return props.keyField || 'id';
});
const computeValueField = (0, _vue.computed)(() => {
const keyField = computeKeyField.value;
return props.valueField || keyField;
});
const computeParentField = (0, _vue.computed)(() => {
return props.parentField || 'parentId';
});
const computeChildrenField = (0, _vue.computed)(() => {
return props.childrenField || 'children';
});
const computeHasChildField = (0, _vue.computed)(() => {
return props.hasChildField || 'hasChild';
});
const computeIsRowCurrent = (0, _vue.computed)(() => {
const nodeOpts = computeNodeOpts.value;
const {
isCurrent
} = nodeOpts;
if (_xeUtils.default.isBoolean(isCurrent)) {
return isCurrent;
}
return props.isCurrent;
});
const computeIsRowHover = (0, _vue.computed)(() => {
const nodeOpts = computeNodeOpts.value;
const {
isHover
} = nodeOpts;
if (_xeUtils.default.isBoolean(isHover)) {
return isHover;
}
return props.isHover;
});
const computeRadioOpts = (0, _vue.computed)(() => {
return Object.assign({
showIcon: true
}, (0, _ui.getConfig)().tree.radioConfig, props.radioConfig);
});
const computeCheckboxOpts = (0, _vue.computed)(() => {
return Object.assign({
showIcon: true
}, (0, _ui.getConfig)().tree.checkboxConfig, props.checkboxConfig);
});
const computeNodeOpts = (0, _vue.computed)(() => {
return Object.assign({}, (0, _ui.getConfig)().tree.nodeConfig, props.nodeConfig);
});
const computeLoadingOpts = (0, _vue.computed)(() => {
return Object.assign({}, (0, _ui.getConfig)().tree.loadingConfig, props.loadingConfig);
});
const computeTreeStyle = (0, _vue.computed)(() => {
const {
height,
minHeight
} = props;
const stys = {};
if (height) {
stys.height = (0, _dom.toCssUnit)(height);
}
if (minHeight) {
stys.minHeight = (0, _dom.toCssUnit)(minHeight);
}
return stys;
});
const computeMaps = {
computeRadioOpts,
computeCheckboxOpts,
computeNodeOpts
};
const $xeTree = {
xID,
props,
context,
internalData,
reactData,
getRefMaps: () => refMaps,
getComputeMaps: () => computeMaps
};
const getNodeId = node => {
const valueField = computeValueField.value;
const nodeid = _xeUtils.default.get(node, valueField);
return _xeUtils.default.eqNull(nodeid) ? '' : encodeURIComponent(nodeid);
};
const isExpandByNode = node => {
const {
treeExpandedMaps
} = reactData;
const nodeid = getNodeId(node);
return !!treeExpandedMaps[nodeid];
};
const isCheckedByRadioNodeId = nodeid => {
const {
selectRadioKey
} = reactData;
return selectRadioKey === nodeid;
};
const isCheckedByRadioNode = node => {
return isCheckedByRadioNodeId(getNodeId(node));
};
const isCheckedByCheckboxNodeId = nodeid => {
const {
selectCheckboxMaps
} = reactData;
return !!selectCheckboxMaps[nodeid];
};
const isCheckedByCheckboxNode = node => {
return isCheckedByCheckboxNodeId(getNodeId(node));
};
const isIndeterminateByCheckboxNodeid = nodeid => {
const {
indeterminateCheckboxMaps
} = reactData;
return !!indeterminateCheckboxMaps[nodeid];
};
const isIndeterminateByCheckboxNode = node => {
return isIndeterminateByCheckboxNodeid(getNodeId(node));
};
const emitCheckboxMode = value => {
emit('update:checkNodeKeys', value);
};
const emitRadioMode = value => {
emit('update:checkNodeKey', value);
};
const setRadioNode = node => {
if (node) {
reactData.selectRadioKey = getNodeId(node);
}
return (0, _vue.nextTick)();
};
const setCheckboxNode = (nodeList, checked) => {
if (nodeList) {
if (!_xeUtils.default.isArray(nodeList)) {
nodeList = [nodeList];
}
handleCheckedCheckboxNode(nodeList.map(item => getNodeId(item)), checked);
}
return (0, _vue.nextTick)();
};
const setCheckboxByNodeId = (nodeIds, checked) => {
if (nodeIds) {
if (!_xeUtils.default.isArray(nodeIds)) {
nodeIds = [nodeIds];
}
handleCheckedCheckboxNode(nodeIds, checked);
}
return (0, _vue.nextTick)();
};
const handleCheckedCheckboxNode = (nodeIds, checked) => {
const selectKeyMaps = Object.assign({}, reactData.selectCheckboxMaps);
nodeIds.forEach(key => {
if (checked) {
selectKeyMaps[key] = true;
} else if (selectKeyMaps[key]) {
delete selectKeyMaps[key];
}
});
reactData.selectCheckboxMaps = selectKeyMaps;
};
const updateCheckboxChecked = nodeIds => {
const selectKeyMaps = {};
if (nodeIds) {
nodeIds.forEach(key => {
selectKeyMaps[key] = true;
});
}
reactData.selectCheckboxMaps = selectKeyMaps;
};
const handleSetExpand = (nodeid, expanded, expandedMaps) => {
if (expanded) {
if (!expandedMaps[nodeid]) {
expandedMaps[nodeid] = true;
}
} else {
if (expandedMaps[nodeid]) {
delete expandedMaps[nodeid];
}
}
};
const dispatchEvent = (type, params, evnt) => {
emit(type, (0, _ui.createEvent)(evnt, {
$tree: $xeTree
}, params));
};
const createNode = records => {
const valueField = computeValueField.value;
return Promise.resolve(records.map(obj => {
const item = Object.assign({}, obj);
let nodeid = getNodeId(item);
if (!nodeid) {
nodeid = getNodeUniqueId();
_xeUtils.default.set(item, valueField, nodeid);
}
return item;
}));
};
const treeMethods = {
dispatchEvent,
clearCurrentNode() {
reactData.currentNode = null;
return (0, _vue.nextTick)();
},
getCurrentNodeId() {
const {
currentNode
} = reactData;
if (currentNode) {
return getNodeId(currentNode);
}
return null;
},
getCurrentNode() {
const {
currentNode,
nodeMaps
} = reactData;
if (currentNode) {
const nodeItem = nodeMaps[getNodeId(currentNode)];
if (nodeItem) {
return nodeItem.item;
}
}
return null;
},
setCurrentNodeId(nodeKey) {
const {
nodeMaps
} = reactData;
const nodeItem = nodeMaps[nodeKey];
reactData.currentNode = nodeItem ? nodeItem.item : null;
return (0, _vue.nextTick)();
},
setCurrentNode(node) {
reactData.currentNode = node;
return (0, _vue.nextTick)();
},
clearRadioNode() {
reactData.selectRadioKey = null;
return (0, _vue.nextTick)();
},
getRadioNodeId() {
return reactData.selectRadioKey || null;
},
getRadioNode() {
const {
selectRadioKey,
nodeMaps
} = reactData;
if (selectRadioKey) {
const nodeItem = nodeMaps[selectRadioKey];
if (nodeItem) {
return nodeItem.item;
}
}
return null;
},
setRadioNodeId(nodeKey) {
reactData.selectRadioKey = nodeKey;
return (0, _vue.nextTick)();
},
setRadioNode,
setCheckboxNode,
setCheckboxByNodeId,
getCheckboxNodeIds() {
const {
selectCheckboxMaps
} = reactData;
return Object.keys(selectCheckboxMaps);
},
getCheckboxNodes() {
const {
nodeMaps,
selectCheckboxMaps
} = reactData;
const list = [];
_xeUtils.default.each(selectCheckboxMaps, (item, nodeid) => {
const nodeItem = nodeMaps[nodeid];
if (nodeItem) {
list.push(nodeItem.item);
}
});
return list;
},
clearCheckboxNode() {
reactData.selectCheckboxMaps = {};
return (0, _vue.nextTick)();
},
setAllCheckboxNode(checked) {
const selectMaps = {};
const childrenField = computeChildrenField.value;
if (checked) {
_xeUtils.default.eachTree(reactData.treeList, node => {
const nodeid = getNodeId(node);
selectMaps[nodeid] = true;
}, {
children: childrenField
});
}
reactData.selectCheckboxMaps = selectMaps;
return (0, _vue.nextTick)();
},
clearExpandNode() {
return treeMethods.clearAllExpandNode();
},
clearAllExpandNode() {
_xeUtils.default.each(reactData.nodeMaps, nodeItem => {
nodeItem.treeLoaded = false;
});
reactData.treeExpandedMaps = {};
return (0, _vue.nextTick)();
},
setExpandByNodeId(nodeids, expanded) {
const expandedMaps = Object.assign({}, reactData.treeExpandedMaps);
if (nodeids) {
if (!_xeUtils.default.isArray(nodeids)) {
nodeids = [nodeids];
}
nodeids.forEach(nodeid => {
handleSetExpand(nodeid, expanded, expandedMaps);
});
reactData.treeExpandedMaps = expandedMaps;
}
return (0, _vue.nextTick)();
},
getExpandNodeIds() {
const {
treeExpandedMaps
} = reactData;
return Object.keys(treeExpandedMaps);
},
getExpandNodes() {
const {
nodeMaps,
treeExpandedMaps
} = reactData;
const list = [];
_xeUtils.default.each(treeExpandedMaps, (item, nodeid) => {
const nodeItem = nodeMaps[nodeid];
if (nodeItem) {
list.push(nodeItem.item);
}
});
return list;
},
setExpandNode(nodes, expanded) {
const expandedMaps = Object.assign({}, reactData.treeExpandedMaps);
if (nodes) {
if (!_xeUtils.default.isArray(nodes)) {
nodes = [nodes];
}
nodes.forEach(node => {
const nodeid = getNodeId(node);
handleSetExpand(nodeid, expanded, expandedMaps);
});
reactData.treeExpandedMaps = expandedMaps;
}
return (0, _vue.nextTick)();
},
toggleExpandByNodeId(nodeids) {
const expandedMaps = Object.assign({}, reactData.treeExpandedMaps);
if (nodeids) {
if (!_xeUtils.default.isArray(nodeids)) {
nodeids = [nodeids];
}
nodeids.forEach(nodeid => {
handleSetExpand(nodeid, !expandedMaps[nodeid], expandedMaps);
});
reactData.treeExpandedMaps = expandedMaps;
}
return (0, _vue.nextTick)();
},
toggleExpandNode(nodes) {
const expandedMaps = Object.assign({}, reactData.treeExpandedMaps);
if (nodes) {
if (!_xeUtils.default.isArray(nodes)) {
nodes = [nodes];
}
nodes.forEach(node => {
const nodeid = getNodeId(node);
handleSetExpand(nodeid, !expandedMaps[nodeid], expandedMaps);
});
reactData.treeExpandedMaps = expandedMaps;
}
return (0, _vue.nextTick)();
},
setAllExpandNode(expanded) {
const expandedMaps = {};
const childrenField = computeChildrenField.value;
if (expanded) {
_xeUtils.default.eachTree(reactData.treeList, node => {
const childList = _xeUtils.default.get(node, childrenField);
const hasChild = childList && childList.length;
if (hasChild) {
const nodeid = getNodeId(node);
expandedMaps[nodeid] = true;
}
}, {
children: childrenField
});
}
reactData.treeExpandedMaps = expandedMaps;
return (0, _vue.nextTick)();
},
reloadExpandNode(node) {
const {
lazy
} = props;
if (lazy) {
treeMethods.clearExpandLoaded(node);
return handleAsyncTreeExpandChilds(node);
}
return (0, _vue.nextTick)();
},
clearExpandLoaded(node) {
const {
lazy
} = props;
const {
nodeMaps
} = reactData;
if (lazy) {
const nodeItem = nodeMaps[getNodeId(node)];
if (nodeItem) {
nodeItem.treeLoaded = false;
}
}
return (0, _vue.nextTick)();
},
/**
* 用于树结构,给行数据加载子节点
*/
loadChildrenNode(node, childRecords) {
const {
lazy,
transform
} = props;
const {
nodeMaps
} = reactData;
if (!lazy) {
return Promise.resolve([]);
}
const childrenField = computeChildrenField.value;
const parentNodeItem = nodeMaps[getNodeId(node)];
const parentLevel = parentNodeItem ? parentNodeItem.level : 0;
const parentNodes = parentNodeItem ? parentNodeItem.nodes : [];
return createNode(childRecords).then(nodeList => {
_xeUtils.default.eachTree(nodeList, (childRow, index, items, path, parent, nodes) => {
const itemNodeId = getNodeId(childRow);
nodeMaps[itemNodeId] = {
item: node,
itemIndex: -1,
items,
parent: parent || parentNodeItem.item,
nodes: parentNodes.concat(nodes),
level: parentLevel + nodes.length,
lineCount: 0,
treeLoaded: false
};
}, {
children: childrenField
});
node[childrenField] = nodeList;
if (transform) {
node[childrenField] = nodeList;
}
updateNodeLine(node);
return nodeList;
});
},
isExpandByNode,
isCheckedByRadioNodeId,
isCheckedByRadioNode,
isCheckedByCheckboxNodeId,
isIndeterminateByCheckboxNode,
isCheckedByCheckboxNode,
getCheckboxIndeterminateNodes() {
const {
treeList,
indeterminateCheckboxMaps
} = reactData;
const indeterminateNodes = [];
_xeUtils.default.eachTree(treeList, node => {
if (indeterminateCheckboxMaps[getNodeId(node)]) {
indeterminateNodes.push(node);
}
});
return indeterminateNodes;
}
};
const cacheNodeMap = () => {
const {
treeList
} = reactData;
const valueField = computeValueField.value;
const childrenField = computeChildrenField.value;
const keyMaps = {};
_xeUtils.default.eachTree(treeList, (item, itemIndex, items, path, parent, nodes) => {
let nodeid = getNodeId(item);
if (!nodeid) {
nodeid = getNodeUniqueId();
_xeUtils.default.set(item, valueField, nodeid);
}
keyMaps[nodeid] = {
item,
itemIndex,
items,
parent,
nodes,
level: nodes.length,
lineCount: 0,
treeLoaded: false
};
}, {
children: childrenField
});
reactData.nodeMaps = keyMaps;
};
const updateData = list => {
const {
expandAll,
transform
} = props;
const {
initialized
} = internalData;
const keyField = computeKeyField.value;
const parentField = computeParentField.value;
const childrenField = computeChildrenField.value;
if (transform) {
reactData.treeList = _xeUtils.default.toArrayTree(list, {
key: keyField,
parentKey: parentField,
mapChildren: childrenField
});
} else {
reactData.treeList = list ? list.slice(0) : [];
}
cacheNodeMap();
if (expandAll && !initialized) {
if (list && list.length) {
internalData.initialized = true;
$xeTree.setAllExpandNode(true);
}
}
};
const handleCountLine = (item, isRoot, nodeItem) => {
const {
treeExpandedMaps
} = reactData;
const childrenField = computeChildrenField.value;
const nodeid = getNodeId(item);
nodeItem.lineCount++;
if (treeExpandedMaps[nodeid]) {
_xeUtils.default.arrayEach(item[childrenField], (childItem, childIndex, childList) => {
if (!isRoot || childIndex < childList.length - 1) {
handleCountLine(childItem, false, nodeItem);
}
});
}
};
const updateNodeLine = node => {
const {
nodeMaps
} = reactData;
if (node) {
const nodeid = getNodeId(node);
const nodeItem = nodeMaps[nodeid];
if (nodeItem) {
_xeUtils.default.lastArrayEach(nodeItem.nodes, childItem => {
const nodeid = getNodeId(childItem);
const nodeItem = nodeMaps[nodeid];
if (nodeItem) {
nodeItem.lineCount = 0;
handleCountLine(childItem, true, nodeItem);
}
});
}
}
};
const handleNodeClickEvent = (evnt, node) => {
const {
showRadio,
showCheckbox,
trigger
} = props;
const radioOpts = computeRadioOpts.value;
const checkboxOpts = computeCheckboxOpts.value;
const isRowCurrent = computeIsRowCurrent.value;
let triggerCurrent = false;
let triggerRadio = false;
let triggerCheckbox = false;
let triggerExpand = false;
if (isRowCurrent) {
triggerCurrent = true;
changeCurrentEvent(evnt, node);
} else if (reactData.currentNode) {
reactData.currentNode = null;
}
if (trigger === 'node') {
triggerExpand = true;
toggleExpandEvent(evnt, node);
}
if (showRadio && radioOpts.trigger === 'node') {
triggerRadio = true;
changeRadioEvent(evnt, node);
}
if (showCheckbox && checkboxOpts.trigger === 'node') {
triggerCheckbox = true;
changeCheckboxEvent(evnt, node);
}
dispatchEvent('node-click', {
node,
triggerCurrent,
triggerRadio,
triggerCheckbox,
triggerExpand
}, evnt);
};
const handleNodeDblclickEvent = (evnt, node) => {
dispatchEvent('node-dblclick', {
node
}, evnt);
};
const handleAsyncTreeExpandChilds = node => {
const checkboxOpts = computeCheckboxOpts.value;
const {
loadMethod
} = props;
const {
checkStrictly
} = checkboxOpts;
return new Promise(resolve => {
if (loadMethod) {
const tempExpandLazyLoadedMaps = Object.assign({}, reactData.treeExpandLazyLoadedMaps);
const {
nodeMaps
} = reactData;
const nodeid = getNodeId(node);
const nodeItem = nodeMaps[nodeid];
tempExpandLazyLoadedMaps[nodeid] = true;
reactData.treeExpandLazyLoadedMaps = tempExpandLazyLoadedMaps;
Promise.resolve(loadMethod({
$tree: $xeTree,
node
})).then(childRecords => {
const {
treeExpandLazyLoadedMaps
} = reactData;
nodeItem.treeLoaded = true;
if (treeExpandLazyLoadedMaps[nodeid]) {
treeExpandLazyLoadedMaps[nodeid] = false;
}
if (!_xeUtils.default.isArray(childRecords)) {
childRecords = [];
}
if (childRecords) {
return treeMethods.loadChildrenNode(node, childRecords).then(childRows => {
const tempExpandedMaps = Object.assign({}, reactData.treeExpandedMaps);
if (childRows.length && !tempExpandedMaps[nodeid]) {
tempExpandedMaps[nodeid] = true;
}
reactData.treeExpandedMaps = tempExpandedMaps;
// 如果当前节点已选中,则展开后子节点也被选中
if (!checkStrictly && treeMethods.isCheckedByCheckboxNodeId(nodeid)) {
handleCheckedCheckboxNode(childRows.map(item => getNodeId(item)), true);
}
updateNodeLine(node);
dispatchEvent('load-success', {
node,
data: childRecords
}, new Event('load-success'));
return (0, _vue.nextTick)();
});
} else {
updateNodeLine(node);
dispatchEvent('load-success', {
node,
data: childRecords
}, new Event('load-success'));
}
}).catch(e => {
const {
treeExpandLazyLoadedMaps
} = reactData;
nodeItem.treeLoaded = false;
if (treeExpandLazyLoadedMaps[nodeid]) {
treeExpandLazyLoadedMaps[nodeid] = false;
}
updateNodeLine(node);
dispatchEvent('load-error', {
node,
data: e
}, new Event('load-error'));
}).finally(() => {
return (0, _vue.nextTick)();
});
} else {
resolve();
}
});
};
/**
* 展开与收起树节点
* @param nodeList
* @param expanded
* @returns
*/
const handleBaseTreeExpand = (nodeList, expanded) => {
const {
lazy,
accordion,
toggleMethod
} = props;
const {
nodeMaps,
treeExpandLazyLoadedMaps
} = reactData;
const tempExpandedMaps = Object.assign({}, reactData.treeExpandedMaps);
const childrenField = computeChildrenField.value;
const hasChildField = computeHasChildField.value;
const result = [];
let validNodes = toggleMethod ? nodeList.filter(node => toggleMethod({
$tree: $xeTree,
expanded,
node
})) : nodeList;
if (accordion) {
validNodes = validNodes.length ? [validNodes[validNodes.length - 1]] : [];
// 同一级只能展开一个
const nodeid = getNodeId(validNodes[0]);
const nodeItem = nodeMaps[nodeid];
if (nodeItem) {
nodeItem.items.forEach(item => {
const itemNodeId = getNodeId(item);
if (tempExpandedMaps[itemNodeId]) {
delete tempExpandedMaps[itemNodeId];
}
});
}
}
const expandNodes = [];
if (expanded) {
validNodes.forEach(item => {
const itemNodeId = getNodeId(item);
if (!tempExpandedMaps[itemNodeId]) {
const nodeItem = nodeMaps[itemNodeId];
const isLoad = lazy && item[hasChildField] && !nodeItem.treeLoaded && !treeExpandLazyLoadedMaps[itemNodeId];
// 是否使用懒加载
if (isLoad) {
result.push(handleAsyncTreeExpandChilds(item));
} else {
if (item[childrenField] && item[childrenField].length) {
tempExpandedMaps[itemNodeId] = true;
expandNodes.push(item);
}
}
}
});
} else {
validNodes.forEach(item => {
const itemNodeId = getNodeId(item);
if (tempExpandedMaps[itemNodeId]) {
delete tempExpandedMaps[itemNodeId];
expandNodes.push(item);
}
});
}
reactData.treeExpandedMaps = tempExpandedMaps;
expandNodes.forEach(updateNodeLine);
return Promise.all(result);
};
const toggleExpandEvent = (evnt, node) => {
const {
lazy
} = props;
const {
treeExpandedMaps,
treeExpandLazyLoadedMaps
} = reactData;
const nodeid = getNodeId(node);
const expanded = !treeExpandedMaps[nodeid];
evnt.stopPropagation();
if (!lazy || !treeExpandLazyLoadedMaps[nodeid]) {
handleBaseTreeExpand([node], expanded);
}
};
const handleNodeCheckboxStatus = (node, selectKeyMaps, indeterminateMaps) => {
const childrenField = computeChildrenField.value;
const childList = _xeUtils.default.get(node, childrenField);
const nodeid = getNodeId(node);
if (childList && childList.length) {
let checkSome = false;
let checkSize = 0;
childList.forEach(childNode => {
const childNodeid = getNodeId(childNode);
const isChecked = selectKeyMaps[childNodeid];
if (isChecked || indeterminateMaps[childNodeid]) {
if (isChecked) {
checkSize++;
}
checkSome = true;
}
});
const checkAll = checkSize === childList.length;
if (checkAll) {
if (!selectKeyMaps[nodeid]) {
selectKeyMaps[nodeid] = true;
}
if (indeterminateMaps[nodeid]) {
delete indeterminateMaps[nodeid];
}
} else {
if (selectKeyMaps[nodeid]) {
delete selectKeyMaps[nodeid];
}
indeterminateMaps[nodeid] = checkSome;
}
} else {
if (indeterminateMaps[nodeid]) {
delete indeterminateMaps[nodeid];
}
}
};
const updateCheckboxStatus = () => {
const {
treeList
} = reactData;
const childrenField = computeChildrenField.value;
const checkboxOpts = computeCheckboxOpts.value;
const {
checkStrictly
} = checkboxOpts;
if (!checkStrictly) {
const selectKeyMaps = Object.assign({}, reactData.selectCheckboxMaps);
const indeterminateMaps = {};
_xeUtils.default.eachTree(treeList, (node, index, items, path, parent, nodes) => {
const childList = _xeUtils.default.get(node, childrenField);
if (!childList || !childList.length) {
handleNodeCheckboxStatus(node, selectKeyMaps, indeterminateMaps);
}
if (index === items.length - 1) {
for (let len = nodes.length - 2; len >= 0; len--) {
const parentItem = nodes[len];
handleNodeCheckboxStatus(parentItem, selectKeyMaps, indeterminateMaps);
}
}
});
reactData.selectCheckboxMaps = selectKeyMaps;
reactData.indeterminateCheckboxMaps = indeterminateMaps;
}
};
const changeCheckboxEvent = (evnt, node) => {
evnt.preventDefault();
evnt.stopPropagation();
const checkboxOpts = computeCheckboxOpts.value;
const {
checkStrictly,
checkMethod
} = checkboxOpts;
let isDisabled = !!checkMethod;
if (checkMethod) {
isDisabled = !checkMethod({
node
});
}
if (isDisabled) {
return;
}
const selectKeyMaps = Object.assign({}, reactData.selectCheckboxMaps);
const childrenField = computeChildrenField.value;
const nodeid = getNodeId(node);
let isChecked = false;
if (selectKeyMaps[nodeid]) {
delete selectKeyMaps[nodeid];
} else {
isChecked = true;
selectKeyMaps[nodeid] = isChecked;
}
if (!checkStrictly) {
_xeUtils.default.eachTree(_xeUtils.default.get(node, childrenField), childNode => {
const childNodeid = getNodeId(childNode);
if (isChecked) {
if (!selectKeyMaps[childNodeid]) {
selectKeyMaps[childNodeid] = true;
}
} else {
if (selectKeyMaps[childNodeid]) {
delete selectKeyMaps[childNodeid];
}
}
}, {
children: childrenField
});
}
reactData.selectCheckboxMaps = selectKeyMaps;
updateCheckboxStatus();
const value = Object.keys(reactData.selectCheckboxMaps);
emitCheckboxMode(value);
dispatchEvent('checkbox-change', {
node,
value,
checked: isChecked
}, evnt);
};
const changeCurrentEvent = (evnt, node) => {
evnt.preventDefault();
const nodeOpts = computeNodeOpts.value;
const {
currentMethod,
trigger
} = nodeOpts;
const childrenField = computeChildrenField.value;
const childList = _xeUtils.default.get(node, childrenField);
const hasChild = childList && childList.length;
let isDisabled = !!currentMethod;
if (trigger === 'child') {
if (hasChild) {
return;
}
} else if (trigger === 'parent') {
if (!hasChild) {
return;
}
}
if (currentMethod) {
isDisabled = !currentMethod({
node
});
}
if (isDisabled) {
return;
}
const isChecked = true;
reactData.currentNode = node;
dispatchEvent('current-change', {
node,
checked: isChecked
}, evnt);
};
const changeRadioEvent = (evnt, node) => {
evnt.preventDefault();
evnt.stopPropagation();
const radioOpts = computeRadioOpts.value;
const {
checkMethod
} = radioOpts;
let isDisabled = !!checkMethod;
if (checkMethod) {
isDisabled = !checkMethod({
node
});
}
if (isDisabled) {
return;
}
const isChecked = true;
const value = getNodeId(node);
reactData.selectRadioKey = value;
emitRadioMode(value);
dispatchEvent('radio-change', {
node,
value,
checked: isChecked
}, evnt);
};
const treePrivateMethods = {};
Object.assign($xeTree, treeMethods, treePrivateMethods);
const renderRadio = (node, nodeid, isChecked) => {
const {
showRadio
} = props;
const radioOpts = computeRadioOpts.value;
const {
showIcon,
checkMethod,
visibleMethod
} = radioOpts;
const isVisible = !visibleMethod || visibleMethod({
node
});
let isDisabled = !!checkMethod;
if (showRadio && showIcon && isVisible) {
if (checkMethod) {
isDisabled = !checkMethod({
node
});
}
return (0, _vue.h)('div', {
class: ['vxe-tree--radio-option', {
'is--checked': isChecked,
'is--disabled': isDisabled
}],
onClick: evnt => {
if (!isDisabled) {
changeRadioEvent(evnt, node);
}
}
}, [(0, _vue.h)('span', {
class: ['vxe-radio--icon', isChecked ? (0, _ui.getIcon)().RADIO_CHECKED : (0, _ui.getIcon)().RADIO_UNCHECKED]
})]);
}
return (0, _vue.createCommentVNode)();
};
const renderCheckbox = (node, nodeid, isChecked) => {
const {
showCheckbox
} = props;
const checkboxOpts = computeCheckboxOpts.value;
const {
showIcon,
checkMethod,
visibleMethod
} = checkboxOpts;
const isIndeterminate = isIndeterminateByCheckboxNodeid(nodeid);
const isVisible = !visibleMethod || visibleMethod({
node
});
let isDisabled = !!checkMethod;
if (showCheckbox && showIcon && isVisible) {
if (checkMethod) {
isDisabled = !checkMethod({
node
});
}
return (0, _vue.h)('div', {
class: ['vxe-tree--checkbox-option', {
'is--checked': isChecked,
'is--indeterminate': isIndeterminate,
'is--disabled': isDisabled
}],
onClick: evnt => {
if (!isDisabled) {
changeCheckboxEvent(evnt, node);
}
}
}, [(0, _vue.h)('span', {
class: ['vxe-checkbox--icon', isIndeterminate ? (0, _ui.getIcon)().CHECKBOX_INDETERMINATE : isChecked ? (0, _ui.getIcon)().CHECKBOX_CHECKED : (0, _ui.getIcon)().CHECKBOX_UNCHECKED]
})]);
}
return (0, _vue.createCommentVNode)();
};
const renderNode = node => {
const {
lazy,
showRadio,
showCheckbox,
showLine,
indent,
iconOpen,
iconClose,
iconLoaded,
showIcon
} = props;
const {
nodeMaps,
treeExpandedMaps,
currentNode,
selectRadioKey,
treeExpandLazyLoadedMaps
} = reactData;
const childrenField = computeChildrenField.value;
const titleField = computeTitleField.value;
const hasChildField = computeHasChildField.value;
const childList = _xeUtils.default.get(node, childrenField);
const hasChild = childList && childList.length;
const iconSlot = slots.icon;
const titleSlot = slots.title;
const extraSlot = slots.extra;
const nodeid = getNodeId(node);
const isExpand = treeExpandedMaps[nodeid];
const nodeItem = nodeMaps[nodeid];
const nodeValue = _xeUtils.default.get(node, titleField);
const childVns = [];
if (hasChild && treeExpandedMaps[nodeid]) {
if (showLine) {
childVns.push((0, _vue.h)('div', {
key: 'line',
class: 'vxe-tree--node-child-line',
style: {
height: `calc(${nodeItem.lineCount} * var(--vxe-ui-tree-node-height) - var(--vxe-ui-tree-node-height) / 2)`,
left: `${(nodeItem.level + 1) * (indent || 1)}px`
}
}));
}
childList.forEach(childItem => {
childVns.push(renderNode(childItem));
});
}
let isRadioChecked = false;
if (showRadio) {
// eslint-disable-next-line eqeqeq
isRadioChecked = nodeid == selectRadioKey;
}
let isCheckboxChecked = false;
if (showCheckbox) {
isCheckboxChecked = isCheckedByCheckboxNodeId(nodeid);
}
let hasLazyChilds = false;
let isLazyLoading = false;
let isLazyLoaded = false;
if (lazy) {
isLazyLoading = !!treeExpandLazyLoadedMaps[nodeid];
hasLazyChilds = node[hasChildField];
isLazyLoaded = !!nodeItem.treeLoaded;
}
return (0, _vue.h)('div', {
class: ['vxe-tree--node-wrapper', `node--level-${nodeItem.level}`],
nodeid
}, [(0, _vue.h)('div', {
class: ['vxe-tree--node-item', {
'is--current': currentNode && nodeid === getNodeId(currentNode),
'is-radio--checked': isRadioChecked,
'is-checkbox--checked': isCheckboxChecked
}],
style: {
paddingLeft: `${(nodeItem.level - 1) * (indent || 1)}px`
},
onClick(evnt) {
handleNodeClickEvent(evnt, node);
},
onDblclick(evnt) {
handleNodeDblclickEvent(evnt, node);
}
}, [showIcon || showLine ? (0, _vue.h)('div', {
class: 'vxe-tree--node-item-switcher'
}, showIcon && (lazy ? isLazyLoaded ? hasChild : hasLazyChilds : hasChild) ? [(0, _vue.h)('div', {
class: 'vxe-tree--node-item-icon',
onClick(evnt) {
toggleExpandEvent(evnt, node);
}
}, iconSlot ? iconSlot({
node,
isExpand
}) : [(0, _vue.h)('i', {
class: isLazyLoading ? iconLoaded || (0, _ui.getIcon)().TREE_NODE_LOADED : isExpand ? iconOpen || (0, _ui.getIcon)().TREE_NODE_OPEN : iconClose || (0, _ui.getIcon)().TREE_NODE_CLOSE
})])] : []) : (0, _vue.createCommentVNode)(), renderRadio(node, nodeid, isRadioChecked), renderCheckbox(node, nodeid, isCheckboxChecked), (0, _vue.h)('div', {
class: 'vxe-tree--node-item-inner'
}, [(0, _vue.h)('div', {
class: 'vxe-tree--node-item-title'
}, titleSlot ? (0, _vn.getSlotVNs)(titleSlot({
node,
isExpand
})) : `${nodeValue}`), extraSlot ? (0, _vue.h)('div', {
class: 'vxe-tree--node-item-extra'
}, (0, _vn.getSlotVNs)(extraSlot({
node,
isExpand
}))) : (0, _vue.createCommentVNode)()])]), hasChild && treeExpandedMaps[nodeid] ? (0, _vue.h)('div', {
class: 'vxe-tree--node-child-wrapper'
}, childVns) : (0, _vue.createCommentVNode)()]);
};
const renderNodeList = () => {
const {
treeList
} = reactData;
return (0, _vue.h)('div', {
class: 'vxe-tree--node-list-wrapper'
}, treeList.map(node => renderNode(node)));
};
const renderVN = () => {
const {
loading,
trigger,
showLine
} = props;
const vSize = computeSize.value;
const radioOpts = computeRadioOpts.value;
const checkboxOpts = computeCheckboxOpts.value;
const treeStyle = computeTreeStyle.value;
const loadingOpts = computeLoadingOpts.value;
const isRowHover = computeIsRowHover.value;
const loadingSlot = slots.loading;
return (0, _vue.h)('div', {
ref: refElem,
class: ['vxe-tree', {
[`size--${vSize}`]: vSize,
'show--line': showLine,
'checkbox--highlight': checkboxOpts.highlight,
'radio--highlight': radioOpts.highlight,
'node--hover': isRowHover,
'node--trigger': trigger === 'node',
'is--loading': loading
}],
style: treeStyle
}, [renderNodeList(),
/**
* 加载中
*/
(0, _vue.h)(_loading.default, {
class: 'vxe-tree--loading',
modelValue: loading,
icon: loadingOpts.icon,
text: loadingOpts.text
}, loadingSlot ? {
default: () => loadingSlot({
$tree: $xeTree
})
} : {})]);
};
const dataFlag = (0, _vue.ref)(0);
(0, _vue.watch)(() => props.data ? props.data.length : 0, () => {
dataFlag.value++;
});
(0, _vue.watch)(() => props.data, () => {
dataFlag.value++;
});
(0, _vue.watch)(dataFlag, () => {
updateData(props.data || []);
});
(0, _vue.watch)(() => props.checkNodeKey, val => {
reactData.selectRadioKey = val;
});
const checkboxFlag = (0, _vue.ref)(0);
(0, _vue.watch)(() => props.checkNodeKeys ? props.checkNodeKeys.length : 0, () => {
checkboxFlag.value++;
});
(0, _vue.watch)(() => props.checkNodeKeys, () => {
checkboxFlag.value++;
});
(0, _vue.watch)(checkboxFlag, () => {
updateCheckboxChecked(props.checkNodeKeys || []);
});
(0, _vue.onUnmounted)(() => {
reactData.treeList = [];
reactData.treeExpandedMaps = {};
reactData.nodeMaps = {};
});
updateData(props.data || []);
updateCheckboxChecked(props.checkNodeKeys || []);
$xeTree.renderVN = renderVN;
return $xeTree;
},
render() {
return this.renderVN();
}
});