Files
Chronic-Disease-Management/src/components/da-tree/index.vue
2025-06-25 12:27:52 +08:00

1210 lines
36 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="da-tree" :style="{ '--theme-color': themeColor }">
<scroll-view class="da-tree-scroll" :scroll-y="true" :scroll-x="false">
<view
v-for="item in datalist"
:key="item.key"
class="da-tree-item"
:class="{ 'is-show': item.show }"
:style="{ paddingLeft: item.level * indent + 'rpx' }"
>
<view
v-if="item.showArrow && !filterValue"
class="da-tree-item__icon"
@click="handleExpandedChange(item)"
>
<view
v-if="loadLoading && item.loading"
:class="['da-tree-item__icon--arr', 'is-loading']"
/>
<view
v-else
:class="['da-tree-item__icon--arr', 'is-expand', { 'is-right': !item.expand }]"
/>
</view>
<view v-else class="da-tree-item__icon" />
<view
v-if="showCheckbox"
class="da-tree-item__checkbox"
:class="[
`da-tree-item__checkbox--${checkboxPlacement}`,
{ 'is--disabled': item.disabled },
]"
@click="handleCheckChange(item)"
>
<view
v-if="item.checkedStatus === isCheckedStatus"
class="da-tree-item__checkbox--icon da-tree-checkbox-checked"
/>
<view
v-else-if="item.checkedStatus === halfCheckedStatus"
class="da-tree-item__checkbox--icon da-tree-checkbox-indeterminate"
/>
<view v-else class="da-tree-item__checkbox--icon da-tree-checkbox-outline" />
</view>
<view
v-if="!showCheckbox && showRadioIcon"
class="da-tree-item__checkbox"
:class="[
`da-tree-item__checkbox--${checkboxPlacement}`,
{ 'is--disabled': item.disabled },
]"
@click="handleRadioChange(item)"
>
<view
v-if="item.checkedStatus === isCheckedStatus"
class="da-tree-item__checkbox--icon da-tree-radio-checked"
/>
<view
v-else-if="item.checkedStatus === halfCheckedStatus"
class="da-tree-item__checkbox--icon da-tree-radio-indeterminate"
/>
<view v-else class="da-tree-item__checkbox--icon da-tree-radio-outline" />
</view>
<view
class="da-tree-item__label"
:class="'da-tree-item__label--' + item.checkedStatus"
@click="handleLabelClick(item)"
>
{{ item.label }}
<text v-if="item.append" class="da-tree-item__label--append">{{ item.append }}</text>
</view>
</view>
</scroll-view>
</view>
</template>
<script>
import { defineComponent, ref, unref, watch } from "vue";
import {
unCheckedStatus,
halfCheckedStatus,
isCheckedStatus,
deepClone,
getAllNodeKeys,
getAllNodes,
logError,
isArray,
isString,
isNumber,
isFunction,
} from "./utils";
import basicProps from "./props";
export default defineComponent({
name: "DaTree",
props: basicProps,
emits: ["change", "expand"],
setup(props, { emit }) {
/** 原始的树数据 */
const dataRef = ref([]);
/** 处理后的一维树项数据 */
const datalist = ref([]);
/** 处理后的以key为键值的树项数据 */
const datamap = ref({});
/** 默认的展开数据 */
const expandedKeys = ref([]);
/** 默认的已选数据 */
const checkedKeys = ref(null);
/** 加载状态 */
const loadLoading = ref(false);
let fieldMap = {
value: "value",
label: "label",
children: "children",
disabled: "disabled",
append: "append",
leaf: "leaf",
sort: "sort",
};
/**
* 初始化数据结构
*/
function initData() {
fieldMap = {
value: props.field?.key || props.field?.value || props.valueField || "value",
label: props.field?.label || props.labelField || "label",
children: props.field?.children || props.childrenField || "children",
disabled: props.field?.disabled || props.disabledField || "disabled",
append: props.field?.append || props.appendField || "append",
leaf: props.field?.leaf || props.leafField || "leaf",
sort: props.field?.sort || props.sortField || "sort",
};
const data = deepClone(dataRef.value);
datalist.value = [];
datamap.value = {};
// clean tree
handleTreeData(data);
// flat tree
datalist.value = checkInitData(datalist.value);
// console.log('init datalist', datalist.value)
// console.log('init datamap', datamap.value)
}
/**
* 转换为节点数据
* @param data
* @param parent
* @param level
*/
function handleTreeData(data = [], parent = null, level = 0, insertIndex = -1) {
return data.reduce((prev, cur, index) => {
const key = cur[fieldMap.value];
const children = cur[fieldMap.children] || null;
const newItem = createNewItem(cur, index, parent, level);
if (insertIndex > -1) {
// 插入子项尾部
const index = (parent.childrenKeys?.length || 0) + insertIndex + 1;
if (!parent?.childrenKeys?.includes(key)) {
datamap.value[key] = newItem;
datalist.value.splice(index, 0, newItem);
parent.children.push(newItem);
if (newItem.parentKeys?.length) {
newItem.parentKeys.forEach((k) => {
datamap.value[k].childrenKeys = [...datamap.value[k].childrenKeys, newItem.key];
});
}
}
} else {
datamap.value[key] = newItem;
datalist.value.push(newItem);
}
const hasChildren = children && children.length > 0;
if (hasChildren) {
const childrenData = handleTreeData(children, newItem, level + 1);
// childrenData.sort((a, b) => a.sort - b.sort)
newItem.children = childrenData;
const childrenKeys = childrenData.reduce((p, k) => {
const keys = k.childrenKeys;
p.push(...keys, k.key);
return p;
}, []);
newItem.childrenKeys = childrenKeys;
}
prev.push(newItem);
return prev;
}, []);
}
/**
* 创建节点
* @param item
* @param index
* @param parent
* @param level
*/
function createNewItem(item, index, parent, level) {
const key = item[fieldMap.value];
const label = item[fieldMap.label];
const sort = item[fieldMap.sort] || 0;
const children = item[fieldMap.children] || null;
const append = item[fieldMap.append] || null;
let disabled = item[fieldMap.disabled] || false;
// 优先继承父级禁用属性
disabled = parent?.disabled || disabled;
let isLeaf = isFunction(props.isLeafFn) ? props.isLeafFn(item) : item[fieldMap.leaf] || false;
// const hasChildren = children && children.length > 0
const isEmptyChildren = children && children.length === 0;
let showArrow = true;
// let isLeaf = !hasChildren
let expand = props.defaultExpandAll || false;
// 是否异步加载模式
const isLoadMode = props.loadMode && isFunction(props.loadApi);
if (!children) {
expand = false;
if (isLoadMode) {
showArrow = true;
} else {
isLeaf = true;
showArrow = false;
}
}
if (isEmptyChildren) {
expand = false;
if (isLoadMode) {
showArrow = true;
} else {
isLeaf = true;
showArrow = false;
}
}
if (isLeaf) {
showArrow = false;
expand = false;
} else {
showArrow = true;
}
// onlyRadioLeaf 单选只能选择末级节点
if (!props.showCheckbox) {
if (props.onlyRadioLeaf) {
if (!isLeaf) {
disabled = true;
} else {
// 仍旧继承父类原始禁用状态
disabled = parent?.originItem?.disabled || false;
}
}
}
if (disabled) {
if (isLeaf || !children || isEmptyChildren) {
expand = false;
showArrow = false;
}
}
const parentKey = parent ? parent.key : null;
const show = props.defaultExpandAll || level === 0;
const newItem = {
key,
parentKey,
label,
append,
isLeaf,
showArrow,
level,
expand,
show,
sort,
disabled,
loaded: false,
loading: false,
indexs: [index],
checkedStatus: unCheckedStatus,
parentKeys: [],
childrenKeys: [],
children: [],
originItem: item,
};
if (parent) {
newItem.parentKeys = [parent.key, ...parent.parentKeys];
newItem.indexs = [...parent.indexs, index];
}
return newItem;
}
/**
* 处理初始化内容
* @param list
*/
function checkInitData(list) {
let checkedKeyList = null;
let expandedKeyList = [];
if (props.showCheckbox) {
checkedKeyList = [...new Set(checkedKeys.value || [])];
expandedKeyList = props.expandChecked
? [...(checkedKeys.value || []), ...(expandedKeys.value || [])]
: expandedKeys.value;
} else {
checkedKeyList = checkedKeys.value || null;
expandedKeyList =
props.expandChecked && checkedKeys.value
? [checkedKeys.value, ...(expandedKeys.value || [])]
: expandedKeys.value;
}
handleCheckState(list, checkedKeyList, true);
// 处理初始展开
expandedKeyList = [...new Set(expandedKeyList)];
if (!props.defaultExpandAll) {
handleExpandState(list, expandedKeyList, true);
}
list.sort((a, b) => {
if (a.sort === 0 && b.sort === 0) {
return 0;
}
if (a.parentKey === b.parentKey) {
if (a.sort - b.sort > 0) {
return 1;
} else {
return -1;
}
}
return 0;
});
return list;
}
/**
* 处理选中
* @param list
* @param checkedKeyList
*/
function handleCheckState(list, checkedKeyList, checked = true) {
// 多选
if (props.showCheckbox) {
if (checkedKeyList?.length) {
checkedKeyList.forEach((k) => {
const item = datamap.value[k];
if (item) {
checkTheChecked(item, checked);
}
});
}
return;
}
// 单选
for (let i = 0; i < list.length; i++) {
const item = list[i];
if (item.key === checkedKeyList) {
checkTheRadio(item, checked);
break;
}
}
}
/**
* 校验多选节点
* @param item
* @param checked
*/
function checkTheChecked(item, checked = true) {
const { childrenKeys, parentKeys, disabled = false } = item;
if (!props.checkedDisabled && disabled) return;
// 当前
item.checkedStatus = checked ? isCheckedStatus : unCheckedStatus;
if (!props.checkStrictly) {
// 子类
childrenKeys.forEach((k) => {
const childrenItem = unref(datamap)[k];
childrenItem.checkedStatus =
!props.checkedDisabled && childrenItem.disabled
? childrenItem.checkedStatus
: item.checkedStatus;
});
// 父类
parentKeys.forEach((k) => {
const parentItem = datamap.value[k];
parentItem.checkedStatus = getParentCheckedStatus(parentItem);
});
}
}
/**
* 校验单选节点
* @param item
*/
function checkTheRadio(item, checked) {
const { parentKeys, isLeaf, disabled = false } = item;
if (!props.checkedDisabled && disabled) return;
// 限制末节点选中,但当前非末节点
if (props.onlyRadioLeaf && !isLeaf) {
logError(`限制了末节点选中,当前[${item.label}]非末节点`);
return;
}
if (datalist.value?.length) {
datalist.value.forEach((k) => {
k.checkedStatus = unCheckedStatus;
});
}
parentKeys.forEach((k) => {
const parentItem = datamap.value[k];
parentItem.checkedStatus = checked ? getParentCheckedStatus(parentItem) : unCheckedStatus;
});
// 当前
item.checkedStatus = checked ? isCheckedStatus : unCheckedStatus;
}
/**
* 处理父节点展开
* @param item
* @param expand
*/
// function handleExpandParentNode(item, expand = true) {
// if (!expand) return
// if (item?.parentKeys?.length) {
// item.parentKeys.forEach(pk => {
// if (!datamap.value[pk].expand) {
// datamap.value[pk].expand = true
// }
// })
// }
// }
/**
* 处理节点展开
* @param list
* @param expandedKeyList
* @param expand
*/
function handleExpandState(list, expandedKeyList, expand = true) {
// 收起
if (expand === false) {
for (let i = 0; i < list.length; i++) {
const item = list[i];
if (expandedKeyList?.includes(item.key)) {
item.expand = false;
if (item.childrenKeys?.length) {
item.childrenKeys.forEach((ck) => {
datamap.value[ck].expand = false;
datamap.value[ck].show = false;
});
}
}
}
return;
}
// 展开
for (let i = 0; i < list.length; i++) {
const item = list[i];
// 处理展开
if (expandedKeyList?.includes(item.key)) {
// 父子
item.expand = true;
if (item.children?.length) {
item.children.forEach((k) => {
const kItem = unref(datamap)[k.key];
kItem.show = true;
});
}
// 族系
if (item.parentKeys?.length) {
item.parentKeys.forEach((k) => {
const kItem = unref(datamap)[k];
kItem.expand = true;
if (kItem.children?.length) {
kItem.children.forEach((k) => {
const skItem = unref(datamap)[k.key];
skItem.show = true;
});
}
});
}
}
}
}
/**
* 点击选框
* @param item
*/
function handleCheckChange(item) {
const { childrenKeys, parentKeys, checkedStatus, isLeaf, disabled = false } = item;
if (!props.showCheckbox) return;
if (disabled) return;
// 当前
item.checkedStatus = checkedStatus === isCheckedStatus ? unCheckedStatus : isCheckedStatus;
// 子类
if (!props.checkStrictly) {
if (props.expandChecked) {
item.show = true;
item.expand = childrenKeys?.length > 0 || isLeaf;
}
childrenKeys.forEach((k) => {
const childrenItem = unref(datamap)[k];
childrenItem.checkedStatus = childrenItem.disabled
? childrenItem.checkedStatus
: item.checkedStatus;
if (props.expandChecked) {
childrenItem.show = true;
childrenItem.expand = childrenItem?.childrenKeys?.length > 0 || childrenItem.isLeaf;
}
});
} else {
if (props.expandChecked) {
logError(
`多选时,当 checkStrictly 为 true 时,不支持选择自动展开子节点属性(expandChecked)`
);
}
}
// 父类
if (!props.checkStrictly) {
parentKeys.forEach((k) => {
const parentItem = datamap.value[k];
parentItem.checkedStatus = getParentCheckedStatus(parentItem);
});
}
const hasCheckedKeys = [];
for (let i = 0; i < datalist.value.length; i++) {
const k = datalist.value[i];
if (k.checkedStatus === isCheckedStatus) {
if ((props.packDisabledkey && k.disabled) || !k.disabled) {
hasCheckedKeys.push(k.key);
}
}
}
checkedKeys.value = [...hasCheckedKeys];
emit("change", hasCheckedKeys, item);
}
/**
* 点击单选
* @param item
*/
function handleRadioChange(item) {
const { parentKeys, checkedStatus, key, disabled = false, isLeaf } = item;
if (props.showCheckbox) return;
if (props.onlyRadioLeaf && !isLeaf) handleExpandedChange(item);
if (disabled) return;
// 重置所有选择
if (datalist.value?.length) {
for (let i = 0; i < datalist.value.length; i++) {
const k = datalist.value[i];
k.checkedStatus = unCheckedStatus;
}
}
parentKeys.forEach((k) => {
const parentItem = datamap.value[k];
parentItem.checkedStatus = getParentCheckedStatus(parentItem);
});
// 当前
item.checkedStatus = checkedStatus === isCheckedStatus ? unCheckedStatus : isCheckedStatus;
checkedKeys.value = key;
emit("change", key, item);
}
/**
* 点击标签
*/
function handleLabelClick(item) {
if (props.showCheckbox) {
handleCheckChange(item);
} else {
handleRadioChange(item);
}
}
/**
* 点击展开收起
* @param item
*/
async function handleExpandedChange(item) {
if (props.filterValue) return;
const { expand, loading = false, disabled } = item;
if (loadLoading.value && loading) return;
checkExpandedChange(item);
// 异步
item.expand = !expand;
let currentItem = null;
if (!disabled) {
if (!props.showCheckbox && props.onlyRadioLeaf && props.loadMode) {
logError(`单选时,当 onlyRadioLeaf 为 true 时不支持动态数据`);
} else {
currentItem = await loadExpandNode(item);
}
}
emit("expand", !expand, currentItem || item || null);
}
/**
* 检查展开状态
* @param item
*/
function checkExpandedChange(item) {
const { expand, childrenKeys, children = null } = item;
if (expand) {
if (childrenKeys?.length) {
childrenKeys.forEach((k) => {
if (unref(datamap)[k]) {
unref(datamap)[k].show = false;
unref(datamap)[k].expand = false;
}
});
}
} else {
if (children?.length) {
const childrenKeys = children.map((k) => k.key);
childrenKeys.forEach((k) => {
if (unref(datamap)[k]) {
unref(datamap)[k].show = true;
}
});
}
}
}
/**
* 加载异步数据
* @param item
*/
async function loadExpandNode(item) {
const { expand, key, loaded, children } = item;
if (children?.length && !props.alwaysFirstLoad) {
return item;
}
if (expand && props.loadMode && !loaded) {
if (isFunction(props.loadApi)) {
expandedKeys.value.push(key);
loadLoading.value = true;
item.loading = true;
const currentNode = deepClone(item);
const apiRes = await props.loadApi(currentNode);
// 新增子项
let newChildren = [...(item.originItem?.children || []), ...(apiRes || [])];
const newChildrenObj = {};
newChildren = newChildren.reduce((total, next) => {
if (newChildrenObj[next[fieldMap.value]]) {
return total;
} else {
newChildrenObj[next[fieldMap.value]] = true;
total.push(next);
return total;
}
}, []);
item.originItem.children = newChildren || null;
if (apiRes?.length) {
const insertIndex = datalist.value.findIndex((k) => k.key === item.key);
handleTreeData(apiRes, item, item.level + 1, insertIndex);
datalist.value = checkInitData(datalist.value);
} else {
// 加载后无数据就移除展开图标
item.expand = false;
item.isLeaf = true;
item.showArrow = false;
}
loadLoading.value = false;
item.loading = false;
item.loaded = true;
}
} else {
const eki = expandedKeys.value.findIndex((k) => k === key);
if (eki >= 0) {
expandedKeys.value.splice(eki, 1);
}
}
return item;
}
/**
* 获取父类的选中状态
* @param item
*/
function getParentCheckedStatus(item) {
if (!item) {
return unCheckedStatus;
}
if (!props.checkedDisabled && item.disabled) {
return item.checkedStatus || unCheckedStatus;
}
// 单选时,父类永远为半选
if (!props.showCheckbox) {
return halfCheckedStatus;
}
const { children } = item;
// 子类全选中
const childrenCheckedAll = children.every((k) => k.checkedStatus === isCheckedStatus);
if (childrenCheckedAll) {
return isCheckedStatus;
}
// 子类全不选中
const childrenUncheckedAll = children.every((k) => k.checkedStatus === unCheckedStatus);
if (childrenUncheckedAll) {
return unCheckedStatus;
}
return halfCheckedStatus;
}
function filterData() {
if (props.filterValue === "") {
datalist.value.forEach((k) => {
k.show = true;
});
return;
}
datalist.value.forEach((k) => {
if (k.label.indexOf(props.filterValue) > -1) {
k.show = true;
k.parentKeys.forEach((k) => {
datamap.value[k].show = true;
});
} else {
k.show = false;
}
});
datalist.value.forEach((k) => {
if (k.show) {
k.parentKeys.forEach((k) => {
datamap.value[k].show = true;
});
}
});
}
/**
* 返回已选的 key
*/
const getCheckedKeys = () =>
getAllNodeKeys(datalist.value, "checkedStatus", isCheckedStatus, props.packDisabledkey);
/**
* 根据key设置已选
* @param keys 单选时为数字或者字符串,多选时为数组
* @param checked 多选时为key的数组单选时为key
*/
function setCheckedKeys(keys, checked = true) {
// 多选
if (props.showCheckbox) {
if (!isArray(keys)) {
logError(`setCheckedKeys 第一个参数非数组,传入的是[${keys}]`);
return;
}
const list = datalist.value;
// 取消选择
if (checked === false) {
let newCheckedKeys = [];
for (let i = 0; i < checkedKeys.value.length; i++) {
const ck = checkedKeys.value[i];
if (!keys.includes(ck)) {
newCheckedKeys.push(ck);
}
}
newCheckedKeys = [...new Set(newCheckedKeys)];
checkedKeys.value = newCheckedKeys;
handleCheckState(list, keys, false);
return;
}
// 选择
const newCheckedKeys = [...checkedKeys.value, ...keys];
checkedKeys.value = [...new Set(newCheckedKeys)];
handleCheckState(list, checkedKeys.value, true);
if (props.expandChecked && checked) {
expandedKeys.value = [...new Set([...(checkedKeys.value || []), ...(keys || [])])];
handleExpandState(list, keys, true);
}
return;
}
// 单选
// 如果为数组则拿第一个
if (isArray(keys)) {
keys = keys[0];
}
if (!isString(keys) && !isNumber(keys)) {
logError("setCheckedKeys 第一个参数字符串或数字,传入的是==>", keys);
return;
}
const list = datalist.value;
checkedKeys.value = checked ? keys : null;
if (props.expandChecked && checked) {
handleExpandState(list, [keys], true);
}
handleCheckState(list, keys, !!checked);
}
/**
* 返回半选的 key
*/
const getHalfCheckedKeys = () =>
getAllNodeKeys(datalist.value, "checkedStatus", halfCheckedStatus, props.packDisabledkey);
/**
* 返回未选的 key
*/
const getUncheckedKeys = () =>
getAllNodeKeys(datalist.value, "checkedStatus", unCheckedStatus, props.packDisabledkey);
/**
* 返回已展开的 key
*/
const getExpandedKeys = () => getAllNodeKeys(datalist.value, "expand", true);
/**
* 返回未展开的 key
*/
const getUnexpandedKeys = () => getAllNodeKeys(datalist.value, "expand", false);
/**
* 根据key展开/收起
*
* @param keys 数组,或字符串 all
* @param expand true为展开/false为收起
*/
function setExpandedKeys(keys, expand = true) {
if (!Array.isArray(keys) && keys !== "all") {
logError("setExpandedKeys 第一个参数非数组,传入的是===>", keys);
return;
}
const list = datalist.value;
// 展开/收起全部
if (keys === "all") {
list.forEach((k) => {
k.expand = expand;
if (k.level > 0) {
k.show = expand;
}
});
return;
}
// 收起
if (expand === false) {
const newExpandedKeys = [];
for (let i = 0; i < expandedKeys.value.length; i++) {
const ek = expandedKeys.value[i];
if (!keys.includes(ek)) {
newExpandedKeys.push(ek);
}
}
expandedKeys.value = [...new Set(newExpandedKeys)];
handleExpandState(list, keys, false);
return;
}
// 展开
const newExpandedKeys = [];
for (let i = 0; i < list.length; i++) {
if (keys.includes(list[i].key)) {
newExpandedKeys.push(list[i].key);
}
}
expandedKeys.value = [...new Set(newExpandedKeys)];
handleExpandState(list, newExpandedKeys, true);
}
/**
* 返回已选的节点
*/
const getCheckedNodes = () =>
getAllNodes(datalist.value, "checkedStatus", isCheckedStatus, props.packDisabledkey);
/**
* 返回半选的节点
*/
const getHalfCheckedNodes = () =>
getAllNodes(datalist.value, "checkedStatus", halfCheckedStatus, props.packDisabledkey);
/**
* 返回未选的节点
*/
const getUncheckedNodes = () =>
getAllNodes(datalist.value, "checkedStatus", unCheckedStatus, props.packDisabledkey);
/**
* 返回已展开的节点
*/
const getExpandedNodes = () => getAllNodes(datalist.value, "expand", true);
/**
* 返回未展开的节点
*/
const getUnexpandedNodes = () => getAllNodes(datalist.value, "expand", false);
watch(
() => props.defaultExpandedKeys,
(v) => {
if (v?.length) {
expandedKeys.value = v;
} else {
expandedKeys.value = [];
}
// if (v) checkInitData(datalist.value)
},
{ immediate: true }
);
watch(
() => props.defaultCheckedKeys,
(v) => {
if (props.showCheckbox) {
if (v?.length) {
checkedKeys.value = v;
} else {
checkedKeys.value = [];
}
} else {
if (v || v === 0) {
checkedKeys.value = v;
} else {
checkedKeys.value = null;
}
}
// checkInitData(datalist.value)
},
{ immediate: true }
);
watch(
() => props.data,
(v) => {
dataRef.value = deepClone(v);
setTimeout(() => {
initData();
}, 36);
},
{ immediate: true, deep: true }
);
watch(
() => props.filterValue,
() => {
filterData();
}
);
return {
datalist,
unCheckedStatus,
halfCheckedStatus,
isCheckedStatus,
handleCheckChange,
handleRadioChange,
handleLabelClick,
handleExpandedChange,
loadLoading,
// updateChildrenByKey: () => {},
// insertBeforeByKey: () => {},
// insertAfterByKey: () => {},
getCheckedKeys,
setCheckedKeys,
getHalfCheckedKeys,
getUncheckedKeys,
getExpandedKeys,
getUnexpandedKeys,
setExpandedKeys,
getCheckedNodes,
getHalfCheckedNodes,
getUncheckedNodes,
getExpandedNodes,
getUnexpandedNodes,
};
},
});
</script>
<style lang="scss" scoped>
@font-face {
font-family: "da-tree-iconfont"; /* Project id */
src: url("data:application/octet-stream;base64,AAEAAAALAIAAAwAwR1NVQiCLJXoAAAE4AAAAVE9TLzI8GU+XAAABjAAAAGBjbWFwahLuHAAAAhQAAAIQZ2x5ZtAAFwYAAAQ8AAAEWGhlYWQkfWz8AAAA4AAAADZoaGVhB94DiwAAALwAAAAkaG10eCgAAAAAAAHsAAAAKGxvY2EE3AQOAAAEJAAAABZtYXhwAR0AoAAAARgAAAAgbmFtZRCjPLAAAAiUAAACZ3Bvc3TfNfUGAAAK/AAAALsAAQAAA4D/gABcBAAAAAAABAAAAQAAAAAAAAAAAAAAAAAAAAoAAQAAAAEAAJx55T9fDzz1AAsEAAAAAADgrxSAAAAAAOCvFIAAAP/VBAADKgAAAAgAAgAAAAAAAAABAAAACgCUAAkAAAAAAAIAAAAKAAoAAAD/AAAAAAAAAAEAAAAKADAAPgACREZMVAAObGF0bgAaAAQAAAAAAAAAAQAAAAQAAAAAAAAAAQAAAAFsaWdhAAgAAAABAAAAAQAEAAQAAAABAAgAAQAGAAAAAQAAAAQEAAGQAAUAAAKJAswAAACPAokCzAAAAesAMgEIAAACAAUDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFBmRWQAwOYE7McDgP+AAAAD3ACAAAAAAQAAAAAAAAAAAAAAAAACBAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAAAAAUAAAADAAAALAAAAAQAAAGUAAEAAAAAAI4AAwABAAAALAADAAoAAAGUAAQAYgAAABAAEAADAADmBOfx6k/q1evO7MXsx///AADmBOfx6k/q1OvO7MTsx///AAAAAAAAAAAAAAAAAAAAAQAQABAAEAAQABIAEgAUAAAAAQAIAAIAAwAEAAUABgAHAAkAAAEGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAAHwAAAAAAAAACQAA5gQAAOYEAAAAAQAA5/EAAOfxAAAACAAA6k8AAOpPAAAAAgAA6tQAAOrUAAAAAwAA6tUAAOrVAAAABAAA684AAOvOAAAABQAA7MQAAOzEAAAABgAA7MUAAOzFAAAABwAA7McAAOzHAAAACQAAAAAALgBgAIoArgDSAQIBJgH+AiwAAAABAAAAAANZAkoAGQAAATIeAQYHDgEHDgImJyYvAiYnLgE+ATM3AxsXHQkJEEB3Nw8pKigNHyFFQiAdDQgJGxa2AkoSHCQRR4g8EBEBDhAiI0dGIyAPIRsRAQAAAAMAAP/VA6sDKgAIABEAGgAAARQGIiY0NjIWAzI2ECYgBhAWEzIWEAYgJhA2AoBMaExMaEyAjMrK/ujKyoyw+vr+oPr6AYA0TExoTEz+dsoBGMrK/ujKAwD6/qD6+gFg+gAAAAACAAAAAAOAAwAABQAVAAAlAScBJwcBMhYVERQGIyEiJjURNDYzAaoBgDz+vJg8AlQkMjIk/awkMjIkqgGAPv68mDwBgDQi/awiNDQiAlQiNAAAAAACAAAAAAOAAwAADwATAAABMhYVERQGIyEiJjURNDYzBSERIQMqIjQ0Iv2sIjQ0IgJU/awCVAMANCL9rCI0NCICVCI0Vv2sAAACAAAAAAOAAwAAAwATAAABNSEVATIWFREUBiMhIiY1ETQ2MwLW/lQCACI0NCL9rCI0NCIBVlRUAao0Iv2sIjQ0IgJUIjQAAAADAAD/1QOrAyoACAARABoAACUyNhAmIAYQFhMyFhAGICYQNhcyFhQGIiY0NgIAjMrK/ujKyoyw+vr+oPr6sFh+frB+firKARjKyv7oygMA+v6g+voBYPrUfrB+frB+AAACAAD/1QOrAyoACAARAAAlMjYQJiAGEBYTMhYQBiAmEDYCAIzKyv7oysqMsPr6/qD6+irKARjKyv7oygMA+v6g+voBYPoAAAAJAAAAAANpAwEAHAA0AEgAWQBqAHUAfgCSAJMAAAEUFhcWFxYyNzY3Njc2NTQmJyYnJiIHBgcGBwYVBxQeARcWMzI+ATc2NTQuAScmIyIOAQcGExQWFx4BMj4CNCYnLgEiDgEHBhcUHgIyPgI0LgIiDgI3FBcWMzI3NjU0JyYjIgcGBzcGFjI2NCYiBw4BJxQWMjY0JiIGJxQWFxYzMjY3NjU0JicmIyIGBwYVASYUDxMUFTEVGQ4TBggUDxMUFTEVGQ4TBgimDh8SFBEUIx8HBw4fERUREyQfBghZDgsPHiceHQsNDA4fJx4dBAfyCxUdHx0VCwsVHR8dFAzMEhMcGhUTExMcGRYSAV8BIy8jIy8RCAkHGSMZGSMZVAUECQ0GDAQJBQQKDAYNAwkCixksDxMGCQkMDRMTFxYZLA8TBgkJDA0TExsT5BQkHgcIDx4SFRETJB4HCA8eEg7+6xQfDA4LDBsdJyALDwsNGw4WZxAdFQsLFR0fHRUMDBUdTBoVExMSHRkWExMWGakXIyIvIxEIFpMRGRkjGBhfBgwECQUECgwGDQMJBQQHDwAAAAABAAAAAALGAtkAGQAAATQ+ARYXHgEXHgIGBwYPAgYHDgEuATUnATYSHCQRR4g8EBEBDhAiI0dGIyAPIRsRAQKbFx0JCRBAdzcPKSooDR8hREMgHQ0ICRsWtgAAAAAAEgDeAAEAAAAAAAAAEwAAAAEAAAAAAAEACAATAAEAAAAAAAIABwAbAAEAAAAAAAMACAAiAAEAAAAAAAQACAAqAAEAAAAAAAUACwAyAAEAAAAAAAYACAA9AAEAAAAAAAoAKwBFAAEAAAAAAAsAEwBwAAMAAQQJAAAAJgCDAAMAAQQJAAEAEACpAAMAAQQJAAIADgC5AAMAAQQJAAMAEADHAAMAAQQJAAQAEADXAAMAAQQJAAUAFgDnAAMAAQQJAAYAEAD9AAMAAQQJAAoAVgENAAMAAQQJAAsAJgFjQ3JlYXRlZCBieSBpY29uZm9udGljb25mb250UmVndWxhcmljb25mb250aWNvbmZvbnRWZXJzaW9uIDEuMGljb25mb250R2VuZXJhdGVkIGJ5IHN2ZzJ0dGYgZnJvbSBGb250ZWxsbyBwcm9qZWN0Lmh0dHA6Ly9mb250ZWxsby5jb20AQwByAGUAYQB0AGUAZAAgAGIAeQAgAGkAYwBvAG4AZgBvAG4AdABpAGMAbwBuAGYAbwBuAHQAUgBlAGcAdQBsAGEAcgBpAGMAbwBuAGYAbwBuAHQAaQBjAG8AbgBmAG8AbgB0AFYAZQByAHMAaQBvAG4AIAAxAC4AMABpAGMAbwBuAGYAbwBuAHQARwBlAG4AZQByAGEAdABlAGQAIABiAHkAIABzAHYAZwAyAHQAdABmACAAZgByAG8AbQAgAEYAbwBuAHQAZQBsAGwAbwAgAHAAcgBvAGoAZQBjAHQALgBoAHQAdABwADoALwAvAGYAbwBuAHQAZQBsAGwAbwAuAGMAbwBtAAACAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoBAgEDAQQBBQEGAQcBCAEJAQoBCwAIeGlhbmd4aWEGYWRqdXN0CGNoZWNrYm94FGNoZWNrYm94b3V0bGluZWJsYW5rFWluZGV0ZXJtaW5hdGVjaGVja2JveBJyYWRpb2J1dHRvbmNoZWNrZWQUcmFkaW9idXR0b251bmNoZWNrZWQHbG9hZGluZw14aWFuZ3hpYS1jb3B5AAAA")
format("truetype");
}
.da-tree {
width: 100%;
height: 100%;
&-scroll {
width: 100%;
height: 100%;
}
&-item {
display: flex;
align-items: center;
height: 0;
padding: 0;
overflow: hidden;
font-size: 36rpx;
line-height: 1;
visibility: hidden;
opacity: 0;
transition: opacity 0.2s linear;
&.is-show {
height: auto;
padding: 12rpx 24rpx;
visibility: visible;
opacity: 1;
}
&__icon {
display: flex;
align-items: center;
justify-content: center;
width: 50rpx;
height: 50rpx;
overflow: hidden;
&--arr {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 40rpx;
height: 40rpx;
&::after {
position: relative;
z-index: 1;
overflow: hidden;
/* stylelint-disable-next-line font-family-no-missing-generic-family-keyword */
font-family: "da-tree-iconfont" !important;
font-size: 40rpx;
font-style: normal;
color: #999;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
&.is-expand {
&::after {
content: "\e604";
}
}
&.is-right {
transform: rotate(-90deg);
}
&.is-loading {
animation: IconLoading 1s linear 0s infinite;
&::after {
content: "\e7f1";
}
}
}
}
&__checkbox {
width: 50rpx;
height: 50rpx;
overflow: hidden;
&--left {
order: 0;
}
&--right {
order: 1;
}
&--icon {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 50rpx;
height: 50rpx;
&::after {
position: relative;
top: 0;
left: 0;
z-index: 1;
overflow: hidden;
/* stylelint-disable-next-line font-family-no-missing-generic-family-keyword */
font-family: "da-tree-iconfont" !important;
font-size: 40rpx;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
&.da-tree-checkbox-outline::after {
color: #bbb;
content: "\ead5";
}
&.da-tree-checkbox-checked::after {
color: var(--theme-color, #007aff);
content: "\ead4";
}
&.da-tree-checkbox-indeterminate::after {
color: var(--theme-color, #007aff);
content: "\ebce";
}
&.da-tree-radio-outline::after {
color: #bbb;
content: "\ecc5";
}
&.da-tree-radio-checked::after {
color: var(--theme-color, #007aff);
content: "\ecc4";
}
&.da-tree-radio-indeterminate::after {
color: var(--theme-color, #007aff);
content: "\ea4f";
}
}
&.is--disabled {
cursor: not-allowed;
opacity: 0.35;
}
}
&__label {
flex: 1;
margin-left: 4rpx;
color: #555;
&--2 {
color: var(--theme-color, #007aff);
}
&--append {
font-size: 60%;
opacity: 0.6;
}
}
}
}
@keyframes IconLoading {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>