Skip to content

Commit

Permalink
Merge pull request #3 from hug-sun-1/refactor/tree-3
Browse files Browse the repository at this point in the history
refactor(Tree): Implements expanding the folding child element
  • Loading branch information
Lydanne authored Feb 1, 2021
2 parents 7ab0a8e + 2dbad32 commit 6bd8c71
Show file tree
Hide file tree
Showing 8 changed files with 289 additions and 22 deletions.
30 changes: 27 additions & 3 deletions packages/element3/src/components/Tree/src/TreeMain.vue
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,25 @@ export default {
checked: { type: Array as PropType<ID[]>, default: () => [] },
showCheckbox: Boolean,
checkOnClickNode: Boolean,
checkStrictly: Boolean
checkStrictly: Boolean,
iconClass: { type: String, default: 'el-icon-caret-right' },
renderAfterExpand: { type: Boolean, default: true },
accordion: Boolean,
autoExpandParent: { type: Boolean, default: true },
expandOnClickNode: { type: Boolean, default: true },
expanded: { type: Array as PropType<ID[]>, default: () => [] },
defaultExpandAll: Boolean
},
emits: ['update:modelValue', 'update:checked'],
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)
watchEffect(
() => {
tree.setCheckedByIds(props.checked)
Expand All @@ -57,6 +65,22 @@ export default {
ctx.emit('update:checked', tree.getCheckedIds())
})
if (props.defaultExpandAll) {
tree.expandAll()
}
watchEffect(
() => {
tree.expandNodeByIds(props.expanded)
},
{
flush: 'post'
// exec after wait component flush
}
)
watchEffect(() => {
ctx.emit('update:expanded', tree.getExpandedNodeIds())
})
return {
tree,
rootChildren
Expand Down
44 changes: 39 additions & 5 deletions packages/element3/src/components/Tree/src/TreeNode.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,37 @@
class="el-tree-node"
:class="{
'is-checked': node.isChecked,
'is-focusable': !node.isDisabled
'is-focusable': !node.isDisabled,
'is-expanded': node.isExpanded
}"
role="TreeNode"
:aria-checked="node.isChecked"
:aria-disabled="node.isDisabled"
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' }"
@click="onClickTreeNodeContent"
>
<span
:class="[
{ expanded: node.isExpanded, 'is-leaf': node.isLeaf },
'el-tree-node__expand-icon',
elTree.iconClass
]"
@click.stop="onClickTreeNodeExpand"
>
</span>
<el-checkbox
v-if="elTree.showCheckbox"
:modelValue="node.isChecked"
:indeterminate="node.isIndeterminate"
:disabled="node.isDisabled"
@click.prevent="onClickCheckbox"
@click.prevent.stop="onClickCheckbox"
>
</el-checkbox>
<span
Expand All @@ -35,7 +46,13 @@
></el-node-content>
</div>
<el-collapse-transition>
<div class="el-tree-node__children" role="group">
<div
v-show="node.isExpanded"
v-if="!elTree.renderAfterExpand || node.isRendered"
class="el-tree-node__children"
role="group"
:aria-expanded="node.isExpanded"
>
<el-tree-node
v-for="child in node.children"
:key="child.id"
Expand Down Expand Up @@ -67,7 +84,13 @@ export default {
},
setup(props) {
const elTree = inject('elTree', { indent: 10, checkOnClickNode: false })
const elTree = inject('elTree', {
indent: 10,
checkOnClickNode: false,
accordion: false,
autoExpandParent: true,
expandOnClickNode: true
})
const onClickTreeNodeContent = () => {
if (!elTree.checkOnClickNode) {
return
Expand All @@ -80,10 +103,21 @@ export default {
}
props.node.setChecked()
}
const onClickTreeNodeExpand = () => {
if (elTree.accordion) props.node.collapse()
else props.node.expand(undefined, elTree.autoExpandParent)
}
const onClickTreeNode = () => {
if (elTree.expandOnClickNode) {
onClickTreeNodeExpand()
}
}
return {
elTree,
onClickCheckbox,
onClickTreeNodeContent
onClickTreeNodeContent,
onClickTreeNode,
onClickTreeNodeExpand
}
}
}
Expand Down
25 changes: 25 additions & 0 deletions packages/element3/src/components/Tree/src/entity/Tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,29 @@ export class Tree<RawNode extends RawNodeBase> {

return ids
}

expandNodeByIds(ids: ID[]): void {
this.rootProxy.depthEach((currentNode: TreeNode) => {
if (ids.includes(currentNode.id)) {
currentNode.expand(true)
}
})
}

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

return ids
}

