version: v5.0.2

This commit is contained in:
XiaoDaiGua-Ray 2024-10-23 20:48:01 +08:00
parent 707300774d
commit 7783872ef6
7 changed files with 69 additions and 23 deletions

View File

@ -1,5 +1,18 @@
# CHANGE LOG # CHANGE LOG
## 5.0.2
## Feats
- 暴露 `setupAppMenu` 方法,提供自定义菜单渲染时机能力
## Fixes
- 修复 `MenuTag` 右键菜单不能被选中的问题
- 修复 `Menu` 设置 `iconSize`, `iconCollapseSize` 等属性,不能及时刷新渲染的问题,现在新增手动刷新操作按钮
> 菜单渲染是很复杂、很耗时的操作,所以在权衡以后还是考虑使用手动刷新操作方式更新菜单状态。
## 5.0.1 ## 5.0.1
本次更新灵感来自于 `vben admin 5` 项目。 本次更新灵感来自于 `vben admin 5` 项目。

View File

@ -1,7 +1,7 @@
{ {
"name": "ray-template", "name": "ray-template",
"private": false, "private": false,
"version": "5.0.1", "version": "5.0.2",
"type": "module", "type": "module",
"engines": { "engines": {
"node": "^18.0.0 || >=20.0.0", "node": "^18.0.0 || >=20.0.0",

View File

@ -21,7 +21,6 @@ export default defineComponent({
useMenuActions() useMenuActions()
const { getMenuConfig } = useSettingGetters() const { getMenuConfig } = useSettingGetters()
const { getMenuOptions, getCollapsed, getMenuKey } = useMenuGetters() const { getMenuOptions, getCollapsed, getMenuKey } = useMenuGetters()
const modelMenuKey = computed({ const modelMenuKey = computed({
get: () => { get: () => {
// eslint-disable-next-line vue/no-async-in-computed-properties // eslint-disable-next-line vue/no-async-in-computed-properties

View File

@ -16,7 +16,7 @@
* Root Path MenuTag Root Tag * Root Path MenuTag Root Tag
* *
* outsideClick contextmenu * outsideClick contextmenu
* 使 throttle v5.0.1 * 使 throttle v5.0.2
*/ */
import './index.scss' import './index.scss'
@ -34,7 +34,6 @@ import { RIcon, RMoreDropdown } from '@/components'
import { useMenuGetters, useMenuActions } from '@/store' import { useMenuGetters, useMenuActions } from '@/store'
import { hasClass, uuid, queryElements } from '@/utils' import { hasClass, uuid, queryElements } from '@/utils'
import { useMaximize, useSpinning, useAppRoot, useSiderBar } from '@/hooks' import { useMaximize, useSpinning, useAppRoot, useSiderBar } from '@/hooks'
import { throttle } from 'lodash-es'
import { getVariableToRefs } from '@/global-variable' import { getVariableToRefs } from '@/global-variable'
import { useTemplateRef } from 'vue' import { useTemplateRef } from 'vue'
@ -65,7 +64,6 @@ export default defineComponent({
'closeRight', 'closeRight',
'closeLeft', 'closeLeft',
'closeOther', 'closeOther',
'closeCurrentPage',
] ]
// 当前右键标签页索引位置 // 当前右键标签页索引位置
let currentContextmenuIndex = Infinity let currentContextmenuIndex = Infinity
@ -179,6 +177,8 @@ export default defineComponent({
const naiveScrollbarContainerClass = 'n-scrollbar-container' const naiveScrollbarContainerClass = 'n-scrollbar-container'
// 缓存上一次的菜单 key // 缓存上一次的菜单 key
let catchMenuKey = getMenuKey.value let catchMenuKey = getMenuKey.value
// 当前鼠标是否划入 menu tag
const isMouseInMenuTag = ref(false)
// 关闭当前菜单标签,如果只有一个标签,则不允许关闭 // 关闭当前菜单标签,如果只有一个标签,则不允许关闭
const closeCurrentMenuTag = (idx: number) => { const closeCurrentMenuTag = (idx: number) => {
@ -260,21 +260,14 @@ export default defineComponent({
actionState.actionDropdownShow = false actionState.actionDropdownShow = false
nextTick(() => { nextTick(() => {
actionState.actionDropdownShow = true
actionState.x = e.clientX actionState.x = e.clientX
actionState.y = e.clientY actionState.y = e.clientY
actionState.actionDropdownShow = true
}) })
} }
// 动态设置某些项禁用 // 动态设置某些项禁用
const setDisabledAccordionToIndex = () => { const setDisabledAccordionToIndex = () => {
const { closeable } =
getMenuTagOptions.value[currentContextmenuIndex] ??
({} as MenuTagOptions)
// 是否需要禁用关闭当前标签页
setMoreOptionsDisabled('closeCurrentPage', !closeable ?? false)
// 是否需要禁用关闭右侧标签页 // 是否需要禁用关闭右侧标签页
checkCloseRight(currentContextmenuIndex) checkCloseRight(currentContextmenuIndex)
? setMoreOptionsDisabled('closeRight', false) ? setMoreOptionsDisabled('closeRight', false)
@ -306,6 +299,8 @@ export default defineComponent({
) { ) {
option.closeable = true option.closeable = true
} }
isMouseInMenuTag.value = true
} }
// 移出 MenuTag 时,判断是否为当前已激活 key // 移出 MenuTag 时,判断是否为当前已激活 key
@ -313,6 +308,8 @@ export default defineComponent({
if (option.fullPath !== getMenuKey.value) { if (option.fullPath !== getMenuKey.value) {
option.closeable = false option.closeable = false
} }
isMouseInMenuTag.value = false
} }
// 每当新的页面打开后,将滚动条横向滚到至底部,使用 nextTick 避免元素未渲染挂载至页面 // 每当新的页面打开后,将滚动条横向滚到至底部,使用 nextTick 避免元素未渲染挂载至页面
@ -359,7 +356,7 @@ export default defineComponent({
(ndata, odata) => { (ndata, odata) => {
// 当 menuTagOptions 长度为 1时禁用所有 canDisabledOptions 匹配的项 // 当 menuTagOptions 长度为 1时禁用所有 canDisabledOptions 匹配的项
moreOptions.value.forEach((curr) => { moreOptions.value.forEach((curr) => {
if (canDisabledOptions.includes(curr.key)) { if (canDisabledOptions.includes(curr.key as string)) {
ndata.length > 1 ? (curr.disabled = false) : (curr.disabled = true) ndata.length > 1 ? (curr.disabled = false) : (curr.disabled = true)
} }
}) })
@ -384,8 +381,7 @@ export default defineComponent({
) )
watchEffect(() => { watchEffect(() => {
if (actionState.actionDropdownShow) { if (actionState.actionDropdownShow) {
// 使用节流函数,避免右键菜单闪烁问题 setDisabledAccordionToIndex()
throttle(setDisabledAccordionToIndex, 300)?.()
} }
if (catchMenuKey !== getMenuKey.value) { if (catchMenuKey !== getMenuKey.value) {
@ -418,6 +414,7 @@ export default defineComponent({
reload, reload,
globalMainLayoutLoad, globalMainLayoutLoad,
maximizeBtnClick, maximizeBtnClick,
isMouseInMenuTag,
} }
}, },
render() { render() {
@ -427,6 +424,7 @@ export default defineComponent({
getMenuTagOptions, getMenuTagOptions,
MENU_TAG_DATA, MENU_TAG_DATA,
globalMainLayoutLoad, globalMainLayoutLoad,
isMouseInMenuTag,
} = this } = this
const { const {
maximizeBtnClick, maximizeBtnClick,
@ -454,6 +452,11 @@ export default defineComponent({
trigger="manual" trigger="manual"
placement="bottom-start" placement="bottom-start"
onSelect={actionDropdownSelect.bind(this)} onSelect={actionDropdownSelect.bind(this)}
onClickoutside={() => {
if (!isMouseInMenuTag) {
this.actionState.actionDropdownShow = false
}
}}
/> />
<NFlex <NFlex
class="menu-tag-space" class="menu-tag-space"
@ -510,12 +513,10 @@ export default defineComponent({
onContextmenu: menuTagContextMenu.bind(this, idx), onContextmenu: menuTagContextMenu.bind(this, idx),
onMouseenter: menuTagMouseenter.bind(this, curr), onMouseenter: menuTagMouseenter.bind(this, curr),
onMouseleave: menuTagMouseleave.bind(this, curr), onMouseleave: menuTagMouseleave.bind(this, curr),
onBlur: () => {
this.actionState.actionDropdownShow = false
},
[MENU_TAG_DATA]: curr.fullPath, [MENU_TAG_DATA]: curr.fullPath,
}} }}
size="small" size="small"
focusable={false}
> >
{{ {{
default: () => ( default: () => (

View File

@ -21,9 +21,9 @@ import ThemeSegment from './components/ThemeSegment'
import { RIcon } from '@/components' import { RIcon } from '@/components'
import { APP_THEME, CONTENT_TRANSITION_OPTIONS } from '@/app-config' import { APP_THEME, CONTENT_TRANSITION_OPTIONS } from '@/app-config'
import { useSettingGetters, useSettingActions } from '@/store' import { useSettingGetters, useSettingActions, useMenuActions } from '@/store'
import { defaultSettingConfig } from './constant' import { defaultSettingConfig } from './constant'
import { forIn } from 'lodash-es' import { forIn, throttle } from 'lodash-es'
import type { PropType } from 'vue' import type { PropType } from 'vue'
import type { Placement } from '@/types' import type { Placement } from '@/types'
@ -60,6 +60,7 @@ export default defineComponent({
getMenuConfig, getMenuConfig,
getDrawerPlacement, getDrawerPlacement,
} = useSettingGetters() } = useSettingGetters()
const { setupAppMenu } = useMenuActions()
const modelShow = computed({ const modelShow = computed({
get: () => props.show, get: () => props.show,
@ -84,10 +85,14 @@ export default defineComponent({
set: (value) => {}, set: (value) => {},
}) })
const throttleSetupAppMenu = throttle(setupAppMenu, 300)
const defaultSettingBtnClick = () => { const defaultSettingBtnClick = () => {
forIn(defaultSettingConfig, (value, key) => { forIn(defaultSettingConfig, (value, key) => {
updateSettingState(key as keyof SettingState, value) updateSettingState(key as keyof SettingState, value)
}) })
throttleSetupAppMenu()
} }
return { return {
@ -98,6 +103,7 @@ export default defineComponent({
updateSettingState, updateSettingState,
modelReactive, modelReactive,
defaultSettingBtnClick, defaultSettingBtnClick,
throttleSetupAppMenu,
} }
}, },
render() { render() {
@ -106,6 +112,7 @@ export default defineComponent({
changePrimaryColor, changePrimaryColor,
updateSettingState, updateSettingState,
defaultSettingBtnClick, defaultSettingBtnClick,
throttleSetupAppMenu,
} = this } = this
return ( return (
@ -226,7 +233,17 @@ export default defineComponent({
/> />
</NDescriptionsItem> </NDescriptionsItem>
</NDescriptions> </NDescriptions>
<NDivider titlePlacement="center"></NDivider> <NDivider titlePlacement="center">
<NFlex wrap={false} align="center" size={[4, 0]}>
<NTooltip placement="top" showArrow={false}>
{{
trigger: () => <RIcon name="question" size="16" />,
default: () => '菜单渲染是一个复杂、耗时的操作,请手动更新',
}}
</NTooltip>
<NText></NText>
</NFlex>
</NDivider>
<NForm showFeedback={true} showRequireMark={false}> <NForm showFeedback={true} showRequireMark={false}>
<NFormItem label="每级菜单缩进"> <NFormItem label="每级菜单缩进">
<NInputNumber <NInputNumber
@ -274,7 +291,7 @@ export default defineComponent({
}} }}
/> />
</NFormItem> </NFormItem>
<NFormItem label="折叠菜单宽度" showFeedback={false}> <NFormItem label="折叠菜单宽度">
<NInputNumber <NInputNumber
v-model:value={ v-model:value={
this.modelReactive.getMenuConfig.collapsedWidth this.modelReactive.getMenuConfig.collapsedWidth
@ -290,6 +307,19 @@ export default defineComponent({
}} }}
/> />
</NFormItem> </NFormItem>
<NFormItem showFeedback={false} showLabel={false}>
<NButton
onClick={throttleSetupAppMenu}
block
type="info"
secondary
>
{{
icon: () => <RIcon name="question" size="16" />,
default: () => '点击刷新',
}}
</NButton>
</NFormItem>
</NForm> </NForm>
<NDivider titlePlacement="center"> <NDivider titlePlacement="center">
<NFlex wrap={false} align="center" size={[4, 0]}> <NFlex wrap={false} align="center" size={[4, 0]}>

View File

@ -73,6 +73,7 @@ export const useMenuActions = () => {
setMenuTagOptions, setMenuTagOptions,
resolveOption, resolveOption,
updateMenuState, updateMenuState,
setupAppMenu,
} = piniaMenuStore() } = piniaMenuStore()
return { return {
@ -82,5 +83,6 @@ export const useMenuActions = () => {
setMenuTagOptions, setMenuTagOptions,
resolveOption, resolveOption,
updateMenuState, updateMenuState,
setupAppMenu,
} }
} }

View File

@ -436,6 +436,7 @@ export const piniaMenuStore = defineStore(
setMenuTagOptions, setMenuTagOptions,
resolveOption, resolveOption,
updateMenuState, updateMenuState,
setupAppMenu,
} }
}, },
{ {