mirror of
https://gitee.com/element-plus/element-plus.git
synced 2024-12-04 20:27:44 +08:00
refactor(components): [tabs] simplify logic with hooks (#10224)
This commit is contained in:
parent
bfb8e26ed8
commit
af874ea93e
@ -341,6 +341,45 @@ describe('Tabs.vue', () => {
|
||||
expect(panesWrapper.length).toEqual(2)
|
||||
})
|
||||
|
||||
test('tab order', async () => {
|
||||
const editableTabs = ref([
|
||||
{
|
||||
title: 'Tab 1',
|
||||
name: '1',
|
||||
content: 'Tab 1 content',
|
||||
},
|
||||
{
|
||||
title: 'Tab 2',
|
||||
name: '2',
|
||||
content: 'Tab 2 content',
|
||||
},
|
||||
])
|
||||
|
||||
const wrapper = mount(() => (
|
||||
<Tabs ref="tabs" type="card">
|
||||
{editableTabs.value.map((item) => (
|
||||
<TabPane
|
||||
label={item.title}
|
||||
key={item.name}
|
||||
name={item.name}
|
||||
></TabPane>
|
||||
))}
|
||||
</Tabs>
|
||||
))
|
||||
|
||||
editableTabs.value.splice(1, 0, {
|
||||
title: 'Tab 3',
|
||||
name: '3',
|
||||
content: 'Tab 3 content',
|
||||
})
|
||||
await nextTick()
|
||||
|
||||
const items = wrapper.findAll('.el-tabs__item')
|
||||
editableTabs.value.forEach((tab, index) => {
|
||||
expect(items[index].element.textContent).toEqual(tab.title)
|
||||
})
|
||||
})
|
||||
|
||||
test('closable in tab-pane', async () => {
|
||||
const wrapper = mount(() => (
|
||||
<Tabs type="card" ref="tabs">
|
||||
|
@ -6,8 +6,6 @@ import {
|
||||
provide,
|
||||
ref,
|
||||
renderSlot,
|
||||
shallowReactive,
|
||||
shallowRef,
|
||||
watch,
|
||||
} from 'vue'
|
||||
import {
|
||||
@ -21,9 +19,12 @@ import { EVENT_CODE, UPDATE_MODEL_EVENT } from '@element-plus/constants'
|
||||
import ElIcon from '@element-plus/components/icon'
|
||||
import { Plus } from '@element-plus/icons-vue'
|
||||
import { tabsRootContextKey } from '@element-plus/tokens'
|
||||
import { useDeprecated, useNamespace } from '@element-plus/hooks'
|
||||
import {
|
||||
useDeprecated,
|
||||
useNamespace,
|
||||
useOrderedChildren,
|
||||
} from '@element-plus/hooks'
|
||||
import TabNav from './tab-nav'
|
||||
import { getOrderedPanes } from './utils/pane'
|
||||
|
||||
import type { TabNavInstance } from './tab-nav'
|
||||
import type { TabsPaneContext } from '@element-plus/tokens'
|
||||
@ -85,13 +86,15 @@ export default defineComponent({
|
||||
emits: tabsEmits,
|
||||
|
||||
setup(props, { emit, slots, expose }) {
|
||||
const vm = getCurrentInstance()!
|
||||
|
||||
const ns = useNamespace('tabs')
|
||||
|
||||
const {
|
||||
children: panes,
|
||||
addChild: registerPane,
|
||||
removeChild: unregisterPane,
|
||||
} = useOrderedChildren<TabsPaneContext>(getCurrentInstance()!, 'ElTabPane')
|
||||
|
||||
const nav$ = ref<TabNavInstance>()
|
||||
const panes = shallowReactive<TabsPanes>({})
|
||||
const orderedPanes = shallowRef<TabsPaneContext[]>([])
|
||||
const currentName = ref<TabPaneName>(
|
||||
props.modelValue ?? props.activeName ?? '0'
|
||||
)
|
||||
@ -171,24 +174,12 @@ export default defineComponent({
|
||||
nav$.value?.scrollToActiveTab()
|
||||
})
|
||||
|
||||
{
|
||||
const registerPane = (pane: TabsPaneContext) => {
|
||||
panes[pane.uid] = pane
|
||||
orderedPanes.value = getOrderedPanes(vm, panes)
|
||||
}
|
||||
|
||||
const unregisterPane = (uid: number) => {
|
||||
delete panes[uid]
|
||||
orderedPanes.value = getOrderedPanes(vm, panes)
|
||||
}
|
||||
|
||||
provide(tabsRootContextKey, {
|
||||
props,
|
||||
currentName,
|
||||
registerPane,
|
||||
unregisterPane,
|
||||
})
|
||||
}
|
||||
provide(tabsRootContextKey, {
|
||||
props,
|
||||
currentName,
|
||||
registerPane,
|
||||
unregisterPane,
|
||||
})
|
||||
|
||||
expose({
|
||||
currentName,
|
||||
@ -219,7 +210,7 @@ export default defineComponent({
|
||||
currentName={currentName.value}
|
||||
editable={props.editable}
|
||||
type={props.type}
|
||||
panes={orderedPanes.value}
|
||||
panes={panes.value}
|
||||
stretch={props.stretch}
|
||||
onTabClick={handleTabClick}
|
||||
onTabRemove={handleTabRemove}
|
||||
|
@ -1,20 +0,0 @@
|
||||
import { flattedChildren, isVNode } from '@element-plus/utils'
|
||||
import type { ComponentInternalInstance, VNode } from 'vue'
|
||||
import type { TabsPanes } from '../tabs'
|
||||
|
||||
export const getTabPanes = (vm: ComponentInternalInstance) => {
|
||||
const nodes = flattedChildren(vm.subTree)
|
||||
return nodes.filter(
|
||||
(n): n is VNode =>
|
||||
isVNode(n) && (n.type as any)?.name === 'ElTabPane' && !!n.component
|
||||
)
|
||||
}
|
||||
|
||||
export const getOrderedPanes = (
|
||||
vm: ComponentInternalInstance,
|
||||
panes: TabsPanes
|
||||
) => {
|
||||
const nodes = getTabPanes(vm)
|
||||
const uids = nodes.map((n) => n.component!.uid)
|
||||
return uids.map((uid) => panes[uid]).filter((p) => !!p)
|
||||
}
|
Loading…
Reference in New Issue
Block a user