Skip to content

Commit

Permalink
Merge pull request #4 from hug-sun-1/refactor/tree-4
Browse files Browse the repository at this point in the history
refactor(Tree): realize filter and async and render-content
  • Loading branch information
Lydanne authored Feb 2, 2021
2 parents 6bd8c71 + 0348713 commit 77f9456
Show file tree
Hide file tree
Showing 15 changed files with 609 additions and 161 deletions.
12 changes: 6 additions & 6 deletions packages/element3/src/components/Tree/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import ElTree from './src/Tree.vue'
import _ElTree from './src/Tree.vue'

ElTree.install = function (app) {
app.component(ElTree.name, ElTree)
}

export { ElTree }
export const ElTree = Object.assign({}, _ElTree, {
install: function (app) {
app.component(_ElTree.name, _ElTree)
}
})
15 changes: 14 additions & 1 deletion packages/element3/src/components/Tree/src/NodeContent.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script lang="ts">
import { TreeNode } from './entity/TreeNode'
import { h } from 'vue'
import { h, inject } from 'vue'
export default {
name: 'ElNodeContent',
Expand All @@ -12,7 +12,20 @@ export default {
},
setup(props) {
const elTree: any = inject('elTree')
return () => {
if (typeof elTree.$slots.default === 'function') {
return elTree.$slots.default({
node: props.node,
data: elTree.tree.getRawNode(props.node)
})
} else if (typeof elTree.renderContent === 'function') {
return elTree.renderContent({
node: props.node,
data: elTree.tree.getRawNode(props.node)
})
}
return h('span', props.node.label)
}
}
Expand Down
34 changes: 33 additions & 1 deletion packages/element3/src/components/Tree/src/Tree.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
ref="treeMain"
v-model="_modelValue"
:defaultNodeKey="_defaultNodeKey"
:async="_async"
:asyncLoader="_asyncLoader"
></el-tree-main>
</template>
<script lang="ts">
Expand All @@ -19,7 +21,15 @@ export default defineComponent({
modelValue: Array,
defaultNodeKey: Object,
props: Object
props: Object,
filterNodeMethod: Function,
async: Boolean,
lazy: Boolean,
asyncLoader: Function,
load: Function
},
emits: ['update:modelValue', 'update:data'],
computed: {
Expand All @@ -34,6 +44,28 @@ export default defineComponent({
},
_defaultNodeKey() {
return this.defaultNodeKey ?? this.props
},
_async() {
return this.async || this.lazy
},
_asyncLoader() {
return this.asyncLoader ?? this.load
}
},
methods: {
filter(value) {
const tree = this.$refs.treeMain.tree
if (typeof this.filterNodeMethod === 'function') {
return tree.filter((currentNode) =>
this.filterNodeMethod(
value,
tree.getRawNode(currentNode),
currentNode
)
)
} else {
return tree.filter(value)
}
}
}
})
Expand Down
28 changes: 17 additions & 11 deletions packages/element3/src/components/Tree/src/TreeMain.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
import { t } from '../../../locale'
import ElTreeNode from './TreeNode.vue'
import { Tree } from './entity/Tree'
import { ID } from './entity/TreeNode'
import { AsyncLoader, ID } from './entity/TreeNode'
import { DefaultNodeKey, RawNodeBase } from './types'
export default {
name: 'ElTreeMain',
Expand All @@ -41,46 +41,52 @@ export default {
autoExpandParent: { type: Boolean, default: true },
expandOnClickNode: { type: Boolean, default: true },
expanded: { type: Array as PropType<ID[]>, default: () => [] },
defaultExpandAll: Boolean
defaultExpandAll: Boolean,
async: Boolean,
asyncLoader: Function as PropType<AsyncLoader>,
renderContent: Function
},
emits: ['update:modelValue', 'update:checked', 'update:expanded'],
setup(props, ctx) {
const elTree = getCurrentInstance().proxy
provide('elTree', elTree)
const tree = new Tree(props.modelValue, props.defaultNodeKey)
ctx.emit('update:modelValue', tree.rawNodesProxy)
const rootChildren = computed(() => tree.root.children)
tree.rootProxy.setStrictly(props.checkStrictly)
const rootChildren = computed(() => tree.rootProxy.children)
watchEffect(
() => {
tree.setCheckedByIds(props.checked)
tree.expandNodeByIds(props.expanded)
},
{
flush: 'post'
// exec after wait component flush
}
)
watchEffect(() => {
ctx.emit('update:checked', tree.getCheckedIds())
ctx.emit('update:expanded', tree.getExpandedNodeIds())
})
if (props.defaultExpandAll) {
tree.expandAll()
}
if (props.async) tree.bindAsyncLoader(props.asyncLoader)
tree.setStrictly(props.checkStrictly)
watchEffect(
() => {
tree.expandNodeByIds(props.expanded)
tree.setCheckedByIds(props.checked)
},
{
flush: 'post'
// exec after wait component flush
}
)
watchEffect(() => {
ctx.emit('update:expanded', tree.getExpandedNodeIds())
ctx.emit('update:checked', tree.getCheckedIds())
})
if (props.defaultExpandAll) tree.expandAll(true)
return {
tree,
rootChildren
Expand Down
10 changes: 7 additions & 3 deletions packages/element3/src/components/Tree/src/TreeNode.vue
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
<template>
<div
v-show="node.isVisible"
class="el-tree-node"
:class="{
'is-checked': node.isChecked,
'is-focusable': !node.isDisabled,
'is-expanded': node.isExpanded
'is-expanded': node.isExpanded,
'is-hidden': !node.isVisible
}"
role="TreeNode"
:aria-checked="node.isChecked"
:aria-expanded="node.isExpanded"
:aria-disabled="node.isDisabled"
:aria-checked="node.isChecked"
:aria-visible="node.isVisible"
tabindex="-1"
:id="'TreeNode' + node.id"
:data-node-id="node.id"
@click.stop="onClickTreeNode"
>
<div
class="el-tree-node__content"
:style="{ 'padding-left': node.level * elTree.indent + 'px' }"
:style="{ 'padding-left': (node.level - 1) * elTree.indent + 'px' }"
@click="onClickTreeNodeContent"
>
<span
Expand Down
70 changes: 49 additions & 21 deletions packages/element3/src/components/Tree/src/entity/Tree.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { DefaultNodeKey, RawNodeBase } from '../types'
import { ID, TreeNode } from './TreeNode'
import { AsyncLoader, HandlerCb, ID, TreeNode } from './TreeNode'
import { TreeMapper } from './TreeMapper'

export class Tree<RawNode extends RawNodeBase> {
Expand Down Expand Up @@ -34,10 +34,10 @@ export class Tree<RawNode extends RawNodeBase> {
children: 'children',
isDisabled: 'isDisabled',
isAsync: 'isAsync',
isChecked: 'isChecked',
isVisible: 'isVisible',
isExpanded: 'isExpanded',
isLeaf: 'isLeaf'
// isChecked: 'isChecked',
// isVisible: 'isVisible',
// isExpanded: 'isExpanded',
},
defaultNodeKey
)
Expand All @@ -60,14 +60,9 @@ export class Tree<RawNode extends RawNodeBase> {
}

getCheckedIds(): ID[] {
const ids = []
this.rootProxy.depthEach((currentNode: TreeNode) => {
if (currentNode !== this.rootProxy && currentNode.isChecked) {
ids.push(currentNode.id)
}
})

return ids
return this.root
.findMany((node) => node !== this.root && node.isChecked)
.map((node) => node.id)
}

expandNodeByIds(ids: ID[]): void {
Expand All @@ -79,19 +74,52 @@ export class Tree<RawNode extends RawNodeBase> {
}

getExpandedNodeIds(): ID[] {
const ids = []
this.rootProxy.depthEach((currentNode: TreeNode) => {
if (currentNode !== this.rootProxy && currentNode.isExpanded) {
ids.push(currentNode.id)
}
})

return ids
return this.root
.findMany((node) => node !== this.root && node.isExpanded)
.map((node) => node.id)
}

expandAll(v = true): void {
this.rootProxy.depthEach((currentNode) => {
currentNode.expand(v, false, () => this.expandAll(v))
})
}

filter(target: HandlerCb | string): TreeNode[] {
const nodes = this.root.findMany(target)
this.root.depthEach((currentNode) => {
currentNode.expand(v, false)
currentNode.hide()
})
nodes.forEach((node) => node.show())
return nodes
}

getRawNode(treeNode: TreeNode): RawNode {
return this._mapper.getRawNode(treeNode)
}

getTreeNode(rawNode: RawNode): TreeNode {
return this._mapper.getTreeNode(rawNode)
}

setStrictly(isStrictly: boolean): void {
this.root.setStrictly(isStrictly)
}

bindAsyncLoader(asyncLoader: AsyncLoader): void {
const _asyncLoader = (node, resolve) => {
const _resolve = (nodes: RawNode[] | TreeNode[]) => {
if (nodes.length === 0) {
return resolve([])
}
if (node[0] instanceof TreeNode) {
return resolve(nodes)
}
return resolve(this._mapper.convertToTreeNodes(nodes as RawNode[]))
}
asyncLoader(node, _resolve)
}
this.root.bindAsyncLoader(_asyncLoader)
// this.rootProxy.expand(true)
}
}
12 changes: 11 additions & 1 deletion packages/element3/src/components/Tree/src/entity/TreeMapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ export class TreeMapper<RawNode extends RawNodeBase> {
this.convertToTreeNodes(rawNode[this._toRawNodeKey.get('children')]),
{
isDisabled: rawNode[this._toRawNodeKey.get('isDisabled')],
isLeaf: rawNode[this._toRawNodeKey.get('isLeaf')]
isLeaf: rawNode[this._toRawNodeKey.get('isLeaf')],
isAsync: rawNode[this._toRawNodeKey.get('isAsync')]
}
)
) as TreeNode
Expand Down Expand Up @@ -251,6 +252,7 @@ export class TreeMapper<RawNode extends RawNodeBase> {
key: string,
value: any
): void {
if (!currentRawNode) return // TODO: 暂时这样,有个未知的BUG,对懒加载的性能有影响
if (key === this._toRawNodeKey.get('children')) {
Reflect.set(currentRawNode, key, this.convertToRawNodes(value))
} else if (Reflect.has(currentRawNode, key)) {
Expand All @@ -270,4 +272,12 @@ export class TreeMapper<RawNode extends RawNodeBase> {
): void {
currentRawNode[this._toRawNodeKey.get('children')][index] = childNode
}

getRawNode(treeNode: TreeNode): RawNode {
return this._toRawNode.get(this._treeNodeWatcher.getRaw(treeNode))
}

getTreeNode(rawNode: RawNode): TreeNode {
return this._toTreeNode.get(this._rawNodeWatcher.getRaw(rawNode))
}
}
Loading

0 comments on commit 77f9456

Please sign in to comment.