Skip to content

Commit 4c720f5

Browse files
committed
小范围重构: 弃用watch监听, 改用$emit向上和原生js通过前序和层序向下遍历
1 parent e57382c commit 4c720f5

File tree

3 files changed

+69
-38
lines changed

3 files changed

+69
-38
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "vue-search-tree",
3-
"version": "2.2.1",
3+
"version": "2.2.2",
44
"description": "",
55
"main": "index.js",
66
"scripts": {

src/search-node.vue

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -16,29 +16,10 @@ export default {
1616
children: [],
1717
}
1818
},
19-
computed: {
20-
indeterminate () {
21-
const children = this.data[this.root.defaultProps.children]
22-
const number = children.reduce((num, item) => num += +item.checked, 0)
23-
// 子节点存在并且没有全部选中, 并且children里有一个被选中的
24-
return (!number || number !== children.length) && !!this.root._preorder(children, item => item.checked)
25-
}
26-
},
2719
created () {
28-
const { data } = this
29-
const parent = this.$parent
30-
this.root = parent.isTree ? parent : parent.root
31-
this.$set(this.data, '$pid', parent.isTree ? null : parent.data[this.root.nodeKey])
32-
this.$watch(`data.${this.root.defaultProps.children}`, {
33-
handler (newVal, old) {
34-
const len = newVal.length
35-
const number = newVal.reduce((num, item) => num += +item.checked, 0)
36-
// 子节点存在并且全都选中
37-
this.data.checked = (!old.length && this.data.checked) || (!!len && number === len)
38-
},
39-
deep: true,
40-
immediate: false
41-
})
20+
const { data, $parent } = this
21+
this.root = $parent.isTree ? $parent : $parent.root
22+
this.$set(data, '$pid', $parent.isTree ? null : $parent.data[this.root.nodeKey])
4223
},
4324
render () {
4425
const { data, root } = this
@@ -57,7 +38,7 @@ export default {
5738
class="point"
5839
value={data.checked}
5940
disabled={data[disabled]}
60-
indeterminate={this.indeterminate}
41+
indeterminate={data.indeterminate}
6142
onClick={e => this.handlerChecked(e)}
6243
></zCheckbox>
6344
}
@@ -72,29 +53,51 @@ export default {
7253
data.$keys?.length ? data[name].split('').map(
7354
(curr, i) => <span style={{ color: data.$keys.indexOf(i) > -1 ? 'red': '#666' }}>{curr}</span>
7455
) : <span style={{ color: '#666' }}>{data[name]}</span>
75-
}
56+
} {data.checked + ''} {data.indeterminate + ''}
7657
</p>
7758
}
7859
</div>
7960
</li>
8061
{
8162
!!data[children].length && data.expand && <div>
82-
{ data[children].map(item => <search-node key={item[root.nodeKey]} data={item}></search-node>) }
63+
{
64+
data[children].map(item => <search-node
65+
key={item[root.nodeKey]}
66+
data={item}
67+
onCheck-change={this._upwardUpdateChecked}
68+
></search-node>)
69+
}
8370
</div>
8471
}
8572
</ul> : null
8673
},
8774
methods: {
75+
_upwardUpdateChecked (checked) {
76+
const { data, root } = this
77+
const { children } = root.defaultProps
78+
// 获取所有选中节点的数量
79+
const checkedNum = data[children].reduce((num, item) => num += +item.checked, 0)
80+
// 所有节点都被选中时checked=true, 反之false
81+
data.checked = checkedNum === data[children].length
82+
//
83+
if (checkedNum === data[children].length) {
84+
data.indeterminate = false
85+
} else {
86+
data.indeterminate = !!checkedNum || !!root._preorder(data[children], item => item.checked)
87+
}
88+
this.$emit('check-change', data.checked)
89+
},
8890
handlerChecked (e) {
8991
const { data, root } = this
9092
const { children, disabled } = root.defaultProps
9193
let checked = !data.checked
9294
if (data[disabled]) return false
9395
// 过滤所有disabled=false的叶子节点, 如果有没选中的就重写checked
9496
data[children].length && checked && (
95-
checked = !!this.root._preorder(data[children], item => !item[children].length && !item[disabled] && !item.checked)
97+
checked = !!root._levelOrder(data[children], item => !item[disabled] && !item.checked)
9698
)
97-
this.root._downwardUpdateChecked(data, checked)
99+
root._downwardUpdateChecked(data, checked)
100+
this.$emit('check-change', checked)
98101
root.$emit('node-checked', e, deepCopy(data))
99102
},
100103
handlerExpand (e) {

src/search-tree.vue

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -171,25 +171,35 @@ export default {
171171
this.$set(node, disabled, node[disabled] || false)
172172
this.$set(node, 'visible', true)
173173
this.$set(node, 'level', parent ? ~~parent.level + 1 : 1)
174-
this.$set(node, 'checked', Reflect.has(node, 'checked') ? node.checked : (parent && parent.checked) || this.defaultCheckedKeys.indexOf(key) > -1)
175-
this.$set(node, 'expand', Reflect.has(node, 'expand') ? node.expand : this.defaultExpandAll || this.defaultExpandedKeys.indexOf(key) > -1)
174+
this.$set(node, 'checked', Reflect.has(node, 'checked') ? node.checked : (parent && parent.checked) || this.defaultCheckedKeys.includes(key))
175+
this.$set(node, 'indeterminate', false)
176+
this.$set(node, 'expand', Reflect.has(node, 'expand') ? node.expand : this.defaultExpandAll || this.defaultExpandedKeys.includes(key))
176177
this.$set(node, '$keys', [])
177178
this.$set(node, '$sort', 0)
178179
},
179180
_initData () { // 初始化数据
180181
const { children } = this.defaultProps
181182
const _deep = (arr, parent) => {
183+
let checkedNum = 0, anyOne = false
182184
arr.forEach(item => {
183185
this._initNode(item, parent)
184-
item[children]?.length && _deep(item[children], item)
186+
checkedNum += +item.checked
187+
item[children].length && _deep(item[children], item)
185188
item.expand && parent && (parent.expand = true)
189+
if (item.indeterminate) anyOne = true
186190
})
191+
if (parent) {
192+
// 子节点是否全选 || 子节点的叶子节点全部选中
193+
parent.checked = checkedNum === arr.length || !this._levelOrder(arr, item => !item.checked)
194+
// 子节点有一个是半选 || 被选中的节点不为零并且被选中的节点不等于子节点长度 || 该节点不是全选并且子节点中任意一个被选中
195+
parent.indeterminate = anyOne || (!!checkedNum && checkedNum != arr.length) || (!parent.checked && !!this._preorder(arr, item => item.checked))
196+
}
187197
}
188198
_deep(this.sourceData)
189199
const data = deepCopy(this.sourceData)
190200
this.deepData = this._getLdqTree(data)
191201
},
192-
_getLdqTree (tree) { // 获取关键词索引并排序, 输入关键词为空时不要走这个方法
202+
_getLdqTree (tree) { // 获取关键词索引并排序
193203
const { name, children } = this.defaultProps
194204
tree.forEach(item => {
195205
if (this._search) {
@@ -215,12 +225,30 @@ export default {
215225
},
216226
_downwardUpdateChecked (data, checked) { // 向下处理树节点的checked
217227
const { children, disabled } = this.defaultProps
218-
// 如果当前节点是叶子节点, 只需要判断disabled
228+
// 如果当前节点是叶子节点, 只需要判断disabled即可
219229
if (!data[children].length) return !data[disabled] && (data.checked = checked)
220-
// 然后过滤所有叶子节点, 如果全部都是disabled就return
221-
if (!this._levelOrder(data[children], item => !item[disabled])) return false
222-
// 最后判断当前节点是否为disable
223-
!data[disabled] && (data.checked = checked)
230+
// 提前声明变量来合并多次层序遍历
231+
let allNodeIsDisabled = true,
232+
oneNodeIsDisabledAndChecked = false,
233+
oneNodeIsDisabledAndUncheck = false
234+
// 遍历所有叶子节点
235+
this._levelOrder(data[children], item => {
236+
if (!item[disabled]) allNodeIsDisabled = false
237+
if (item[disabled] && item.checked) oneNodeIsDisabledAndChecked = true
238+
if (item[disabled] && !item.checked) oneNodeIsDisabledAndUncheck = true
239+
})
240+
// 如果所有叶子节点都是disabled就提前打断逻辑
241+
if (allNodeIsDisabled) return false
242+
/**
243+
* 如果有一个叶子节点是disabled并且checked=false, 那么该节点只有半选和全不选两种状态
244+
* 如果有一个叶子节点是disabled并且checked=true, 那么该节点只有半选和全选两种状态
245+
*/
246+
data.indeterminate = checked ? oneNodeIsDisabledAndUncheck : oneNodeIsDisabledAndChecked
247+
// 默认情况和oneNodeIsDisabledAndChecked时
248+
data.checked = checked
249+
// 由于两种状态可能叠加存在, 所以oneNodeIsDisabledAndUncheck的判断放在后面
250+
if (oneNodeIsDisabledAndUncheck) data.checked = false
251+
// 可以向下继续遍历
224252
data[children].forEach(item => this._downwardUpdateChecked(item, checked))
225253
},
226254
getNodeByKey (key) { // 根据key获取对应深拷贝节点
@@ -230,7 +258,7 @@ export default {
230258
return this._preorder(this.deepData, item => item[this.nodeKey] == key)
231259
},
232260
resetChecked () { // 取消所有节点的选中状态
233-
return !this._preorder(this.deepData, item => item.checked = false)
261+
return !this._preorder(this.deepData, item => (item.checked = false, item.indeterminate = false))
234262
},
235263
setCheckedByKeys (keys, checked) { // 设置指定keys节点的checked
236264
if (!keys.length) return null

0 commit comments

Comments
 (0)