mirror of
https://github.com/element-plus/element-plus.git
synced 2024-11-21 01:02:59 +08:00
perf(components): [tabs] improve order performance
This commit is contained in:
parent
116c1daf05
commit
ab19e8f2e6
@ -30,7 +30,7 @@ import { useMenuCssVar } from './use-menu-css-var'
|
||||
|
||||
import type { MenuItemClicked, MenuProvider, SubMenuProvider } from './types'
|
||||
import type { NavigationFailure, Router } from 'vue-router'
|
||||
import type { ExtractPropTypes, VNode } from 'vue'
|
||||
import type { ExtractPropTypes, VNode, VNodeArrayChildren } from 'vue'
|
||||
import type { UseResizeObserverReturn } from '@vueuse/core'
|
||||
|
||||
export const menuProps = buildProps({
|
||||
@ -358,11 +358,11 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
return () => {
|
||||
let slot = slots.default?.() ?? []
|
||||
let slot: VNodeArrayChildren = slots.default?.() ?? []
|
||||
const vShowMore: VNode[] = []
|
||||
|
||||
if (props.mode === 'horizontal' && menu.value) {
|
||||
const originalSlot = flattedChildren(slot)
|
||||
const originalSlot = flattedChildren(slot) as VNodeArrayChildren
|
||||
const slotDefault =
|
||||
sliceIndex.value === -1
|
||||
? originalSlot
|
||||
|
@ -4,16 +4,15 @@ import {
|
||||
getCurrentInstance,
|
||||
nextTick,
|
||||
provide,
|
||||
reactive,
|
||||
ref,
|
||||
renderSlot,
|
||||
shallowReactive,
|
||||
shallowRef,
|
||||
watch,
|
||||
} from 'vue'
|
||||
import {
|
||||
buildProps,
|
||||
definePropType,
|
||||
flattedChildren,
|
||||
getFirstValidNode,
|
||||
isNumber,
|
||||
isString,
|
||||
isUndefined,
|
||||
@ -24,10 +23,11 @@ import { Plus } from '@element-plus/icons-vue'
|
||||
import { tabsRootContextKey } from '@element-plus/tokens'
|
||||
import { useDeprecated, useNamespace } 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'
|
||||
import type { ExtractPropTypes, VNode, VNodeNormalizedChildren } from 'vue'
|
||||
import type { ExtractPropTypes } from 'vue'
|
||||
import type { Awaitable } from '@element-plus/utils'
|
||||
|
||||
export type TabPanelName = string | number
|
||||
@ -79,6 +79,8 @@ export const tabsEmits = {
|
||||
}
|
||||
export type TabsEmits = typeof tabsEmits
|
||||
|
||||
export type TabsPanes = Record<number, TabsPaneContext>
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ElTabs',
|
||||
|
||||
@ -91,8 +93,8 @@ export default defineComponent({
|
||||
const ns = useNamespace('tabs')
|
||||
|
||||
const nav$ = ref<TabNavInstance>()
|
||||
const panes = reactive<Record<number, TabsPaneContext>>({})
|
||||
const orderedPanes = ref<Array<TabsPaneContext>>([])
|
||||
const panes = shallowReactive<TabsPanes>({})
|
||||
const orderedPanes = shallowRef<TabsPaneContext[]>([])
|
||||
const currentName = ref<TabPanelName>(
|
||||
props.modelValue ?? props.activeName ?? '0'
|
||||
)
|
||||
@ -172,39 +174,15 @@ export default defineComponent({
|
||||
nav$.value?.scrollToActiveTab()
|
||||
})
|
||||
|
||||
// panes-order control
|
||||
{
|
||||
const calcOrderedPanes = () => {
|
||||
const tabContentChildren = getTabContentChildren()
|
||||
orderedPanes.value = tabContentChildren.map(
|
||||
(node) => panes[node.component.uid]
|
||||
)
|
||||
}
|
||||
|
||||
const getTabContentChildren = () => {
|
||||
const node = vm.subTree
|
||||
if (Array.isArray(node?.children)) {
|
||||
const nodeTabContent = node.children.find((x) => {
|
||||
return (x as VNode)?.props?.class === ns.e('content')
|
||||
})
|
||||
const validNodeTabContent = getFirstValidNode(
|
||||
nodeTabContent as VNodeNormalizedChildren
|
||||
)
|
||||
const nodePanes = flattedChildren(
|
||||
validNodeTabContent as VNodeNormalizedChildren
|
||||
)
|
||||
return nodePanes
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
const registerPane = (pane: TabsPaneContext) => {
|
||||
panes[pane.uid] = pane
|
||||
calcOrderedPanes()
|
||||
orderedPanes.value = getOrderedPanes(vm, panes)
|
||||
}
|
||||
|
||||
const unregisterPane = (uid: number) => {
|
||||
delete panes[uid]
|
||||
calcOrderedPanes()
|
||||
orderedPanes.value = getOrderedPanes(vm, panes)
|
||||
}
|
||||
|
||||
provide(tabsRootContextKey, {
|
||||
|
20
packages/components/tabs/src/utils/pane.ts
Normal file
20
packages/components/tabs/src/utils/pane.ts
Normal file
@ -0,0 +1,20 @@
|
||||
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)
|
||||
}
|
@ -35,6 +35,12 @@ export enum PatchFlags {
|
||||
BAIL = -2,
|
||||
}
|
||||
|
||||
export type VNodeChildAtom = Exclude<VNodeChild, Array<any>>
|
||||
export type RawSlots = Exclude<
|
||||
VNodeNormalizedChildren,
|
||||
Array<any> | null | string
|
||||
>
|
||||
|
||||
export function isFragment(node: VNode): boolean
|
||||
export function isFragment(node: unknown): node is VNode
|
||||
export function isFragment(node: unknown): node is VNode {
|
||||
@ -138,11 +144,18 @@ export const ensureOnlyChild = (children: VNodeArrayChildren | undefined) => {
|
||||
return children[0]
|
||||
}
|
||||
|
||||
export const flattedChildren = (children: VNodeNormalizedChildren) => {
|
||||
export type FlattenVNodes = Array<VNodeChildAtom | RawSlots>
|
||||
|
||||
export const flattedChildren = (
|
||||
children: FlattenVNodes | VNode | VNodeNormalizedChildren
|
||||
): FlattenVNodes => {
|
||||
const vNodes = isArray(children) ? children : [children]
|
||||
const result: any[] = []
|
||||
vNodes.forEach((child: any) => {
|
||||
if (isArray(child.children)) {
|
||||
const result: FlattenVNodes = []
|
||||
|
||||
vNodes.forEach((child) => {
|
||||
if (isArray(child)) {
|
||||
result.push(...flattedChildren(child))
|
||||
} else if (isVNode(child) && isArray(child.children)) {
|
||||
result.push(...flattedChildren(child.children))
|
||||
} else {
|
||||
result.push(child)
|
||||
|
Loading…
Reference in New Issue
Block a user