Skip to content

常见问题

前言

算是 Vue/Router 基础知识了, 但是很多人不知道

添加页面

添加页面必须使用单标签, 由于使用了Transition来设置切换动画, 所以必须使用单标签来包裹内容

详见 Vue3 - Transition

txt
<Transition> 仅支持单个元素或组件作为其插槽内容。如果内容是一个组件,这个组件必须仅有一个根元素。

会导致: 页面白屏 路由切换白屏

例如:

vue
错误的
<template>
  <div></div>
  <div></div>
</template>

这也是错误的 没想到吧 注释也算节点
<template>
  <!-- 这也是错误的 -->
  <div></div>
</template>

组件名重复导致的 404

Vue-Router中 路由 Name 不能重复, 否则后一个会覆盖前一个导致 404 链接

txt
所有路由的命名都必须是唯一的。如果为多条路由添加相同的命名,路由器只会保留最后那一条。

默认后台生成的路由为路径首字母转大写 比如路径user 则路由名为User 如果再次添加路径user 则会覆盖导致 404

keepAlive 问题

组件名必须和路由名对应 比如上述的User 则组件名必须为User

ts
// setup语法糖
defineOption({ name: "User" });
// 非setup语法糖
export default defineComponent({
  name: "User",
});

动态组件名 (前端版本 >=1.4.0)

注意

本地路由依然要使用 defineOptions 且 name 不能重复

更改动态生成组件Name逻辑, 可不用添加defineOptions({name: 'xxx'})来定义组件名(也不会生效) 不用担心缓存问题

由于后端路由 name 使用path+id格式, 故也不会产生 404 问题

详见: src\utils\factory\createCustomNameComponent.tsx

tsx
/**
 * 后台返回的路由动态生成name 解决缓存问题
 * 感谢 @fourteendp
 * 详见 https://github.com/vbenjs/vue-vben-admin/issues/3927
 */
import { Component, defineComponent, h } from "vue";

interface Options {
  name?: string;
}

export function createCustomNameComponent(
  loader: () => Promise<Recordable>,
  options: Options = {}
): () => Promise<Component> {
  const { name } = options;
  let component: Component | null = null;

  const load = async () => {
    try {
      const { default: loadedComponent } = await loader();
      component = loadedComponent;
    } catch (error) {
      console.error(`Cannot resolve component ${name}, error:`, error);
    }
  };

  return async () => {
    if (!component) {
      await load();
    }

    return Promise.resolve(
      defineComponent({
        name,
        render() {
          return h(component as Component);
        },
      })
    );
  };
}

src\router\helper\routeHelper.ts

ts
if (matchKeys?.length === 1) {
  const matchKey = matchKeys[0];
  // 动态生成name 解决缓存问题
  return createCustomNameComponent(dynamicViewsModules[matchKey], { name });
}

Select 等有浮层组件偏移

一些有浮层的组件 比如Select PopConfirm等, 默认展示的浮层是挂载在 body 下 在有滚动条的情况下会出现偏移 不会跟随滚动条, 所以需要设置getPopupContainer属性来指定浮层的渲染位置

alt text

解决

vue
<template>
  <Select :getPopupContainer="getPopupContainer" />
</template>

<script lang="ts" setup>
// 挂载到父节点
import { getPopupContainer } from "@/utils";
</script>

官方: 注意,如果发现下拉菜单跟随页面滚动,或者需要在其他弹层中触发 Select,请尝试使用 getPopupContainer={triggerNode => triggerNode.parentNode} 将下拉弹层渲染节点固定在触发器的父元素中。