From 2d360f392e8fc3ba215f0dc5d19b96d325d97b79 Mon Sep 17 00:00:00 2001 From: ray_wuhao <443547225@qq.com> Date: Fri, 7 Apr 2023 13:44:32 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A1=A5=E5=85=85=E9=83=A8=E5=88=86=E6=B3=A8?= =?UTF-8?q?=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/RayChart/index.tsx | 26 +++++++++++++++++++++++- src/store/modules/menu/helper.ts | 17 ++++++++++++++++ src/store/modules/menu/index.ts | 33 ++++++++++++++++++++----------- 3 files changed, 64 insertions(+), 12 deletions(-) diff --git a/src/components/RayChart/index.tsx b/src/components/RayChart/index.tsx index e9495835..92e49292 100644 --- a/src/components/RayChart/index.tsx +++ b/src/components/RayChart/index.tsx @@ -288,16 +288,21 @@ const RayChart = defineComponent({ * 直接使用响应式代理实例会出现诡异的问题, 例如 `legend` 点击时报错 */ const renderChart = (theme: ChartTheme) => { + /** 获取 dom 容器 */ const element = rayChartRef.value as HTMLElement + /** 获取配置项 */ const options = useMergeOptions() + /** 获取 dom 容器实际宽高 */ const { height, width } = element.getBoundingClientRect() + /** 如果高度为 0, 则以 200px 填充 */ if (height === 0) { addStyle(element, { height: '200px', }) } + /** 如果款度为 0, 则以 200px 填充 */ if (width === 0) { addStyle(element, { width: '200px', @@ -305,13 +310,17 @@ const RayChart = defineComponent({ } try { + /** 注册 chart */ echartInstance = echarts.init(element, theme) echartInstanceRef.value = echartInstance + /** 设置 options 配置项 */ options && echartInstance.setOption(options) + /** 渲染成功回调 */ props.success?.(echartInstance) } catch (e) { + /** 渲染失败回调 */ props.error?.() console.error(e) @@ -321,7 +330,6 @@ const RayChart = defineComponent({ /** * * @param bool 渲染带有主题色的可视化图 - * @returns void 0 * * 区别自动跟随模板主题切换与指定主题切换 */ @@ -348,15 +356,23 @@ const RayChart = defineComponent({ } } + /** 重置 echarts 尺寸 */ const resizeChart = () => { if (echartInstance) { echartInstance.resize() } } + /** 监听全局主题变化, 然后重新渲染对应主题 echarts */ watch( () => [themeValue.value], ([theme]) => { + /** + * + * Q: 为什么需要重新卸载再渲染 + * A: 因为 echarts 官方文档并未提供动态渲染方法 + * A: 虽然原型上有 setTheme 方法, 但是官方标记是仅限于在类 ECharts 中访问 + */ if (props.autoChangeTheme) { destroyChart() @@ -384,29 +400,35 @@ const RayChart = defineComponent({ }, ) + /** 监听 options 变化 */ if (props.watchOptions) { watch( () => props.watchOptions, () => { + /** 重新组合 options */ const options = useMergeOptions() + /** 如果 options 发生变动更新 echarts */ echartInstance?.setOption(options) }, ) } onBeforeMount(async () => { + /** 注册 echarts 组件与渲染器 */ await registerChartCore() }) onMounted(() => { nextTick(() => { + /** 注册 echarts */ if (props.autoChangeTheme) { renderThemeChart(themeValue.value) } else { props.theme ? renderChart('dark') : renderChart('') } + /** 注册事件 */ if (props.autoResize) { resizeDebounce = debounce(resizeChart, 500) @@ -416,7 +438,9 @@ const RayChart = defineComponent({ }) onBeforeUnmount(() => { + /** 卸载 echarts */ destroyChart() + /** 卸载事件柄 */ off(window, 'resize', resizeDebounce) }) diff --git a/src/store/modules/menu/helper.ts b/src/store/modules/menu/helper.ts index 3b1500bf..9f5505fc 100644 --- a/src/store/modules/menu/helper.ts +++ b/src/store/modules/menu/helper.ts @@ -110,3 +110,20 @@ export const matchMenuOption = ( } } } + +/** + * + * @param option menu option + * + * @remark 动态修改浏览器标题 + * @remark 会自动拼接 sideBarLogo.title + */ +export const updateDocumentTitle = (option: IMenuOptions) => { + const { breadcrumbLabel } = option + const { + layout: { sideBarLogo }, + } = __APP_CFG__ + const spliceTitle = sideBarLogo ? sideBarLogo.title : '' + + document.title = breadcrumbLabel + ' - ' + spliceTitle +} diff --git a/src/store/modules/menu/index.ts b/src/store/modules/menu/index.ts index 2106fab7..0e559aaf 100644 --- a/src/store/modules/menu/index.ts +++ b/src/store/modules/menu/index.ts @@ -16,6 +16,10 @@ * 说明: * - BreadcrumbMenu、TagMenu、Menu 统一管理 * - BreadcrumbMenu、TagMenu、Menu 属性值重度依赖 vue-router routers, 所以需要按照该项目约定方法进行配置 + * + * 缓存(sessionStorage): + * - breadcrumbOptions + * - menuKey */ import { NEllipsis } from 'naive-ui' @@ -23,7 +27,7 @@ import RayIcon from '@/components/RayIcon/index' import { getCache, setCache } from '@/utils/cache' import { validRole } from '@/router/basic' -import { parse, matchMenuOption } from './helper' +import { parse, matchMenuOption, updateDocumentTitle } from './helper' import type { MenuOption } from 'naive-ui' import type { RouteMeta } from 'vue-router' @@ -87,21 +91,26 @@ export const useMenu = defineStore( menuState.menuKey, menuState.menuTagOptions, ) + updateDocumentTitle(item as unknown as IMenuOptions) menuState.breadcrumbOptions = parse(menuState.options, 'key', key) // 获取面包屑 + /** 是否为根路由 */ if (key[0] !== '/') { + /** 如果不是根路由, 则拼接完整路由并跳转 */ const path = getCompleteRoutePath(menuState.options, key) .map((curr) => curr.key) .join('/') router.push(path) } else { + /** 根路由直接跳转 */ router.push(item.path as string) } menuState.menuKey = key + /** 缓存菜单 key(sessionStorage) */ setCache('menuKey', key) } } @@ -111,7 +120,8 @@ export const useMenu = defineStore( * * @param path 路由地址 * - * 监听路由地址变化更新菜单状态 + * @remark 监听路由地址变化更新菜单状态 + * @remark 递归查找匹配项 */ const updateMenuKeyWhenRouteUpdate = (path: string) => { const matchMenuItem = (options: MenuOption[]) => { @@ -141,16 +151,11 @@ export const useMenu = defineStore( isAppend = true, ) => { const isArray = Array.isArray(optins) + const arr = isArray ? [...optins] : [optins] - if (isAppend) { - isArray - ? menuState.menuTagOptions.push(...optins) - : menuState.menuTagOptions.push(optins) - } else { - isArray - ? (menuState.menuTagOptions = optins) - : (menuState.menuTagOptions = [optins]) - } + isAppend + ? menuState.menuTagOptions.push(...arr) + : (menuState.menuTagOptions = arr) } /** @@ -159,6 +164,7 @@ export const useMenu = defineStore( * @remark 如果权限发生变动, 则会触发强制弹出页面并且重新登陆 */ const setupAppRoutes = () => { + /** 取出所有 layout 下子路由 */ const layout = router.getRoutes().find((route) => route.name === 'layout') const resolveRoutes = (routes: IMenuOptions[], index: number) => { @@ -168,6 +174,7 @@ export const useMenu = defineStore( } const { meta } = curr + /** 设置 label, i18nKey 优先级最高 */ const label = computed(() => meta?.i18nKey ? t(`GlobalMenuOptions.${meta!.i18nKey}`) @@ -203,7 +210,10 @@ export const useMenu = defineStore( : route if (curr.path === cacheMenuKey) { + /** 设置菜单标签 */ setMenuTagOptions(attr) + /** 设置浏览器标题 */ + updateDocumentTitle(attr) } attr.show = validRole(curr) @@ -212,6 +222,7 @@ export const useMenu = defineStore( }) } + /** 缓存菜单列表 */ menuState.options = resolveRoutes(layout?.children as IMenuOptions[], 0) /** 初始化后渲染面包屑 */