|
@@ -2,38 +2,45 @@
|
|
|
<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">
|
|
|
+ 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 && !filterValue"
|
|
|
- class="da-tree-item__icon"
|
|
|
- @click="handleExpandedChange(item)">
|
|
|
+ v-if="item.showArrow && !filterValue"
|
|
|
+ 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>
|
|
|
+ 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>
|
|
|
+ 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 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>
|
|
@@ -41,20 +48,20 @@
|
|
|
|
|
|
<script>
|
|
|
|
|
|
-import { defineComponent, ref, unref, watch } from 'vue'
|
|
|
+import {defineComponent, ref, unref, watch} from 'vue'
|
|
|
|
|
|
import {
|
|
|
- unCheckedStatus,
|
|
|
- halfCheckedStatus,
|
|
|
- isCheckedStatus,
|
|
|
deepClone,
|
|
|
getAllNodeKeys,
|
|
|
getAllNodes,
|
|
|
- logError,
|
|
|
+ halfCheckedStatus,
|
|
|
isArray,
|
|
|
- isString,
|
|
|
- isNumber,
|
|
|
+ isCheckedStatus,
|
|
|
isFunction,
|
|
|
+ isNumber,
|
|
|
+ isString,
|
|
|
+ logError,
|
|
|
+ unCheckedStatus,
|
|
|
} from './utils'
|
|
|
import basicProps from './props'
|
|
|
|
|
@@ -62,7 +69,7 @@ export default defineComponent({
|
|
|
name: 'DaTree',
|
|
|
props: basicProps,
|
|
|
emits: ['change', 'expand'],
|
|
|
- setup(props, { emit }) {
|
|
|
+ setup(props, {emit}) {
|
|
|
/** 原始的树数据 */
|
|
|
const dataRef = ref([])
|
|
|
/** 处理后的一维树项数据 */
|
|
@@ -83,6 +90,7 @@ export default defineComponent({
|
|
|
append: 'append',
|
|
|
leaf: 'leaf',
|
|
|
sort: 'sort',
|
|
|
+ dataNode: "dataNode",
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -97,6 +105,7 @@ export default defineComponent({
|
|
|
append: props.field?.append || props.appendField || 'append',
|
|
|
leaf: props.field?.leaf || props.leafField || 'leaf',
|
|
|
sort: props.field?.sort || props.sortField || 'sort',
|
|
|
+ dataNode: props.field?.dataNode || 'dataNode',
|
|
|
}
|
|
|
|
|
|
const data = deepClone(dataRef.value)
|
|
@@ -170,6 +179,7 @@ export default defineComponent({
|
|
|
const sort = item[fieldMap.sort] || 0
|
|
|
const children = item[fieldMap.children] || null
|
|
|
const append = item[fieldMap.append] || null
|
|
|
+ const dataNode = item[fieldMap.dataNode] || false
|
|
|
let disabled = item[fieldMap.disabled] || false
|
|
|
// 优先继承父级禁用属性
|
|
|
disabled = parent?.disabled || disabled
|
|
@@ -243,6 +253,7 @@ export default defineComponent({
|
|
|
show,
|
|
|
sort,
|
|
|
disabled,
|
|
|
+ dataNode,
|
|
|
loaded: false,
|
|
|
loading: false,
|
|
|
indexs: [index],
|
|
@@ -257,11 +268,40 @@ export default defineComponent({
|
|
|
newItem.parentKeys = [parent.key, ...parent.parentKeys]
|
|
|
newItem.indexs = [...parent.indexs, index]
|
|
|
}
|
|
|
-
|
|
|
return newItem
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
+ * 处理选中
|
|
|
+ * @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 list
|
|
|
*/
|
|
@@ -304,42 +344,12 @@ export default defineComponent({
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 处理选中
|
|
|
- * @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
|
|
|
+ const {childrenKeys, parentKeys, disabled = false} = item
|
|
|
if (!props.checkedDisabled && disabled) return
|
|
|
|
|
|
// 当前
|
|
@@ -365,7 +375,7 @@ export default defineComponent({
|
|
|
* @param item
|
|
|
*/
|
|
|
function checkTheRadio(item, checked) {
|
|
|
- const { parentKeys, isLeaf, disabled = false } = item
|
|
|
+ const {parentKeys, isLeaf, disabled = false} = item
|
|
|
if (!props.checkedDisabled && disabled) return
|
|
|
|
|
|
// 限制末节点选中,但当前非末节点
|
|
@@ -465,7 +475,7 @@ export default defineComponent({
|
|
|
* @param item
|
|
|
*/
|
|
|
function handleCheckChange(item) {
|
|
|
- const { childrenKeys, parentKeys, checkedStatus, isLeaf, disabled = false } = item
|
|
|
+ const {childrenKeys, parentKeys, checkedStatus, isLeaf, disabled = false} = item
|
|
|
if (!props.showCheckbox) return
|
|
|
if (disabled) return
|
|
|
|
|
@@ -522,7 +532,7 @@ export default defineComponent({
|
|
|
* @param item
|
|
|
*/
|
|
|
function handleRadioChange(item) {
|
|
|
- const { parentKeys, checkedStatus, key, disabled = false, isLeaf } = item
|
|
|
+ const {parentKeys, checkedStatus, key, disabled = false, isLeaf} = item
|
|
|
if (props.showCheckbox) return
|
|
|
if (props.onlyRadioLeaf && !isLeaf) handleExpandedChange(item)
|
|
|
|
|
@@ -566,7 +576,7 @@ export default defineComponent({
|
|
|
async function handleExpandedChange(item) {
|
|
|
if (props.filterValue) return
|
|
|
|
|
|
- const { expand, loading = false, disabled } = item
|
|
|
+ const {expand, loading = false, disabled} = item
|
|
|
if (loadLoading.value && loading) return
|
|
|
|
|
|
checkExpandedChange(item)
|
|
@@ -591,7 +601,7 @@ export default defineComponent({
|
|
|
* @param item
|
|
|
*/
|
|
|
function checkExpandedChange(item) {
|
|
|
- const { expand, childrenKeys, children = null } = item
|
|
|
+ const {expand, childrenKeys, children = null} = item
|
|
|
|
|
|
if (expand) {
|
|
|
if (childrenKeys?.length) {
|
|
@@ -619,7 +629,7 @@ export default defineComponent({
|
|
|
* @param item
|
|
|
*/
|
|
|
async function loadExpandNode(item) {
|
|
|
- const { expand, key, loaded, children } = item
|
|
|
+ const {expand, key, loaded, children} = item
|
|
|
if (children?.length && !props.alwaysFirstLoad) {
|
|
|
return item
|
|
|
}
|
|
@@ -685,7 +695,7 @@ export default defineComponent({
|
|
|
return halfCheckedStatus
|
|
|
}
|
|
|
|
|
|
- const { children } = item
|
|
|
+ const {children} = item
|
|
|
// 子类全选中
|
|
|
const childrenCheckedAll = children.every(k => k.checkedStatus === isCheckedStatus)
|
|
|
if (childrenCheckedAll) {
|
|
@@ -733,6 +743,7 @@ export default defineComponent({
|
|
|
* 返回已选的 key
|
|
|
*/
|
|
|
const getCheckedKeys = () => getAllNodeKeys(datalist.value, 'checkedStatus', isCheckedStatus, props.packDisabledkey)
|
|
|
+
|
|
|
/**
|
|
|
* 根据key设置已选
|
|
|
* @param keys 单选时为数字或者字符串,多选时为数组
|
|
@@ -796,6 +807,7 @@ export default defineComponent({
|
|
|
|
|
|
handleCheckState(list, keys, !!checked)
|
|
|
}
|
|
|
+
|
|
|
/**
|
|
|
* 返回半选的 key
|
|
|
*/
|
|
@@ -812,6 +824,7 @@ export default defineComponent({
|
|
|
* 返回未展开的 key
|
|
|
*/
|
|
|
const getUnexpandedKeys = () => getAllNodeKeys(datalist.value, 'expand', false)
|
|
|
+
|
|
|
/**
|
|
|
* 根据key展开/收起
|
|
|
*
|
|
@@ -862,6 +875,7 @@ export default defineComponent({
|
|
|
expandedKeys.value = [...new Set(newExpandedKeys)]
|
|
|
handleExpandState(list, newExpandedKeys, true)
|
|
|
}
|
|
|
+
|
|
|
/**
|
|
|
* 返回已选的节点
|
|
|
*/
|
|
@@ -884,56 +898,56 @@ export default defineComponent({
|
|
|
const getUnexpandedNodes = () => getAllNodes(datalist.value, 'expand', false)
|
|
|
|
|
|
watch(
|
|
|
- () => props.defaultExpandedKeys,
|
|
|
- (v) => {
|
|
|
- if (v?.length) {
|
|
|
- expandedKeys.value = v
|
|
|
- } else {
|
|
|
- expandedKeys.value = []
|
|
|
- }
|
|
|
+ () => props.defaultExpandedKeys,
|
|
|
+ (v) => {
|
|
|
+ if (v?.length) {
|
|
|
+ expandedKeys.value = v
|
|
|
+ } else {
|
|
|
+ expandedKeys.value = []
|
|
|
+ }
|
|
|
|
|
|
- // if (v) checkInitData(datalist.value)
|
|
|
- },
|
|
|
- { immediate: true }
|
|
|
+ // 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
|
|
|
+ () => props.defaultCheckedKeys,
|
|
|
+ (v) => {
|
|
|
+ if (props.showCheckbox) {
|
|
|
+ if (v?.length) {
|
|
|
+ checkedKeys.value = v
|
|
|
+ } else {
|
|
|
+ checkedKeys.value = []
|
|
|
+ }
|
|
|
} else {
|
|
|
- checkedKeys.value = null
|
|
|
+ if (v || v === 0) {
|
|
|
+ checkedKeys.value = v
|
|
|
+ } else {
|
|
|
+ checkedKeys.value = null
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
- // checkInitData(datalist.value)
|
|
|
- },
|
|
|
- { immediate: true }
|
|
|
+ // checkInitData(datalist.value)
|
|
|
+ },
|
|
|
+ {immediate: true}
|
|
|
)
|
|
|
|
|
|
watch(
|
|
|
- () => props.data,
|
|
|
- (v) => {
|
|
|
- dataRef.value = deepClone(v)
|
|
|
- setTimeout(() => {
|
|
|
- initData()
|
|
|
- }, 36)
|
|
|
- },
|
|
|
- { immediate: true, deep: true }
|
|
|
+ () => props.data,
|
|
|
+ (v) => {
|
|
|
+ dataRef.value = deepClone(v)
|
|
|
+ setTimeout(() => {
|
|
|
+ initData()
|
|
|
+ }, 36)
|
|
|
+ },
|
|
|
+ {immediate: true, deep: true}
|
|
|
)
|
|
|
|
|
|
watch(
|
|
|
- () => props.filterValue,
|
|
|
- () => {
|
|
|
- filterData()
|
|
|
- },
|
|
|
+ () => props.filterValue,
|
|
|
+ () => {
|
|
|
+ filterData()
|
|
|
+ },
|
|
|
)
|
|
|
|
|
|
return {
|
|
@@ -1091,12 +1105,12 @@ export default defineComponent({
|
|
|
}
|
|
|
|
|
|
&.da-tree-checkbox-checked::after {
|
|
|
- color: var(--theme-color,#007aff);
|
|
|
+ color: var(--theme-color, #007aff);
|
|
|
content: '\ead4';
|
|
|
}
|
|
|
|
|
|
&.da-tree-checkbox-indeterminate::after {
|
|
|
- color: var(--theme-color,#007aff);
|
|
|
+ color: var(--theme-color, #007aff);
|
|
|
content: '\ebce';
|
|
|
}
|
|
|
|
|
@@ -1106,12 +1120,12 @@ export default defineComponent({
|
|
|
}
|
|
|
|
|
|
&.da-tree-radio-checked::after {
|
|
|
- color: var(--theme-color,#007aff);
|
|
|
+ color: var(--theme-color, #007aff);
|
|
|
content: '\ecc4';
|
|
|
}
|
|
|
|
|
|
&.da-tree-radio-indeterminate::after {
|
|
|
- color: var(--theme-color,#007aff);
|
|
|
+ color: var(--theme-color, #007aff);
|
|
|
content: '\ea4f';
|
|
|
}
|
|
|
}
|
|
@@ -1128,7 +1142,7 @@ export default defineComponent({
|
|
|
color: #555;
|
|
|
|
|
|
&--2 {
|
|
|
- color: var(--theme-color,#007aff);
|
|
|
+ color: var(--theme-color, #007aff);
|
|
|
}
|
|
|
|
|
|
&--append {
|