smartswrtch-app/components/da-tree-vue2/index.vue
2025-03-04 16:13:46 +08:00

1109 lines
33 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
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>
<view :class="['da-tree-item__icon--arr','is-expand', {'is-right':!item.expand}]" v-else></view>
</view>
<view v-else class="da-tree-item__icon"></view>
<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>
<view class="da-tree-item__checkbox--icon da-tree-checkbox-indeterminate" v-else-if="item.checkedStatus === halfCheckedStatus"></view>
<view class="da-tree-item__checkbox--icon da-tree-checkbox-outline" v-else></view>
</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>
<view class="da-tree-item__checkbox--icon da-tree-radio-indeterminate" v-else-if="item.checkedStatus === halfCheckedStatus"></view>
<view class="da-tree-item__checkbox--icon da-tree-radio-outline" v-else></view>
</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,
logError,
isArray,
isString,
isNumber,
isFunction,
} from './utils'
import basicProps from './props'
export default {
name: 'DaTree',
props: basicProps,
data() {
return {
unCheckedStatus,
halfCheckedStatus,
isCheckedStatus,
/** 原始的树数据 */
dataRef: [],
/** 处理后的一维树项数据 */
datalist: [],
/** 处理后的以key为键值的树项数据 */
datamap: {},
/** 默认的展开数据 */
expandedKeys: [],
/** 默认的已选数据 */
checkedKeys: null,
/** 加载状态 */
loadLoading: false,
fieldMap: {
value: 'value',
label: 'label',
children: 'children',
disabled: 'disabled',
append: 'append',
leaf: 'leaf',
sort: 'sort',
},
}
},
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() {
this.fieldMap = {
value: this.field?.key || this.field?.value || this.valueField || 'value',
label: this.field?.label || this.labelField || 'label',
children: this.field?.children || this.childrenField || 'children',
disabled: this.field?.disabled || this.disabledField || 'disabled',
append: this.field?.append || this.appendField || 'append',
leaf: this.field?.leaf || this.leafField || 'leaf',
sort: this.field?.sort || this.sortField || 'sort',
}
const data = deepClone(this.dataRef)
this.datalist = []
this.datamap = {}
// clean tree
this.handleTreeData(data)
// flat tree
this.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) {
return data.reduce((prev, cur, index) => {
const key = cur[this.fieldMap.value]
const children = cur[this.fieldMap.children] || null
const newItem = this.createNewItem(cur, index, parent, level)
if (insertIndex > -1) {
// 插入子项尾部
const index = (parent.childrenKeys?.length || 0) + insertIndex + 1
if (!parent?.childrenKeys?.includes(key)) {
this.datamap[key] = newItem
this.datalist.splice(index, 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.datamap[key] = newItem
this.datalist.push(newItem)
}
const hasChildren = children && children.length > 0
if (hasChildren) {
const childrenData = this.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
*/
createNewItem(item, index, parent, level) {
const key = item[this.fieldMap.value]
const label = item[this.fieldMap.label]
const sort = item[this.fieldMap.sort] || 0
const children = item[this.fieldMap.children] || null
const append = item[this.fieldMap.append] || null
let disabled = item[this.fieldMap.disabled] || false
// 优先继承父级禁用属性
disabled = parent?.disabled || disabled
let isLeaf = isFunction(this.isLeafFn) ? this.isLeafFn(item) : (item[this.fieldMap.leaf] || false)
// const hasChildren = children && children.length > 0
const isEmptyChildren = children && children.length === 0
let showArrow = true
// let isLeaf = !hasChildren
let expand = this.defaultExpandAll || false
// 是否异步加载模式
const isLoadMode = this.loadMode && isFunction(this.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 (!this.showCheckbox) {
if (this.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 = this.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
*/
checkInitData(list) {
let checkedKeyList = null
let expandedKeyList = []
if (this.showCheckbox) {
checkedKeyList = [...new Set(this.checkedKeys || [])]
expandedKeyList = this.expandChecked ? ([...(this.checkedKeys || []), ...(this.expandedKeys || [])]) : this.expandedKeys
} else {
checkedKeyList = this.checkedKeys || null
expandedKeyList = this.expandChecked && this.checkedKeys ? ([this.checkedKeys, ...(this.expandedKeys || [])]) : this.expandedKeys
}
this.handleCheckState(list, checkedKeyList, true)
// 处理初始展开
expandedKeyList = [...new Set(expandedKeyList)]
if (!this.defaultExpandAll) {
this.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
*/
handleCheckState(list, checkedKeyList, checked = true) {
// 多选
if (this.showCheckbox) {
if (checkedKeyList?.length) {
checkedKeyList.forEach(k => {
const item = this.datamap[k]
if (item) {
this.checkTheChecked(item, checked)
}
})
}
return
}
// 单选
for (let i = 0; i < list.length; i++) {
const item = list[i]
if (item.key === checkedKeyList) {
// console.log('item.key === checkedKeyList', item.key, checkedKeyList)
this.checkTheRadio(item, checked)
break
}
}
},
/**
* 校验多选节点
* @param item
* @param checked
*/
checkTheChecked(item, checked = true) {
const { childrenKeys, parentKeys, disabled = false } = item
if (!this.checkedDisabled && disabled) return
// 当前
item.checkedStatus = checked ? isCheckedStatus : unCheckedStatus
if (!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) {
const { parentKeys, isLeaf, disabled = false } = item
if (!this.checkedDisabled && disabled) return
// 限制末节点选中,但当前非末节点
if (this.onlyRadioLeaf && !isLeaf) {
logError(`限制了末节点选中,当前[${item.label}]非末节点`)
return
}
if (this.datalist?.length) {
this.datalist.forEach(k => {
k.checkedStatus = unCheckedStatus
})
}
console.log('000', item, parentKeys, this.datamap)
parentKeys.forEach(k => {
console.log('kkk', k, this.datamap[k])
const parentItem = this.datamap[k]
parentItem.checkedStatus = checked ? this.getParentCheckedStatus(parentItem) : unCheckedStatus
})
// 当前
item.checkedStatus = checked ? isCheckedStatus : unCheckedStatus
},
/**
* 处理父节点展开
* @param item
* @param expand
*/
// handleExpandParentNode(item, expand = true) {
// if (!expand) return
// if (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) {
// 收起
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 => {
this.datamap[ck].expand = false
this.datamap[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 = this.datamap[k.key]
kItem.show = true
})
}
// 族系
if (item.parentKeys?.length) {
item.parentKeys.forEach(k => {
const kItem = this.datamap[k]
kItem.expand = true
if (kItem.children?.length) {
kItem.children.forEach(k => {
const skItem = this.datamap[k.key]
skItem.show = true
})
}
})
}
}
}
},
/**
* 点击选框
* @param item
*/
handleCheckChange(item) {
const { childrenKeys, parentKeys, checkedStatus, isLeaf, disabled = false } = item
if (!this.showCheckbox) return
if (disabled) return
// 当前
item.checkedStatus = checkedStatus === isCheckedStatus ? unCheckedStatus : isCheckedStatus
// 子类
if (!this.checkStrictly) {
if (this.expandChecked) {
item.show = true
item.expand = childrenKeys?.length > 0 || isLeaf
}
childrenKeys.forEach(k => {
const childrenItem = this.datamap[k]
childrenItem.checkedStatus = childrenItem.disabled ? childrenItem.checkedStatus : item.checkedStatus
if (this.expandChecked) {
childrenItem.show = true
childrenItem.expand = childrenItem?.childrenKeys?.length > 0 || childrenItem.isLeaf
}
})
} else {
if (this.expandChecked) {
logError(`多选时,当 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, item)
},
/**
* 点击单选
* @param item
*/
handleRadioChange(item) {
const { parentKeys, checkedStatus, key, disabled = false, isLeaf } = item
if (this.showCheckbox) return
if (this.onlyRadioLeaf && !isLeaf) 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 : isCheckedStatus
this.checkedKeys = key
this.$emit('change', key, item)
},
/**
* 点击标签
*/
handleLabelClick(item) {
if (this.showCheckbox) {
this.handleCheckChange(item)
} else {
this.handleRadioChange(item)
}
},
/**
* 点击展开收起
* @param item
*/
async handleExpandedChange(item) {
const { expand, loading = false, disabled } = item
if (this.loadLoading && loading) return
this.checkExpandedChange(item)
// 异步
item.expand = !expand
let currentItem = null
if (!disabled) {
if (!this.showCheckbox && this.onlyRadioLeaf && this.loadMode) {
logError(`单选时,当 onlyRadioLeaf 为 true 时不支持动态数据`)
} else {
currentItem = await this.loadExpandNode(item)
}
}
this.$emit('expand', !expand, currentItem || item || null)
},
/**
* 检查展开状态
* @param item
*/
checkExpandedChange(item) {
const { expand, childrenKeys, children = null } = item
if (expand) {
if (childrenKeys?.length) {
childrenKeys.forEach(k => {
if (this.datamap[k]) {
this.datamap[k].show = false
this.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, loaded, children } = item
if (children?.length && !this.alwaysFirstLoad) {
return item
}
if (expand && this.loadMode && !loaded) {
if (isFunction(this.loadApi)) {
this.expandedKeys.push(key)
this.loadLoading = true
item.loading = true
const currentNode = deepClone(item)
const apiRes = await this.loadApi(currentNode)
// 新增子项
let newChildren = [...(item.originItem?.children || []), ...(apiRes || [])]
const newChildrenObj = {}
newChildren = newChildren.reduce((total, next) => {
newChildrenObj[next[this.fieldMap]] ? '' : newChildrenObj[next[this.fieldMap]] = true && total.push(next)
return total
}, [])
item.originItem.children = newChildren || null
if (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 = false
item.isLeaf = true
item.showArrow = false
}
this.loadLoading = false
item.loading = false
item.loaded = true
}
} else {
const eki = this.expandedKeys.findIndex(k => k === key)
if (eki >= 0) {
this.expandedKeys.splice(eki, 1)
}
}
return item
},
/**
* 获取父类的选中状态
* @param item
*/
getParentCheckedStatus(item) {
if (!item) {
return unCheckedStatus
}
if (!this.checkedDisabled && item.disabled) {
return item.checkedStatus || unCheckedStatus
}
// 单选时,父类永远为半选
if (!this.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
},
/**
* 返回已选的 key
*/
getCheckedKeys() {
return getAllNodeKeys(this.datalist, 'checkedStatus', isCheckedStatus, this.packDisabledkey)
},
/**
* 根据key设置已选
* @param keys 多选时为key的数组单选时为key
* @param checked 多选时为key的数组单选时为key
*/
setCheckedKeys(keys, checked = true) {
// 多选
if (this.showCheckbox) {
if (!isArray(keys)) {
logError(`setCheckedKeys 第一个参数非数组,传入的是[${keys}]`)
return
}
const list = this.datalist
// 取消选择
if (checked === false) {
let 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)]
this.checkedKeys = newCheckedKeys
this.handleCheckState(list, keys, false)
return
}
// 选择
const newCheckedKeys = [...this.checkedKeys, ...keys]
this.checkedKeys = [...new Set(newCheckedKeys)]
this.handleCheckState(list, this.checkedKeys, true)
if (this.expandChecked && checked) {
this.expandedKeys = [...new Set([...(this.checkedKeys || []), ...(keys || [])])]
this.handleExpandState(list, keys, true)
}
return
}
// 单选
// 如果为数组则拿第一个
if (isArray(keys)) {
keys = keys[0]
}
if (!isString(keys) && !isNumber(keys)) {
logError('setCheckedKeys 第一个参数字符串或数字,传入的是==>', keys)
return
}
const list = this.datalist
this.checkedKeys = checked ? keys : null
if (this.expandChecked && checked) {
this.handleExpandState(list, [keys], true)
}
this.handleCheckState(list, keys, !!checked)
},
/**
* 返回半选的 key
*/
getHalfCheckedKeys() {
return getAllNodeKeys(this.datalist, 'checkedStatus', halfCheckedStatus, this.packDisabledkey)
},
/**
* 返回未选的 key
*/
getUncheckedKeys() {
return getAllNodeKeys(this.datalist, 'checkedStatus', unCheckedStatus, this.packDisabledkey)
},
/**
* 返回已展开的 key
*/
getExpandedKeys() {
return getAllNodeKeys(this.datalist, 'expand', true)
},
/**
* 根据key展开/收起
* @param keys key的数组或字符串 all
* @param expand true为展开/false为收起
*/
setExpandedKeys(keys, expand = true) {
if (!Array.isArray(keys) && keys !== 'all') {
logError('setExpandedKeys 第一个参数非数组,传入的是===>', keys)
return
}
const list = this.datalist
// 展开/收起全部
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 < 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)
return
}
// 展开
const newExpandedKeys = []
for (let i = 0; i < list.length; i++) {
if (keys.includes(list[i].key)) {
newExpandedKeys.push(list[i].key)
}
}
this.expandedKeys = [...new Set(newExpandedKeys)]
this.handleExpandState(list, newExpandedKeys, true)
},
/**
* 返回未展开的 key
*/
getUnexpandedKeys() {
return getAllNodeKeys(this.datalist, 'expand', false)
},
/**
* 返回已选的节点
*/
getCheckedNodes() {
return getAllNodes(this.datalist, 'checkedStatus', isCheckedStatus, this.packDisabledkey)
},
/**
* 返回半选的节点
*/
getHalfCheckedNodes() {
return getAllNodes(this.datalist, 'checkedStatus', halfCheckedStatus, this.packDisabledkey)
},
/**
* 返回未选的节点
*/
getUncheckedNodes() {
return getAllNodes(this.datalist, 'checkedStatus', unCheckedStatus, this.packDisabledkey)
},
/**
* 返回已展开的节点
*/
getExpandedNodes() {
return getAllNodes(this.datalist, 'expand', true)
},
/**
* 返回未展开的节点
*/
getUnexpandedNodes() {
return getAllNodes(this.datalist, 'expand', false)
},
},
}
</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: 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: 'da-tree-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: 'da-tree-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>