Skip to content

Commit 29977fa

Browse files
committed
fix(tree-select): fix deleteTag not working
1 parent b0aaef7 commit 29977fa

File tree

4 files changed

+128
-25
lines changed

4 files changed

+128
-25
lines changed

packages/renderless/src/base-select/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ export const setSelected =
319319
: 'halfselect'
320320
: 'check'
321321

322-
if (!state.selected?.[0]?.isTree && !state.selected?.[0]?.isGrid) {
322+
if (state.selected.length !== 0 && !state.selected?.[0]?.isTree && !state.selected?.[0]?.isGrid) {
323323
state.selected = result
324324
}
325325
state.selected.length && (state.selectedLabel = '')

packages/renderless/src/tree-select/index.ts

Lines changed: 96 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -115,49 +115,73 @@ export const getPluginOption =
115115
*/
116116
export const getCheckedData =
117117
({ props, state }) =>
118-
() => {
118+
(selected) => {
119119
const checkedKey = []
120120

121-
if (!Array.isArray(state.selected)) {
122-
return props.modelValue ? [props.modelValue] : [state.selected[props.valueField]]
121+
if (!Array.isArray(selected)) {
122+
return props.modelValue ? [props.modelValue] : [selected[props.valueField]]
123123
} else {
124-
state.selected.length > 0 &&
125-
state.selected.forEach((item) => {
124+
selected.length > 0 &&
125+
selected.forEach((item) => {
126126
checkedKey.push(item[props.valueField])
127127
})
128128

129129
return checkedKey
130130
}
131131
}
132132

133+
/**
134+
* 递归获取树节点的所有子节点 id 数组
135+
* @params childNodes 树节点的子节点
136+
* @params key value 映射字段(valueField)
137+
* @return 示例:[{ value: 4, children: [{ value: 6 }, { value: 9 }] }] => [4, 6, 9](其中 childNodes 的结构做了简化处理)
138+
*/
139+
export const getChildValue = () => (childNodes, key) => {
140+
const ids = []
141+
142+
const getChild = (nodes) => {
143+
nodes.forEach((node) => {
144+
ids.push(node.data[key])
145+
146+
if (node.childNodes.length > 0) {
147+
getChild(node.childNodes)
148+
}
149+
})
150+
}
151+
152+
getChild(childNodes)
153+
154+
return ids
155+
}
156+
133157
export const mounted =
134158
({ api, state, props, vm }) =>
135159
() => {
136-
if (!state.value || state.value.length === 0) return
160+
if (!state.modelValue || state.modelValue.length === 0) return
137161

138162
if (props.multiple) {
139163
let initialNodes = []
140-
if (Array.isArray(state.value)) {
141-
state.value.forEach((value) => {
164+
if (Array.isArray(state.modelValue)) {
165+
state.modelValue.forEach((value) => {
142166
const option = api.getPluginOption(value)
143167
initialNodes = initialNodes.concat(option)
144168
})
145169
}
146170

147-
vm.$refs.baseSelectRef.updateSelectedData(
148-
initialNodes.map((node) => {
149-
return {
150-
...node,
151-
currentLabel: node[props.textField],
152-
value: node[props.valueField],
153-
isTree: true
154-
}
155-
})
156-
)
171+
const selected = initialNodes.map((node) => {
172+
return {
173+
...node,
174+
currentLabel: node[props.textField],
175+
value: node[props.valueField],
176+
isTree: true
177+
}
178+
})
157179

158-
state.defaultCheckedKeys = api.getCheckedData()[0]
180+
vm.$refs.baseSelectRef.updateSelectedData(selected)
181+
182+
state.defaultCheckedKeys = api.getCheckedData(selected)
159183
} else {
160-
const data = api.getPluginOption(state.value)[0]
184+
const data = api.getPluginOption(state.modelValue)[0]
161185
vm.$refs.baseSelectRef.updateSelectedData({
162186
...data,
163187
currentLabel: data[props.textField],
@@ -170,3 +194,55 @@ export const mounted =
170194
state.currentKey = data[props.valueField]
171195
}
172196
}
197+
198+
export const watchValue =
199+
({ api, props, vm, state }) =>
200+
(newValue, oldValue) => {
201+
if (props.multiple) {
202+
// 取新旧值的差集,用来判断是否是删除标签的操作,如果差值只有一个值,说明是删除操作
203+
// 如果是删除操作,且不是父子严格模式,则需要将父节点的值也删除(严格模式下父子节点勾选相互独立,不会相互影响)
204+
const xorResult = oldValue.filter((item) => !newValue.includes(item))
205+
const tagId = xorResult[0]
206+
const treeIds = [tagId]
207+
let checkedKeys = newValue
208+
209+
// 处理输入框中删除选中标签时,联动下拉面板的逻辑
210+
if (xorResult.length === 1 && !props.treeOp.checkStrictly) {
211+
let node = vm.$refs.treeRef.getNode(tagId)
212+
213+
if (!node.isLeaf) {
214+
treeIds.push(...api.getChildValue(node.childNodes, props.valueField))
215+
}
216+
217+
while (node.parent && !Array.isArray(node.parent.data)) {
218+
node.parent.data && treeIds.push(node.parent.data[props.valueField])
219+
node = node.parent
220+
}
221+
222+
checkedKeys = newValue.filter((item) => !treeIds.includes(item))
223+
}
224+
225+
let initialNodes = []
226+
if (Array.isArray(checkedKeys)) {
227+
checkedKeys.forEach((value) => {
228+
const option = api.getPluginOption(value)
229+
initialNodes = initialNodes.concat(option)
230+
})
231+
}
232+
233+
const selected = initialNodes.map((node) => {
234+
return {
235+
...node,
236+
currentLabel: node[props.textField],
237+
value: node[props.valueField],
238+
isTree: true
239+
}
240+
})
241+
242+
// 更新输入框中选中的标签
243+
vm.$refs.baseSelectRef.updateSelectedData(selected)
244+
245+
// 更新下拉面板中选中的树节点
246+
vm.$refs.treeRef.setCheckedKeys(checkedKeys)
247+
}
248+
}

packages/renderless/src/tree-select/vue.ts

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
1-
import { check, filter, getCheckedData, getPluginOption, getTreeData, mounted, nodeClick } from './index'
1+
import {
2+
check,
3+
filter,
4+
getCheckedData,
5+
getPluginOption,
6+
getTreeData,
7+
mounted,
8+
nodeClick,
9+
watchValue,
10+
getChildValue
11+
} from './index'
212

313
export const api = ['state', 'check', 'filter', 'nodeClick']
414

@@ -11,7 +21,7 @@ export const renderless = (props, { reactive, computed, watch, onMounted }, { vm
1121
defaultCheckedKeys: [],
1222
remoteData: [],
1323
treeData: props.treeOp.data,
14-
value: computed(() => props.modelValue)
24+
modelValue: []
1525
})
1626

1727
Object.assign(api, {
@@ -22,7 +32,9 @@ export const renderless = (props, { reactive, computed, watch, onMounted }, { vm
2232
getPluginOption: getPluginOption({ api, props, state }),
2333
getTreeData: getTreeData({ props, state }),
2434
mounted: mounted({ api, state, props, vm }),
25-
nodeClick: nodeClick({ props, vm, emit })
35+
nodeClick: nodeClick({ props, vm, emit }),
36+
watchValue: watchValue({ api, props, vm, state }),
37+
getChildValue: getChildValue()
2638
})
2739

2840
watch(
@@ -31,6 +43,20 @@ export const renderless = (props, { reactive, computed, watch, onMounted }, { vm
3143
{ immediate: true, deep: true }
3244
)
3345

46+
watch(
47+
() => props.modelValue,
48+
() => {
49+
if (props.multiple && Array.isArray(props.modelValue)) {
50+
state.modelValue = [...props.modelValue]
51+
} else {
52+
state.modelValue = props.modelValue
53+
}
54+
},
55+
{ immediate: true, deep: true }
56+
)
57+
58+
watch(() => state.modelValue, api.watchValue)
59+
3460
onMounted(api.mounted)
3561

3662
return api

packages/vue/src/tree-select/src/pc.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<tiny-base-select
33
ref="baseSelectRef"
44
class="tiny-tree-select"
5-
v-model="state.value"
5+
v-model="state.modelValue"
66
:clearable="clearable"
77
:filterable="filterable"
88
:filter-method="filter"
@@ -11,6 +11,7 @@
1111
<template #panel>
1212
<tiny-tree
1313
ref="treeRef"
14+
:check-strictly="treeOp.checkStrictly"
1415
:current-node-key="!multiple ? state.currentKey : ''"
1516
:data="state.treeData"
1617
:default-checked-keys="multiple ? state.defaultCheckedKeys : treeOp.defaultCheckedKeys || []"

0 commit comments

Comments
 (0)