index.ts 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. import { type VNode, cloneVNode, createVNode, defineComponent, h, KeepAlive } from "vue"
  2. import { useRoute } from "vue-router"
  3. import { useTagsViewStore } from "@/store/modules/tags-view"
  4. interface CompConsumerProps {
  5. component: VNode
  6. }
  7. /** 定义 compMap 对象,用于存储路由名称和对应的组件 */
  8. const compMap = new Map<string, VNode>()
  9. /**
  10. * CompConsumer 组件
  11. * 用法:替换 <keep-alive> 标签以及内部代码,变成:<CompConsumer :component="Component" />
  12. * 优点:缓存路由时只需写路由 Name,无需再写组件 Name
  13. * 缺点:当路由表有动态路由匹配时(指向同一个组件),会出现复用组件的情况(例如修改 /info/1 时 /info/2 也会跟着改变)
  14. */
  15. export const CompConsumer = defineComponent(
  16. (props: CompConsumerProps) => {
  17. const tagsViewStore = useTagsViewStore()
  18. const route = useRoute()
  19. return () => {
  20. // 获取传入的组件
  21. const component = props.component
  22. // 判断当前是否包含 name,如果不包含 name,那就直接处理掉 name
  23. if (!route.name) return component
  24. // 获取当前组件的名称
  25. const compName = (component.type as any)?.name
  26. // 获取当前路由的名称
  27. const routeName = route.name as string
  28. let Comp: VNode
  29. // 检查 compMap 中是否已经存在对应的组件
  30. if (compMap.has(routeName)) {
  31. // 如果存在,则直接使用该组件进行渲染
  32. Comp = compMap.get(routeName)!
  33. } else {
  34. // 如果不存在,则克隆传入的组件并创建一个新的组件,将其添加到 compMap 中
  35. const node = cloneVNode(component)
  36. if (compName && compName === routeName) {
  37. ;(node.type as any).name = `__${compName}__CUSTOM_NAME`
  38. }
  39. // @ts-expect-error this is VNode
  40. Comp = defineComponent({
  41. name: routeName,
  42. setup() {
  43. return () => node
  44. }
  45. })
  46. compMap.set(routeName, Comp)
  47. }
  48. // 使用 createVNode 函数创建一个 KeepAlive 组件,并缓存 cachedViews 数组中对应的组件
  49. return createVNode(
  50. KeepAlive,
  51. {
  52. include: tagsViewStore.cachedViews
  53. },
  54. {
  55. default: () => h(Comp)
  56. }
  57. )
  58. }
  59. },
  60. {
  61. name: "CompConsumer",
  62. props: ["component"]
  63. }
  64. )