@fesjs/plugin-layout
介绍
为了进一步降低研发成本,我们将布局利用 fes.js
插件的方式内置,只需通过简单的配置即可拥有布局,包括导航以及侧边栏。从而做到用户无需关心布局。
- 侧边栏菜单数据根据路由中的配置自动生成。
- 布局,提供
side
、top
、mixin
、left-right
、top-left-right
五种布局。 - 主题,提供
light
、dark
两种主题。 - 默认实现对路由的 404、403 处理。
- 搭配 @fesjs/plugin-access 插件使用,可以完成对路由的权限控制。
- 搭配 @fesjs/plugin-locale 插件使用,提供切换语言的能力。
- 支持自定义头部或者侧边栏区域。
- 菜单支持配置 icon。
- 菜单标题支持国际化。
- 可配置页面是否需要 layout。
启用方式
在 package.json
中引入依赖:
{
"dependencies": {
"@fesjs/fes": "^3.0.0",
"@fesjs/plugin-layout": "^5.0.0"
}
}
布局类型
配置参数是 navigation
, 布局有五种类型 side
、mixin
、top
、left-right
、top-left-right
, 默认是 side
。
side
top
mixin
left-right
页面个性化
可以为页面单独设置布局类型:
import { defineRouteMeta } from '@fesjs/fes';
defineRouteMeta({
layout: {
navigation: null,
},
});
当设置为 null
时,页面不使用布局。
页面缓存
支持配置页面缓存,通过定义路由元信息开启缓存:
import { defineRouteMeta } from '@fesjs/fes';
defineRouteMeta({
'keep-alive': true,
});
处理嵌套路由
Fes.js 里约定目录下有 layout.vue
时会生成嵌套路由,以 layout.vue
为该目录的公共父组件,layout.vue 中必须实现 <RouterView/>
。如果嵌套路由下的页面设置了 keep-alive
,则需要用 <Page/>
替换 <RouterView/>
,<Page/>
实现了页面缓存。
<template>
<Page />
</template>
<script>
import { Page } from '@fesjs/fes';
export default {
components: {
Page,
},
};
</script>
配置
编译时配置方式
在 .fes.js
中配置:
export default {
layout: {
// 标题
title: 'Fes.js',
// 底部文字
footer: 'Created by MumbleFE',
// 主题light
theme: 'dark',
menus: [{
name: 'index'
}, {
name: 'onepiece'
}, {
name: 'store'
}, {
name: 'simpleList'
}],
// 403 页面配置
403: {
title: '没有访问权限,请联系管理人员',
},
// 404 页面配置
404: {
title: '哎呀!这个页面找不到了',
}
},
};
运行时配置方式
在 app.js
中配置:
import UserCenter from '@/components/UserCenter';
export const layout = {
renderCustom: () => <UserCenter />,
menus: [
{
name: 'index',
},
],
};
在fes.js
中,运行时配置有定义对象和函数两种方式,当使用函数配置layout
时,layoutConfig
是编译时配置结果,initialState
是 beforeRender.action
执行后创建的应用初始状态数据。 。
export function layout(layoutConfig, { initialState }) {
return {
renderCustom: () => <UserCenter />,
menus: () => {
const menusRef = ref(layoutConfig.menus);
watch(
() => initialState.userName,
() => {
menusRef.value = [
{
name: 'store',
},
];
},
);
return menusRef;
},
};
}
最终配置结果是运行时配置跟编译时配置合并的结果,运行时配置优先于编译时配置。
实际上运行配置能做的事情更多,推荐用运行时配置方式。
footer
类型:
String
默认值:
null
详情:页面底部的文字。
theme
类型:
String
默认值:
dark
详情:主题,可选有
dark
、light
navigation
类型:
String
默认值:
side
详情:页面布局类型,可选有
side
、top
、mixin
navigationOnError
类型:
String
、Function
详情:指定
403
、404
时,页面的布局类型。值同navigation
。也支持函数返回。
isFixedHeader
类型:
Boolean
默认值:
false
详情:是否固定头部,不跟随页面滚动。
isFixedSidebar
类型:
Boolean
默认值:
true
详情:是否固定 sidebar,不跟随页面滚动。
title
类型:
String
默认值:默认为 编译时配置 title
详情:产品名,当配置为"$"开头时,开启国际化,使用
$
后面的内容去匹配语言设置。
logo
类型:
String
默认值:默认提供
fes.js
的 Logo详情:Logo 的链接,例如在 public/logo.png 放了一个 logo,可以这么配置(BASE_URL 来自这里)
export const layout = {
logo: `${process.env.BASE_URL}logo.png`,
};
multiTabs
类型:
boolean
默认值:
false
详情:是否开启多页。可通过 tabReload: false 控制标签页是否重新加载。
menus
类型:
[] | () => Ref<[]> | () => []
默认值:
[]
详情:菜单配置
子项具体配置如下:
name:菜单的名称。通过匹配
name
和路由元信息 meta 中的name
,把菜单和路由关联起来, 然后使用路由元信息补充菜单配置,比如title
、path
等。path:菜单的路径,可配置第三方地址。
query:同 vue-router 的 query 参数。
params:同 vue-router 的 params 参数。
match (v4.0.0+):额外匹配的路径,当前路由命中匹配规则时,此菜单高亮。
``` { path: '/product', match: ['/product/*', '/product/create'] } ```
title:菜单的标题。
如果同时使用国际化插件,而且
title
的值以$
开头,则使用$
后面的内容去匹配语言设置。title 支持配置函数,对应 Fes Design 中 Menu 组件的
label
插槽。仅在运行时配置中支持。
icon: 菜单的图标,只一级标题展示图标。
图标使用fes-design icon,编译时配置使用组件名称,我们会自动引入组件。
图标使用本地或者远程 svg 图片。
```js { icon: '/wine-outline.svg'; } ```
children:子菜单配置。
_blank:是否在新的窗口打开页面,默认 http 开头的链接在新窗口打开
TIP
函数类型仅在运行时可用,可以实现动态变更菜单。
menuProps
类型:
Object
默认值:
{}
详情:菜单的配置:
defaultExpandAll:是否默认展开全部菜单。
expandedKeys:配置默认展开的菜单,需要传子项是菜单路径的数组。
accordion:是否只保持一个子菜单的展开。
sideWidth
类型:
Number
默认值:
200
详情:sidebar 的宽度
renderCustom
类型:
()=> VNodes
默认值:
null
详情: 自定义区域内容,仅运行时。
unAccessHandler
类型:
({ to, from, next})=> void
默认值:
null
详情:仅运行时,当进入某个路由时,如果路由对应的页面不属于可见资源列表,则会暂停进入,调用
unAccessHandler
函数。参数
- router:createRouter 创建的路由实例
- to: 准备进入的路由
- from:离开的路由
- next: next 函数
比如:
export const layout = {
unAccessHandler({ to, next }) {
const accesssIds = accessApi.getAccess();
if (to.path === '/404') {
accessApi.setAccess(accesssIds.concat(['/404']));
return next('/404');
}
if (!accesssIds.includes('/403')) {
accessApi.setAccess(accesssIds.concat(['/403']));
}
next('/403');
},
};
noFoundHandler
类型:
({ to, from, next})=> void
默认值:
null
详情:仅运行时,当进入某个路由时,如果路由对应的页面不存在,则会调用
noFoundHandler
函数。参数
- router:createRouter 创建的路由实例
- to: 准备进入的路由
- from:离开的路由
- next: next 函数
比如:
export const layout = {
noFoundHandler({ next }) {
const accesssIds = accessApi.getAccess();
if (!accesssIds.includes('/404')) {
accessApi.setAccess(accesssIds.concat(['/404']));
}
next('/404');
},
};
API
useTabTitle(建议使用useLayout)
类型定义如下:
function useTabTitle(title: string | Ref<string>): void;
当使用多页签模式时,在页面中使用 useTabTitle
可以自定义页面标签:
<script setup>
import { useRoute, useTabTitle } from '@fesjs/fes';
const titleRef = useTabTitle(`详情-${route.params?.id}`);
// 如果要更新
titleRef.value = 'changed';
</script>
useLayout
类型定义如下:
function useLayout(options: { title?: string }): { title: Ref<string>; reloadTab: () => void; closeTab: () => void };
- title: 更新当前页签的标题
- reloadTab:重载当前页签
- closeTab:关闭当前页签
4.x 升级到 5.x
- 个性化 layout 配置改为使用传入 navigation
- customHeader 改为 renderCustom
- fixedHeader 改为 isFixedHeader
- menusConfig 改为 menuProps
- fixedSideBar 改为 isFixedSidebar
- 去掉运行时 logo、header、sidebar 三个区域显示配置,请改为使用 navigation: left-right