12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667 |
- import { type VNode, cloneVNode, createVNode, defineComponent, h, KeepAlive } from "vue"
- import { useRoute } from "vue-router"
- import { useTagsViewStore } from "@/store/modules/tags-view"
- interface CompConsumerProps {
- component: VNode
- }
- /** 定义 compMap 对象,用于存储路由名称和对应的组件 */
- const compMap = new Map<string, VNode>()
- /**
- * CompConsumer 组件
- * 用法:替换 <keep-alive> 标签以及内部代码,变成:<CompConsumer :component="Component" />
- * 优点:缓存路由时只需写路由 Name,无需再写组件 Name
- * 缺点:当路由表有动态路由匹配时(指向同一个组件),会出现复用组件的情况(例如修改 /info/1 时 /info/2 也会跟着改变)
- */
- export const CompConsumer = defineComponent(
- (props: CompConsumerProps) => {
- const tagsViewStore = useTagsViewStore()
- const route = useRoute()
- return () => {
- // 获取传入的组件
- const component = props.component
- // 判断当前是否包含 name,如果不包含 name,那就直接处理掉 name
- if (!route.name) return component
- // 获取当前组件的名称
- const compName = (component.type as any)?.name
- // 获取当前路由的名称
- const routeName = route.name as string
- let Comp: VNode
- // 检查 compMap 中是否已经存在对应的组件
- if (compMap.has(routeName)) {
- // 如果存在,则直接使用该组件进行渲染
- Comp = compMap.get(routeName)!
- } else {
- // 如果不存在,则克隆传入的组件并创建一个新的组件,将其添加到 compMap 中
- const node = cloneVNode(component)
- if (compName && compName === routeName) {
- ;(node.type as any).name = `__${compName}__CUSTOM_NAME`
- }
- // @ts-expect-error this is VNode
- Comp = defineComponent({
- name: routeName,
- setup() {
- return () => node
- }
- })
- compMap.set(routeName, Comp)
- }
- // 使用 createVNode 函数创建一个 KeepAlive 组件,并缓存 cachedViews 数组中对应的组件
- return createVNode(
- KeepAlive,
- {
- include: tagsViewStore.cachedViews
- },
- {
- default: () => h(Comp)
- }
- )
- }
- },
- {
- name: "CompConsumer",
- props: ["component"]
- }
- )
|