uniapp目录树
- 父组件调用目录树组件
<DaTreeVue2:data="treeData":field="{label: 'name',key: 'id',}"@change="handleTreeChange":defaultCheckedKeys="addressDefaultCheckedKey":defaultExpandedKeys="addressDefaultCheckedKey":loadApi="getTreeData"ref="addressRef"loadMode
/>
- 父组件方法
handleTreeChange(allSelectedKeys, currentItem, parentKeys) {this.addressDefaultCheckedKey = parentKeys;
}// 获取树async getTreeData(code) {let result = {};await this.$u.api.jobPost.getseekTreeData({parentCode: code,}).then((res) => {result = res.map((it) => {if (it.isParent) {it.children = [];return it;} else {return it;}});});return result;}
- 子组件
<template><view class="da-tree" :style="{'--theme-color': themeColor}"><scroll-view class="da-tree-scroll" :scroll-y="true" :scroll-x="false"><view class="da-tree-item" :class="{'is-show': item.show}":style="{paddingLeft: item.level * indent + 'rpx'}" v-for="item in datalist" :key="item.key"><view v-if="item.showArrow" class="da-tree-item__icon" @click="handleExpandedChange(item)"><view :class="['da-tree-item__icon--arr','is-loading']" v-if="loadLoading && item.loading" /><view :class="['da-tree-item__icon--arr','is-expand', {'is-right':!item.expand}]" v-else /></view><view v-else class="da-tree-item__icon" /><view class="da-tree-item__checkbox":class="[`da-tree-item__checkbox--${checkboxPlacement}`,{'is--disabled': item.disabled}]"v-if="showCheckbox" @click="handleCheckChange(item)"><view class="da-tree-item__checkbox--icon da-tree-checkbox-checked"v-if="item.checkedStatus === isCheckedStatus" /><view class="da-tree-item__checkbox--icon da-tree-checkbox-indeterminate"v-else-if="item.checkedStatus === halfCheckedStatus" /><view class="da-tree-item__checkbox--icon da-tree-checkbox-outline" v-else /></view><view class="da-tree-item__checkbox":class="[`da-tree-item__checkbox--${checkboxPlacement}`,{'is--disabled': item.disabled}]"v-if="!showCheckbox && showRadioIcon" @click="handleRadioChange(item)"><view class="da-tree-item__checkbox--icon da-tree-radio-checked"v-if="item.checkedStatus === isCheckedStatus" /><view class="da-tree-item__checkbox--icon da-tree-radio-indeterminate"v-else-if="item.checkedStatus === halfCheckedStatus" /><view class="da-tree-item__checkbox--icon da-tree-radio-outline" v-else /></view><view class="da-tree-item__label" :class="'da-tree-item__label--'+item.checkedStatus"@click="handleLabelClick(item)">{{ item.label }} <text class="da-tree-item__label--append"v-if="item.append">{{ item.append }}</text></view></view></scroll-view></view>
</template><script>import {unCheckedStatus,halfCheckedStatus,isCheckedStatus,deepClone,getAllNodeKeys,getAllNodes} from './utils'export default {name: 'DaTree',props: {/*** 树的数据*/data: {type: Array,default: () => [],},/*** 主题色*/themeColor: {type: String,default: '#007aff',},/*** 默认选中的节点,注意单选时为单个key,多选时为key的数组*/defaultCheckedKeys: {type: [Array, String, Number],default: null,},/*** 选择框的位置,可选 left/right*/checkboxPlacement: {type: String,default: 'left',},/*** 是否默认展开全部*/defaultExpandAll: {type: Boolean,default: false,},/*** 默认展开的节点*/defaultExpandedKeys: {type: Array,default: null,},/*** 子项缩进距离,默认40,单位rpx*/indent: {type: Number,default: 40,},/*** 字段对应内容,默认为 {label: 'label',key: 'key', children: 'children', disabled: 'disabled', append: 'append'}*/field: {type: Object,default: null,},/*** 是否开启多选,默认单选*/showCheckbox: {type: Boolean,default: false,},/*** 是否显示单选图标,默认显示*/showRadioIcon: {type: Boolean,default: true,},/*** 单选时只允许选中末级,默认可随意选中*/onlyRadioLeaf: {type: Boolean,default: false,},/*** 多选时,是否执行父子不关联的任意勾选,默认父子关联*/checkStrictly: {type: Boolean,default: false,},/*** 为 true 时,空的 children 数组会显示展开图标*/loadMode: {type: Boolean,default: false,},/*** 异步加载接口*/loadApi: {type: Function,default: null,},/*** 是否渲染禁用值*/checkedDisabled: {type: Boolean,default: false,},/*** 是否返回已禁用的但已选中的key*/packDisabledkey: {type: Boolean,default: true,},/*** 选择时是否展开当前已选的所有下级节点,默认不展开*/expandChecked: {type: Boolean,default: false,},},data() {return {unCheckedStatus,halfCheckedStatus,isCheckedStatus,/** 原始的树数据 */dataRef: [],/** 处理后的一维树项数据 */datalist: [],/** 处理后的以key为键值的树项数据 */datamap: {},/** 默认的展开数据 */expandedKeys: [],/** 默认的已选数据 */checkedKeys: null,/** 加载状态 */loadLoading: false,}},watch: {defaultExpandedKeys: {// deep: true,immediate: true,handler: function(v) {if (v?.length) {this.expandedKeys = v} else {this.expandedKeys = []}// if (v) this.checkInitData(this.datalist)},},defaultCheckedKeys: {// deep: true,immediate: true,handler: function(v) {if (this.showCheckbox) {if (v?.length) {this.checkedKeys = v} else {this.checkedKeys = []}} else {if (v || v === 0) {this.checkedKeys = v} else {this.checkedKeys = null}}// this.checkInitData(this.datalist)},},data: {deep: true,immediate: true,handler: function(v) {this.dataRef = deepClone(v)setTimeout(() => {this.initData()}, 36)},},},methods: {/*** 初始化数据结构*/initData() {const data = deepClone(this.dataRef)this.datalist = []this.datamap = {}// clean treethis.handleTreeData(data)// flat treethis.datalist = this.checkInitData(this.datalist)// console.log('init datalist', this.datalist)// console.log('init datamap', this.datamap)},/*** 转换为节点数据* @param data* @param parent* @param level*/handleTreeData(data = [], parent = null, level = 0, insertIndex = -1, secondIndex) {return data.reduce((prev, cur, index) => {const key = cur[this.field?.key || 'key']const children = cur[this.field?.children || 'children'] || nullconst newItem = this.createNewItem(cur, index, parent, level)this.datamap[key] = newItemif (insertIndex > -1) {this.datalist.splice(insertIndex + 1, 0, newItem)parent.children.push(newItem)if (newItem.parentKeys?.length) {newItem.parentKeys.forEach(k => {this.datamap[k].childrenKeys = [...this.datamap[k].childrenKeys,newItem.key]})}} else {this.datalist.push(newItem)}const hasChildren = children && children.length > 0if (hasChildren) {const childrenData = this.handleTreeData(children, newItem, level + 1)newItem.children = childrenDataconst childrenKeys = childrenData.reduce((p, k) => {const keys = k.childrenKeysp.push(...keys, k.key)return p}, [])newItem.childrenKeys = childrenKeys}newItem.positionCode = cur.positionCode// newItem.parentCodes = cur.parentCodes.split(',')prev.push(newItem)return prev}, [])},/*** 创建节点* @param item* @param index* @param parent* @param level*/createNewItem(item, index, parent, level) {const key = item[this.field?.key || 'key']const label = item[this.field?.label || 'label']const children = item[this.field?.children || 'children'] || nullconst append = item[this.field?.append || 'append'] || nulllet disabled = item[this.field?.disabled || 'disabled'] || falseconst hasChildren = children && children.length > 0const hasEmptyChildren = children && children.length === 0let showArrow = truelet isLeaf = !hasChildrenlet expand = this.defaultExpandAllif (this.loadMode && hasEmptyChildren) {isLeaf = falseexpand = falseshowArrow = true}if (disabled) {showArrow = false}if (hasChildren) {showArrow = true} else {if (this.loadMode && hasEmptyChildren && !disabled) {showArrow = true} else {showArrow = false}}if (!isLeaf && !this.showCheckbox && this.onlyRadioLeaf) {disabled = trueshowArrow = true}const parentKey = parent ? parent.key : nullconst show = this.defaultExpandAll ? true : level === 0const newItem = {key,parentKey,label,append,isLeaf,showArrow,level,expand,show,disabled,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*/checkInitData(list) {let checkedKeyList = nulllet expandedKeyList = []if (this.showCheckbox) {checkedKeyList = [...new Set(this.checkedKeys || [])]} else {checkedKeyList = this.checkedKeys || null}this.handleCheckState(list, checkedKeyList)// 处理初始展开expandedKeyList = [...new Set(this.expandedKeys || [])]if (!this.defaultExpandAll) {this.handleExpandState(list, expandedKeyList, true)}return list},/*** 处理选中* @param list* @param checkedKeyList*/handleCheckState(list, checkedKeyList, checked = true) {if (this.showCheckbox) {for (let i = 0; i < list.length; i++) {const item = list[i]if (checkedKeyList?.includes(item.key)) {if (this.checkedDisabled || !item.disabled) {this.handleExpandParentNode(item, checked)this.checkTheChecked(item, checked)}}}} else {// 单选for (let i = 0; i < list.length; i++) {const item = list[i]if (item.key === checkedKeyList && !item.disabled) {if (this.checkedDisabled || !item.disabled) {this.checkTheRadio(item, checked)break}}}}},/*** 校验多选节点* @param item* @param checked*/checkTheChecked(item, checked = true) {const {childrenKeys,parentKeys,disabled = false} = itemif (!this.checkedDisabled && disabled) return// 当前item.checkedStatus = checked ? isCheckedStatus : unCheckedStatusif (!this.checkStrictly) {// 子类childrenKeys.forEach(k => {const childrenItem = this.datamap[k]childrenItem.checkedStatus = (!this.checkedDisabled && childrenItem.disabled) ?childrenItem.checkedStatus : item.checkedStatus})// 父类parentKeys.forEach(k => {const parentItem = this.datamap[k]parentItem.checkedStatus = this.getParentCheckedStatus(parentItem)})}},/*** 校验单选节点* @param item*/checkTheRadio(item, checked) {// console.log('item',item);// console.log('checked',checked);const {parentKeys,isLeaf,disabled = false} = itemif (!this.checkedDisabled && disabled) return// 限制末节点选中,但当前非末节点if (this.onlyRadioLeaf && !isLeaf) {console.error(`DaTree: 限制了末节点选中,当前[${item.label}]非末节点`)return}if (this.datalist?.length) {for (let i = 0; i < this.datalist.length; i++) {const k = this.datalist[i]k.checkedStatus = unCheckedStatus}}parentKeys.forEach(k => {const parentItem = this.datamap[k]parentItem.checkedStatus = this.getParentCheckedStatus(parentItem, checked)})// 当前if (checked === true) {item.checkedStatus = isCheckedStatus}if (checked === false) {item.checkedStatus = unCheckedStatus}// item.checkedStatus = unCheckedStatus },/*** 处理父节点展开* @param item* @param expand*/handleExpandParentNode(item, expand = true) {if (!expand) returnif (item?.parentKeys?.length) {item.parentKeys.forEach(pk => {if (!this.datamap[pk].expand) {this.datamap[pk].expand = true}})}},/*** 处理节点展开* @param list* @param expandedKeyList* @param expand*/handleExpandState(list, expandedKeyList, expand = true) {for (let i = 0; i < list.length; i++) {const item = list[i]if (expand === true) {// 处理展开if (expandedKeyList?.includes(item.key)) {item.expand = truethis.handleExpandParentNode(item, true)}} else {// 处理收起if (expandedKeyList?.includes(item.key)) {item.expand = falseif (item?.childrenKeys?.length) {item.childrenKeys.forEach(ck => {this.datamap[ck].expand = falsethis.datamap[ck].show = false})}}}}for (let i = 0; i < list.length; i++) {const item = list[i]if (item.level > 0) {const parentItem = this.datamap[item.parentKey]if (parentItem) {if (parentItem.expand && parentItem.show) {item.show = true}}}}},/*** 点击选框* @param item*/handleCheckChange(item) {const {childrenKeys,parentKeys,checkedStatus,isLeaf,originItem = null,disabled = false} = itemif (!this.showCheckbox) returnif (disabled) return// 当前item.checkedStatus = checkedStatus === isCheckedStatus ? unCheckedStatus : isCheckedStatus// 子类if (!this.checkStrictly) {if (this.expandChecked) {item.show = trueitem.expand = childrenKeys?.length > 0 || isLeaf}childrenKeys.forEach(k => {const childrenItem = this.datamap[k]childrenItem.checkedStatus = childrenItem.disabled ? childrenItem.checkedStatus : item.checkedStatusif (this.expandChecked) {childrenItem.show = truechildrenItem.expand = childrenItem?.childrenKeys?.length > 0 || childrenItem.isLeaf}})} else {if (this.expandChecked) {console.error(`DaTree: 多选时,当 checkStrictly 为 true 时,不支持选择自动展开子节点属性(expandChecked)`)}}// 父类if (!this.checkStrictly) {parentKeys.forEach(k => {const parentItem = this.datamap[k]parentItem.checkedStatus = this.getParentCheckedStatus(parentItem)})}const hasCheckedKeys = []for (let i = 0; i < this.datalist.length; i++) {const k = this.datalist[i]if (k.checkedStatus === isCheckedStatus) {if ((this.packDisabledkey && k.disabled) || !k.disabled) {hasCheckedKeys.push(k.key)}}}this.checkedKeys = [...hasCheckedKeys]this.$emit('change', hasCheckedKeys, originItem)},/*** 点击单选* @param item*/handleRadioChange(item) {const {parentKeys,checkedStatus,key,originItem = null,disabled = false} = itemif (this.showCheckbox) returnif (this.onlyRadioLeaf) {this.handleExpandedChange(item)}if (disabled) return// 重置所有选择if (this.datalist?.length) {for (let i = 0; i < this.datalist.length; i++) {const k = this.datalist[i]k.checkedStatus = unCheckedStatus}}parentKeys.forEach(k => {const parentItem = this.datamap[k]parentItem.checkedStatus = this.getParentCheckedStatus(parentItem)})// 当前item.checkedStatus = checkedStatus === isCheckedStatus ? unCheckedStatus : isCheckedStatusthis.checkedKeys = keythis.$emit('change', key, originItem, parentKeys)},/*** 点击标签*/handleLabelClick(item) {if (this.showCheckbox) {this.handleCheckChange(item)} else {this.handleRadioChange(item)}},/*** 点击展开收起* @param item*/async handleExpandedChange(item) {const {expand,originItem = null,loading = false} = itemif (this.loadLoading && loading) returnthis.checkExpandedChange(item)// 异步item.expand = !expandlet currentItem = nullif (!this.showCheckbox && this.onlyRadioLeaf && this.loadMode) {console.error(`DaTree: 单选时,当 onlyRadioLeaf 为 true 时不支持动态数据`)} else {currentItem = await this.loadExpandNode(item)}this.$emit('expand', item, !expand, currentItem || originItem || null)},/*** 检查展开状态* @param item*/checkExpandedChange(item) {const {expand,childrenKeys,children = null} = itemif (expand) {if (childrenKeys?.length) {childrenKeys.forEach(k => {if (this.datamap[k]) {this.datamap[k].show = falsethis.datamap[k].expand = false}})}} else {if (children?.length) {const childrenKeys = children.map(k => k.key)childrenKeys.forEach(k => {if (this.datamap[k]) {this.datamap[k].show = true}})}}},/*** 加载异步数据* @param item*/async loadExpandNode(item) {const {expand,key,children = null} = itemif (expand && this.loadMode && (!children || children.length === 0)) {if (typeof this.loadApi === 'function') {this.expandedKeys.push(key)this.loadLoading = trueitem.loading = trueconst currentNode = deepClone(item)const apiRes = await this.loadApi(currentNode.positionCode)item.originItem = apiRes || nullif (apiRes?.length) {const insertIndex = this.datalist.findIndex(k => k.key === item.key)this.handleTreeData(apiRes, item, item.level + 1, insertIndex)this.datalist = this.checkInitData(this.datalist)} else {// 加载后无数据就移除展开图标item.expand = falseitem.isLeaf = trueitem.showArrow = false}this.loadLoading = falseitem.loading = false}} else {const eki = this.expandedKeys.findIndex(k => k === key)if (eki >= 0) {this.expandedKeys.splice(eki, 1)}}return item},/*** 获取父类的选中状态* @param item*/getParentCheckedStatus(item, checked = true) {console.log(item);console.log(checked);if (!item) {return unCheckedStatus}if (!this.checkedDisabled && item.disabled) {return item.checkedStatus || unCheckedStatus}// 单选时,父类永远为半选// checked为false unCheckedStatus取消选择if (!this.showCheckbox && checked == true) {// console.log('半半');return halfCheckedStatus}if (!this.showCheckbox && checked === false) {// console.log('add');return unCheckedStatus}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},/*** 返回已选的 key*/getCheckedKeys() {return getAllNodeKeys(this.datalist, 'checkedStatus', isCheckedStatus, this.packDisabledkey)},/*** 根据key设置已选* @param keys 多选时为key的数组,单选时为key* @param checked 多选时为key的数组,单选时为key*/setCheckedKeys(keys, checked = true) {// console.log('--==========================',keys);// console.log('--==========================',checked);if (!Array.isArray(keys) && this.showCheckbox) {console.error('DaTree: setCheckedKeys 第一个参数非数组,传入的是:', keys)return}const list = this.datalistif (checked === false) {// console.log('11111111111111111111111111111111111111111111111111111111111111111111111');let newCheckedKeysif (this.showCheckbox) {newCheckedKeys = []for (let i = 0; i < this.checkedKeys.length; i++) {const ck = this.checkedKeys[i]if (!keys.includes(ck)) {newCheckedKeys.push(ck)}}newCheckedKeys = [...new Set(newCheckedKeys)]} else {// 单选时,必须至少勾选一个,所以单选不支持取消选中。// newCheckedKeys = nullnewCheckedKeys = keys}this.checkedKeys = newCheckedKeys// console.log(this.checkedKeys);console.log(list);this.handleCheckState(list, keys, false)} else {this.handleCheckState(list, keys, true)if (this.showCheckbox) {this.checkedKeys = [...new Set([...(this.checkedKeys || []), ...(keys || [])])]this.handleExpandState(list, keys, true)} else {// 单选时如果为数组则拿第一个if (Array.isArray(keys)) {keys = keys[0]}this.checkedKeys = keys || nullthis.handleExpandState(list, [keys], true)}}},/*** 返回半选的 key*/getHalfCheckedKeys() {return getAllNodeKeys(this.datalist, 'checkedStatus', halfCheckedStatus, this.packDisabledkey)},/*** 返回已展开的 key*/getExpandedKeys() {return getAllNodeKeys(this.datalist, 'expand', true)},/*** 根据key展开/收起* @param keys key的数组* @param expand true为展开/false为收起*/setExpandedKeys(keys, expand = true) {if (!Array.isArray(keys)) {console.error('DaTree: setExpandedKeys 第一个参数非数组,传入的是:', keys)return}const list = this.datalistif (expand === false) {const newExpandedKeys = []for (let i = 0; i < this.expandedKeys.length; i++) {const ek = this.expandedKeys[i]if (!keys.includes(ek)) {newExpandedKeys.push(ek)}}this.expandedKeys = [...new Set(newExpandedKeys)]this.handleExpandState(list, keys, false)} else {this.datalist.forEach(k => {if (keys.includes(k.key)) {if (k.parentKeys?.length) {k.parentKeys.forEach(pk => {const parentItem = this.datamap[pk]parentItem.expand = trueparentItem.show = trueif (parentItem.children?.length) {const pkcs = parentItem.children.map(k => k.key)pkcs.forEach(pkc => {this.datamap[pkc].show = true})}})}k.show = truethis.handleExpandedChange(k)}})}},/*** 返回已选的节点*/getCheckedNodes() {return getAllNodes(this.datalist, 'checkedStatus', isCheckedStatus, this.packDisabledkey)},/*** 返回半选的节点*/getHalfCheckedNodes() {return getAllNodes(this.datalist, 'checkedStatus', halfCheckedStatus, this.packDisabledkey)},/*** 返回已展开的节点*/getExpandedNodes() {return getAllNodes(this.datalist, 'expand', true)},},}
</script><style lang="scss" scoped>@font-face {font-family: 'iconfont';/* Project id */src: url('data:application/octet-stream;base64,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') 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: 28rpx;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: 40rpx;height: 40rpx;overflow: hidden;&--arr {position: relative;display: flex;align-items: center;justify-content: center;width: 32rpx;height: 32rpx;&::after {position: relative;z-index: 1;overflow: hidden;/* stylelint-disable-next-line font-family-no-missing-generic-family-keyword */font-family: 'iconfont' !important;font-size: 32rpx;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: 40rpx;height: 40rpx;overflow: hidden;&--left {order: 0;}&--right {order: 1;}&--icon {position: relative;display: flex;align-items: center;justify-content: center;width: 40rpx;height: 40rpx;&::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: 'iconfont' !important;font-size: 32rpx;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>
- utils.js文件
// @ts-nocheck
/** 未选 */
export const unCheckedStatus = 0
/** 半选 */
export const halfCheckedStatus = 1
/** 选中 */
export const isCheckedStatus = 2/*** 深拷贝内容* @param originData 拷贝对象* @author crlang(https://crlang.com)*/
export function deepClone(originData) {const type = Object.prototype.toString.call(originData)let dataif (type === '[object Array]') {data = []for (let i = 0; i < originData.length; i++) {data.push(deepClone(originData[i]))}} else if (type === '[object Object]') {data = {}for (const prop in originData) {// eslint-disable-next-line no-prototype-builtinsif (originData.hasOwnProperty(prop)) { // 非继承属性data[prop] = deepClone(originData[prop])}}} else {data = originData}return data
}/*** 获取所有指定的节点* @param type* @param value* @author crlang(https://crlang.com)*/
export function getAllNodes(list, type, value, packDisabledkey = true) {if (!list || list.length === 0) {return []}const res = []for (let i = 0; i < list.length; i++) {const item = list[i]if (item[type] === value) {if ((packDisabledkey && item.disabled) || !item.disabled) {res.push(item)}}}return res
}/*** 获取所有指定的key值* @param type* @param value* @author crlang(https://crlang.com)*/
export function getAllNodeKeys(list, type, value, packDisabledkey = true) {if (!list || list.length === 0) {return []}const res = []for (let i = 0; i < list.length; i++) {const item = list[i]if (item[type] === value) {if ((packDisabledkey && item.disabled) || !item.disabled) {res.push(item.key)}}}return res
}