expandAll(v = true): void {
this.root.depthEach((currentNode) => {
currentNode.expand(v, false)
})
}
}
45 changes: 40 additions & 5 deletions packages/element3/src/components/Tree/src/entity/TreeNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,20 @@ export class TreeNode implements TreeNodePublicProp {
label: string
parent: TreeNode
children: TreeNode[] = []
private _isLeaf = false
private _isChecked = false
private _isStrictly = false
private _isDisabled = false
private _isLeaf: boolean
private _isChecked: boolean
private _isStrictly: boolean
private _isDisabled: boolean
private _isExpanded: boolean
private _isRendered = false

get isRendered(): boolean {
return this._isRendered
}

get isExpanded(): boolean {
return this._isExpanded
}

get isDisabled(): boolean {
return this._isDisabled
Expand Down Expand Up @@ -88,14 +98,17 @@ export class TreeNode implements TreeNodePublicProp {
isLeaf = false,
isChecked = false,
isStrictly = false,
isDisabled = false
isDisabled = false,
isExpanded = false
} = {}
) {
this.id = id ?? idSeed++
this.label = label
this._isLeaf = isLeaf
this._isStrictly = isStrictly
this._isDisabled = isDisabled
this._isExpanded = isExpanded

this.setChecked(isChecked)

this.appendChild(...children)
Expand Down Expand Up @@ -206,4 +219,26 @@ export class TreeNode implements TreeNodePublicProp {
dfs(this, 1)
isFunction(downToUpCallBack) && downToUpCallBack(this, this.parent, 0)
}

expand(v = !this._isExpanded, isAutoExpandParent = false): void {
if (this.isLeaf) {
return
}
this._isExpanded = v
if (v) {
this._isRendered = true
}
if (isAutoExpandParent) {
this.parent?.expand(true, true)
}
}

collapse(v = !this._isExpanded): void {
const parent = this.parent
if (!parent) {
return
}
parent.children.forEach((node) => node.expand(false))
this.expand(v)
}
}
79 changes: 72 additions & 7 deletions packages/element3/src/components/Tree/tests/TreeMain.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ describe('TreeMain.vue', () => {
]
const wrapper = mount(TreeMain, {
props: {
modelValue: rawNodes
modelValue: rawNodes,
renderAfterExpand: false
}
})

Expand All @@ -36,7 +37,8 @@ describe('TreeMain.vue', () => {
const rawNodes = []
const wrapper = mount(TreeMain, {
props: {
modelValue: rawNodes
modelValue: rawNodes,
renderAfterExpand: false
}
})

Expand All @@ -45,7 +47,7 @@ describe('TreeMain.vue', () => {
it('reactive tree data', async () => {
const wrapper = mount({
template: `
<el-Tree-main v-model="nodes"></el-Tree-main>
<el-Tree-main v-model="nodes" :renderAfterExpand="false"></el-Tree-main>
`,
components: { elTreeMain: TreeMain },
setup() {
Expand Down Expand Up @@ -90,7 +92,7 @@ describe('TreeMain.vue', () => {
it('reactive tree data(OptionsAPI)', async () => {
const wrapper = mount({
template: `
<el-Tree-main v-model="nodes"></el-Tree-main>
<el-Tree-main v-model="nodes" :renderAfterExpand="false"></el-Tree-main>
`,
components: { elTreeMain: TreeMain },
data() {
Expand Down Expand Up @@ -129,7 +131,7 @@ describe('TreeMain.vue', () => {
it('Realize node multi - selection function', async () => {
const wrapper = mount({
template: `
<el-Tree-main v-model="nodes" v-model:checked="checked" show-checkbox></el-Tree-main>
<el-Tree-main v-model="nodes" v-model:checked="checked" show-checkbox :renderAfterExpand="false"></el-Tree-main>
`,
components: { elTreeMain: TreeMain },
setup() {
Expand Down Expand Up @@ -173,7 +175,7 @@ describe('TreeMain.vue', () => {
it('Based on the check-on-click-node implementation, whether the node is selected when the node is clicked', async () => {
const wrapper = mount({
template: `
<el-tree-main v-model="nodes" v-model:checked="checked" show-checkbox check-on-click-node></el-tree-main>
<el-tree-main v-model="nodes" v-model:checked="checked" show-checkbox check-on-click-node :renderAfterExpand="false"></el-tree-main>
`,
components: { elTreeMain: TreeMain },
setup() {
Expand Down Expand Up @@ -206,7 +208,7 @@ describe('TreeMain.vue', () => {
it('Implement, in the case of displaying checkboxes, whether to strictly follow the parent-child discordant practice', async () => {
const wrapper = mount({
template: `
<el-tree-main v-model="nodes" v-model:checked="checked" show-checkbox check-strictly></el-tree-main>
<el-tree-main v-model="nodes" v-model:checked="checked" show-checkbox check-strictly :renderAfterExpand="false"></el-tree-main>
`,
components: { elTreeMain: TreeMain },
setup() {
Expand Down Expand Up @@ -237,4 +239,67 @@ describe('TreeMain.vue', () => {
await node2.trigger('click')
expect(wrapper.vm.checked).toEqual([2])
})

it('expand a node', async () => {
const rawNodes = [
{
id: 1,
label: 'Node1',
children: [
{
id: 11,
label: 'Node1-1'
}
]
}
]
const wrapper = mount(TreeMain, {
props: {
modelValue: rawNodes,
renderAfterExpand: false
}
})
await wrapper.find('#TreeNode1').trigger('click')
expect(wrapper.find('#TreeNode1').classes()).toContain('is-expanded')
})

it('expand a node and vModel expanded', async () => {
const rawNodes = [
{
id: 1,
label: 'Node1',
children: [
{
id: 11,
label: 'Node1-1'
}
]
},
{
id: 2,
label: 'Node2',
children: [
{
id: 21,
label: 'Node2-1'
}
]
}
]
const expanded = ref([1])
const wrapper = mount(TreeMain, {
props: {
modelValue: rawNodes,
renderAfterExpand: false,
expanded: expanded,
'onUpdate:expanded'(v) {
expanded.value = v
}
}
})
await nextTick()
await wrapper.find('#TreeNode2').trigger('click')
expect(wrapper.find('#TreeNode1').classes()).toContain('is-expanded')
expect(expanded.value).toEqual([1, 2])
})
})
Loading

0 comments on commit 6bd8c71

Please sign in to comment.