diff --git a/docs/reference/plugin/plugins/layout.md b/docs/reference/plugin/plugins/layout.md
index 238031c1..0aa320b6 100644
--- a/docs/reference/plugin/plugins/layout.md
+++ b/docs/reference/plugin/plugins/layout.md
@@ -20,7 +20,7 @@
{
"dependencies": {
"@fesjs/fes": "^2.0.0",
- "@fesjs/plugin-layout": "^2.0.0"
+ "@fesjs/plugin-layout": "^4.0.0"
},
}
```
@@ -115,7 +115,12 @@ export default {
name: 'store'
}, {
name: 'simpleList'
- }]
+ }],
+ menuConfig: {
+ defaultExpandAll: false,
+ expandedKeys: [],
+ accordion: false
+ }
},
```
@@ -219,7 +224,19 @@ export default {
```
- **children**:子菜单配置。
+
+#### menusConfig
+- **类型**:`Object`
+- **默认值**:`{}`
+
+- **详情**:菜单的配置:
+
+ - **defaultExpandAll**:是否默认展开全部菜单。
+
+ - **expandedKeys**:配置默认展开的菜单,需要传子项是菜单路径的数组。
+
+ - **accordion**:是否只保持一个子菜单的展开。
### 运行时配置
在 `app.js` 中配置:
@@ -231,6 +248,38 @@ export const layout = {
```
+#### menus
+- **类型**:`(defaultMenus: [] )=> Ref | []`
+
+- **详情**:运行时修改菜单,入参是默认菜单配置(.fes.js中的menu配置),需要返回一个`Ref`或者数组。
+
+```js
+import { ClusterOutlined } from '@fesjs/fes-design/icon'
+export const layout = layoutConfig => ({
+ ...layoutConfig,
+ customHeader: ,
+ menus: (defaultMenuData) => {
+ const menusRef = ref(defaultMenuData);
+ watch(() => layoutConfig.initialState.userName, () => {
+ menusRef.value = [{
+ name: 'store',
+ icon:
+ }];
+ });
+ return menusRef;
+ }
+});
+
+```
+`layoutConfig.initialState` 是 `beforeRender.action`执行后创建的应用初始状态数据。
+
+如果菜单需要根据某些状态动态改变,则返回`Ref`,否则只需要返回数组。
+
+:::tip
+在运行时配置菜单中的icon,需要传组件本身,而不是组件的名称。
+:::tip
+
+
#### header
- **类型**:`String`
diff --git a/packages/fes-plugin-layout/src/index.js b/packages/fes-plugin-layout/src/index.js
index 14bafc45..a9417292 100644
--- a/packages/fes-plugin-layout/src/index.js
+++ b/packages/fes-plugin-layout/src/index.js
@@ -39,14 +39,9 @@ export default (api) => {
...(api.config.layout || {})
};
- // 路由信息
- const routes = await api.getRoutes();
- // 把路由的meta合并到menu配置中
- userConfig.menus = helper.fillMenuByRoute(userConfig.menus, routes);
+ const iconNames = helper.getIconNamesFromMenu(userConfig.menus);
- const icons = helper.getIconsFromMenu(userConfig.menus);
-
- const iconsString = icons.map(
+ const iconsString = iconNames.map(
iconName => `import { ${iconName} } from '@fesjs/fes-design/icon'`
);
api.writeTmpFile({
@@ -54,7 +49,7 @@ export default (api) => {
content: `
${iconsString.join(';\n')}
export default {
- ${icons.join(',\n')}
+ ${iconNames.join(',\n')}
}`
});
diff --git a/packages/fes-plugin-layout/src/node/helper.js b/packages/fes-plugin-layout/src/node/helper.js
index d5b83208..effedb72 100644
--- a/packages/fes-plugin-layout/src/node/helper.js
+++ b/packages/fes-plugin-layout/src/node/helper.js
@@ -1,61 +1,5 @@
-const matchName = (config, name) => {
- let res = {};
- if (Array.isArray(config)) {
- for (let i = 0; i < config.length; i++) {
- const item = config[i];
- if (item.meta && item.meta.name === name) {
- res = item.meta;
- res.path = item.path;
- break;
- }
- if (item.children && item.children.length > 0) {
- res = matchName(item.children, name);
- }
- }
- }
- return res;
-};
-
-export const fillMenuByRoute = (menuConfig, routeConfig, dep = 0) => {
- dep += 1;
- if (dep > 3) {
- console.warn('[plugin-layout]: 菜单层级最好不要超出三层!');
- }
- const arr = [];
- if (Array.isArray(menuConfig) && Array.isArray(routeConfig)) {
- menuConfig.forEach((menu) => {
- const pageConfig = {};
- if (menu.name) {
- Object.assign(pageConfig, matchName(routeConfig, menu.name));
- }
- // menu的配置优先级高,当menu存在配置时,忽略页面的配置
- Object.keys(pageConfig).forEach((prop) => {
- if (menu[prop] === undefined || menu[prop] === null || menu[prop] === '') {
- menu[prop] = pageConfig[prop];
- }
- });
- // 处理icon
- if (menu.icon) {
- const icon = menu.icon;
- const urlReg = /^((https?|ftp|file):\/\/)?([\da-z.-]+)\.([a-z.]{2,6})([/\w .-]*)*\/?$/;
- if (typeof icon === 'string' && !((urlReg.test(icon) || icon.includes('.svg')))) {
- menu.icon = {
- type: 'icon',
- name: icon
- };
- }
- }
- if (menu.children && menu.children.length > 0) {
- menu.children = fillMenuByRoute(menu.children, routeConfig, dep);
- }
- arr.push(menu);
- });
- }
- return arr;
-};
-
-export function getIconsFromMenu(data) {
+export function getIconNamesFromMenu(data) {
if (!Array.isArray(data)) {
return [];
}
@@ -63,12 +7,19 @@ export function getIconsFromMenu(data) {
data.forEach((item = { path: '/' }) => {
if (item.icon) {
const { icon } = item;
- if (icon.type === 'icon') {
- icons.push(icon.name);
+ // 处理icon
+ if (icon) {
+ const urlReg = /^((https?|ftp|file):\/\/)?([\da-z.-]+)\.([a-z.]{2,6})([/\w .-]*)*\/?$/;
+ if (
+ typeof icon === 'string'
+ && !(urlReg.test(icon) || icon.includes('.svg'))
+ ) {
+ icons.push(icon);
+ }
}
}
if (item.children) {
- icons = icons.concat(getIconsFromMenu(item.children));
+ icons = icons.concat(getIconNamesFromMenu(item.children));
}
});
diff --git a/packages/fes-plugin-layout/src/runtime/helpers/fillMenu.js b/packages/fes-plugin-layout/src/runtime/helpers/fillMenu.js
new file mode 100644
index 00000000..cbf7da55
--- /dev/null
+++ b/packages/fes-plugin-layout/src/runtime/helpers/fillMenu.js
@@ -0,0 +1,60 @@
+const getMetaByName = (config, name) => {
+ let res = {};
+ if (Array.isArray(config)) {
+ for (let i = 0; i < config.length; i++) {
+ const item = config[i];
+ if (item.meta && item.meta.name === name) {
+ res = item.meta;
+ res.path = item.path;
+ break;
+ }
+ if (item.children && item.children.length > 0) {
+ res = getMetaByName(item.children, name);
+ if (res.path) {
+ break;
+ }
+ }
+ }
+ }
+ return res;
+};
+
+const fillMenuByRoute = (menuConfig, routeConfig, dep = 0) => {
+ dep += 1;
+ if (dep > 3) {
+ console.warn('[plugin-layout]: 菜单层级最好不要超出三层!');
+ }
+ const arr = [];
+ if (Array.isArray(menuConfig) && Array.isArray(routeConfig)) {
+ menuConfig.forEach((menu) => {
+ const pageConfig = {};
+ if (menu.name) {
+ Object.assign(
+ pageConfig,
+ getMetaByName(routeConfig, menu.name)
+ );
+ }
+ // menu的配置优先级高,当menu存在配置时,忽略页面的配置
+ Object.keys(pageConfig).forEach((prop) => {
+ if (
+ menu[prop] === undefined
+ || menu[prop] === null
+ || menu[prop] === ''
+ ) {
+ menu[prop] = pageConfig[prop];
+ }
+ });
+ if (menu.children && menu.children.length > 0) {
+ menu.children = fillMenuByRoute(
+ menu.children,
+ routeConfig,
+ dep
+ );
+ }
+ arr.push(menu);
+ });
+ }
+ return arr;
+};
+
+export default fillMenuByRoute;
diff --git a/packages/fes-plugin-layout/src/runtime/helpers/getRuntimeConfig.js b/packages/fes-plugin-layout/src/runtime/helpers/getRuntimeConfig.js
new file mode 100644
index 00000000..c44b2797
--- /dev/null
+++ b/packages/fes-plugin-layout/src/runtime/helpers/getRuntimeConfig.js
@@ -0,0 +1,22 @@
+
+
+import { plugin, ApplyPluginsType } from '@@/core/coreExports';
+import { inject } from 'vue';
+
+let runtimeConfig;
+
+export default () => {
+ if (!runtimeConfig) {
+ runtimeConfig = plugin.applyPlugins({
+ key: 'layout',
+ type: ApplyPluginsType.modify,
+ initialValue: {
+ initialState: inject('initialState'),
+ sidebar: true,
+ header: true,
+ logo: true
+ }
+ });
+ }
+ return runtimeConfig;
+};
diff --git a/packages/fes-plugin-layout/src/runtime/index.tpl b/packages/fes-plugin-layout/src/runtime/index.tpl
index 3ffef152..683b9015 100644
--- a/packages/fes-plugin-layout/src/runtime/index.tpl
+++ b/packages/fes-plugin-layout/src/runtime/index.tpl
@@ -1,17 +1,25 @@
-import { reactive, defineComponent } from "vue";
-import { plugin, ApplyPluginsType } from "@@/core/coreExports";
-import BaseLayout from "./views/BaseLayout.vue";
+import { ref, defineComponent, computed } from 'vue';
+import { plugin, ApplyPluginsType, getRoutes } from '@@/core/coreExports';
+import BaseLayout from './views/BaseLayout.vue';
+import getRuntimeConfig from './helpers/getRuntimeConfig';
+import fillMenu from './helpers/fillMenu';
const Layout = defineComponent({
name: 'Layout',
- setup(){
- const userConfig = reactive({{{REPLACE_USER_CONFIG}}});
- const runtimeConfig = plugin.applyPlugins({
- key: "layout",
- type: ApplyPluginsType.modify,
- initialValue: {},
+ setup() {
+ const userConfig = {{{REPLACE_USER_CONFIG}}};
+ const runtimeConfig = getRuntimeConfig();
+ let menusRef = ref(userConfig.menus);
+ // 如果运行时配置了menus,则需要处理
+ if (runtimeConfig.menus && typeof runtimeConfig.menus === 'function') {
+ menusRef = ref(runtimeConfig.menus(userConfig.menus));
+ }
+ // 把路由的meta合并到menu配置中
+ const filledMenuRef = computed(() => {
+ return fillMenu(menusRef.value, getRoutes());
});
- const localeShared = plugin.getShared("locale");
+
+ const localeShared = plugin.getShared('locale');
return () => {
const slots = {
customHeader: () => {
@@ -24,14 +32,23 @@ const Layout = defineComponent({
},
locale: () => {
if (localeShared) {
- return ;
+ return (
+
+ );
}
return null;
- },
+ }
};
- return ;
+ return (
+
+ );
};
}
-})
+});
export default Layout;
diff --git a/packages/fes-plugin-layout/src/runtime/runtime.js b/packages/fes-plugin-layout/src/runtime/runtime.js
index c676984f..4eb3273f 100644
--- a/packages/fes-plugin-layout/src/runtime/runtime.js
+++ b/packages/fes-plugin-layout/src/runtime/runtime.js
@@ -1,8 +1,8 @@
-import { plugin, ApplyPluginsType } from '@@/core/coreExports';
// eslint-disable-next-line import/extensions
import { access as accessApi } from '../plugin-access/core';
import Exception404 from './views/404';
import Exception403 from './views/403';
+import getRuntimeConfig from './helpers/getRuntimeConfig';
if (!accessApi) {
throw new Error(
@@ -30,11 +30,7 @@ export const access = memo => ({
unAccessHandler({
router, to, from, next
}) {
- const runtimeConfig = plugin.applyPlugins({
- key: 'layout',
- type: ApplyPluginsType.modify,
- initialValue: {}
- });
+ const runtimeConfig = getRuntimeConfig();
if (runtimeConfig.unAccessHandler && typeof runtimeConfig.unAccessHandler === 'function') {
return runtimeConfig.unAccessHandler({
router, to, from, next
@@ -50,11 +46,7 @@ export const access = memo => ({
noFoundHandler({
router, to, from, next
}) {
- const runtimeConfig = plugin.applyPlugins({
- key: 'layout',
- type: ApplyPluginsType.modify,
- initialValue: {}
- });
+ const runtimeConfig = getRuntimeConfig();
if (runtimeConfig.noFoundHandler && typeof runtimeConfig.noFoundHandler === 'function') {
return runtimeConfig.noFoundHandler({
router, to, from, next
diff --git a/packages/fes-plugin-layout/src/runtime/views/BaseLayout.vue b/packages/fes-plugin-layout/src/runtime/views/BaseLayout.vue
index 83065240..f10a353b 100644
--- a/packages/fes-plugin-layout/src/runtime/views/BaseLayout.vue
+++ b/packages/fes-plugin-layout/src/runtime/views/BaseLayout.vue
@@ -20,6 +20,9 @@
:collapsed="collapsedRef"
mode="vertical"
:inverted="theme === 'dark'"
+ :expandedKeys="menuConfig?.expandedKeys"
+ :defaultExpandAll="menuConfig?.defaultExpandAll"
+ :accordion="menuConfig?.accordion"
/>