常见问题
前言
算是 Vue/Router 基础知识了, 但是很多人不知道
添加页面
添加页面必须使用单标签, 由于使用了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
属性来指定浮层的渲染位置
解决
vue
<template>
<Select :getPopupContainer="getPopupContainer" />
</template>
<script lang="ts" setup>
// 挂载到父节点
import { getPopupContainer } from "@/utils";
</script>
官方: 注意,如果发现下拉菜单跟随页面滚动,或者需要在其他弹层中触发 Select,请尝试使用 getPopupContainer={triggerNode => triggerNode.parentNode} 将下拉弹层渲染节点固定在触发器的父元素中。