mirror of
https://github.com/XiaoDaiGua-Ray/ray-template.git
synced 2025-04-05 07:03:00 +08:00
version: v5.0.2
This commit is contained in:
parent
707300774d
commit
7783872ef6
13
CHANGELOG.md
13
CHANGELOG.md
@ -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` 项目。
|
||||||
|
@ -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",
|
||||||
|
@ -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
|
||||||
|
@ -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: () => (
|
||||||
|
@ -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]}>
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -436,6 +436,7 @@ export const piniaMenuStore = defineStore(
|
|||||||
setMenuTagOptions,
|
setMenuTagOptions,
|
||||||
resolveOption,
|
resolveOption,
|
||||||
updateMenuState,
|
updateMenuState,
|
||||||
|
setupAppMenu,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user