mirror of
https://github.com/element-plus/element-plus.git
synced 2026-03-13 07:51:17 +08:00
fix(components): [tree] keyboard nav broken after filter/collapse (#21377)
* fix(components): [tree] keyboard nav broken after filter/collapse Fix issues #21376 * fix(components): [tree] keyboard nav broken after filter/collapse * fix(components): [tree] keyboard nav broken after filter/collapse * Update packages/components/tree/src/model/node.ts Co-authored-by: Noblet Ouways <91417411+Dsaquel@users.noreply.github.com> * Update packages/components/tree/src/model/node.ts Co-authored-by: Noblet Ouways <91417411+Dsaquel@users.noreply.github.com> * fix(components): [tree] keyboard nav broken after filter/collapse * fix(components): [tree] add test cases * fix(components): [tree] keyboard nav broken after filter/collapse * fix(components): [tree] keyboard nav broken after filter/collapse --------- Co-authored-by: Noblet Ouways <91417411+Dsaquel@users.noreply.github.com>
This commit is contained in:
@@ -1481,6 +1481,102 @@ describe('Tree.vue', () => {
|
||||
expect(flag).toBe(true)
|
||||
})
|
||||
|
||||
test('collapse and navigate down and up', async () => {
|
||||
const { wrapper } = getTreeVm(``, {
|
||||
template: `
|
||||
<div>
|
||||
<el-tree ref="tree1" :data="data" node-key="id" :props="defaultProps" default-expand-all></el-tree>
|
||||
</div>
|
||||
`,
|
||||
})
|
||||
await nextTick()
|
||||
let flag = false
|
||||
function handleFocus() {
|
||||
return () => (flag = true)
|
||||
}
|
||||
const tree = wrapper.findComponent({ name: 'ElTree' })
|
||||
const targetElement = wrapper.find('div[data-key="2"]').element
|
||||
const fromElement = wrapper.find('div[data-key="1"]')
|
||||
await fromElement.trigger('click')
|
||||
|
||||
expect(fromElement.classes('is-expanded')).toBe(false) // 判断是否已折叠
|
||||
|
||||
await nextTick()
|
||||
defineGetter(targetElement, 'focus', handleFocus)
|
||||
;(tree.vm as InstanceType<typeof Tree>).setCurrentKey(1)
|
||||
// 模拟按下下箭头键
|
||||
fromElement.element.dispatchEvent(
|
||||
new KeyboardEvent('keydown', {
|
||||
code: 'ArrowDown',
|
||||
bubbles: true,
|
||||
cancelable: false,
|
||||
})
|
||||
)
|
||||
expect(flag).toBe(true)
|
||||
|
||||
await nextTick()
|
||||
|
||||
flag = false
|
||||
defineGetter(fromElement.element, 'focus', handleFocus)
|
||||
// 模拟按下上箭头键
|
||||
targetElement.dispatchEvent(
|
||||
new KeyboardEvent('keydown', {
|
||||
code: 'ArrowUp',
|
||||
bubbles: true,
|
||||
cancelable: false,
|
||||
})
|
||||
)
|
||||
expect(flag).toBe(true)
|
||||
})
|
||||
|
||||
test('filter-node-method and navigate down', async () => {
|
||||
const { wrapper } = getTreeVm(``, {
|
||||
template: `
|
||||
<div>
|
||||
<el-tree ref="tree1" :data="data" node-key="id" :props="defaultProps" :filter-node-method="filterNode"></el-tree>
|
||||
</div>
|
||||
`,
|
||||
methods: {
|
||||
filterNode(value, data) {
|
||||
if (!value) return true
|
||||
return data.label.includes(value)
|
||||
},
|
||||
},
|
||||
})
|
||||
let flag = false
|
||||
function handleFocus() {
|
||||
return () => (flag = true)
|
||||
}
|
||||
|
||||
const treeWrapper = wrapper.findComponent(Tree)
|
||||
;(treeWrapper.vm as InstanceType<typeof Tree>).filter('-1')
|
||||
|
||||
await sleep()
|
||||
const tree = wrapper.findComponent({ name: 'ElTree' })
|
||||
;(tree.vm as InstanceType<typeof Tree>).setCurrentKey(1)
|
||||
|
||||
const allNodes = treeWrapper.findAll('.el-tree-node')
|
||||
const visibleNodes = allNodes.filter(
|
||||
(node) => !node.classes().includes('is-hidden')
|
||||
)
|
||||
const len = visibleNodes.length
|
||||
for (let i = 0; i < len; i++) {
|
||||
if (visibleNodes[i + 1]) {
|
||||
defineGetter(visibleNodes[i + 1].element, 'focus', handleFocus)
|
||||
// 模拟按下下箭头键
|
||||
visibleNodes[i].element.dispatchEvent(
|
||||
new KeyboardEvent('keydown', {
|
||||
code: 'ArrowDown',
|
||||
bubbles: true,
|
||||
cancelable: false,
|
||||
})
|
||||
)
|
||||
expect(flag).toBe(true)
|
||||
flag = false
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
test('navigate with disabled', async () => {
|
||||
const wrapper = mount({
|
||||
template: `
|
||||
|
||||
@@ -79,6 +79,13 @@ const getPropertyFromData = function (node: Node, prop: string): any {
|
||||
}
|
||||
}
|
||||
|
||||
const setCanFocus = function (childNodes: Node[], focus: boolean): void {
|
||||
childNodes.forEach((item) => {
|
||||
item.canFocus = focus
|
||||
setCanFocus(item.childNodes, focus)
|
||||
})
|
||||
}
|
||||
|
||||
let nodeIdSeed = 0
|
||||
|
||||
class Node {
|
||||
@@ -359,9 +366,7 @@ class Node {
|
||||
}
|
||||
this.expanded = true
|
||||
if (callback) callback()
|
||||
this.childNodes.forEach((item) => {
|
||||
item.canFocus = true
|
||||
})
|
||||
setCanFocus(this.childNodes, true)
|
||||
}
|
||||
|
||||
if (this.shouldLoadData()) {
|
||||
@@ -395,9 +400,7 @@ class Node {
|
||||
|
||||
collapse(): void {
|
||||
this.expanded = false
|
||||
this.childNodes.forEach((item) => {
|
||||
item.canFocus = false
|
||||
})
|
||||
setCanFocus(this.childNodes, false)
|
||||
}
|
||||
|
||||
shouldLoadData() {
|
||||
|
||||
@@ -46,8 +46,13 @@ export function useKeydown({ el$ }: UseKeydownOption, store: Ref<TreeStore>) {
|
||||
: treeItems.length - 1
|
||||
const startIndex = nextIndex
|
||||
while (true) {
|
||||
if (store.value.getNode(treeItems[nextIndex].dataset.key!).canFocus)
|
||||
const currentNode = store.value.getNode(
|
||||
treeItems[nextIndex].dataset.key!
|
||||
)
|
||||
if (currentNode.canFocus && currentNode.visible) {
|
||||
break
|
||||
}
|
||||
|
||||
nextIndex--
|
||||
if (nextIndex === startIndex) {
|
||||
nextIndex = -1
|
||||
@@ -66,8 +71,13 @@ export function useKeydown({ el$ }: UseKeydownOption, store: Ref<TreeStore>) {
|
||||
: 0
|
||||
const startIndex = nextIndex
|
||||
while (true) {
|
||||
if (store.value.getNode(treeItems[nextIndex].dataset.key!).canFocus)
|
||||
const currentNode = store.value.getNode(
|
||||
treeItems[nextIndex].dataset.key!
|
||||
)
|
||||
if (currentNode.canFocus && currentNode.visible) {
|
||||
break
|
||||
}
|
||||
|
||||
nextIndex++
|
||||
if (nextIndex === startIndex) {
|
||||
nextIndex = -1
|
||||
|
||||
Reference in New Issue
Block a user