Skip to content

Commit

Permalink
releases 4.1.30
Browse files Browse the repository at this point in the history
  • Loading branch information
xuliangzhan committed Sep 20, 2024
1 parent 928c8a1 commit af0fb7a
Show file tree
Hide file tree
Showing 9 changed files with 223 additions and 67 deletions.
6 changes: 4 additions & 2 deletions examples/views/menu/MenuTest.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
<template>
<div>
<div style="width: 260px">
<vxe-menu v-model="selectNav" :options="navList" @click="clickEvent"></vxe-menu>
<vxe-button @click="isCollapsed = !isCollapsed">切换</vxe-button>
<div style="display: inline-flex;">
<vxe-menu v-model="selectNav" :collapsed="isCollapsed" :options="navList" @click="clickEvent"></vxe-menu>
</div>
</div>
</template>
Expand All @@ -11,6 +12,7 @@ import { ref } from 'vue'
import { VxeMenuPropTypes, VxeMenuEvents } from 'vxe-pc-ui'
const selectNav = ref('user')
const isCollapsed = ref(false)
const navList = ref<VxeMenuPropTypes.Options>([
{ name: 'home', title: '首页', icon: 'vxe-icon-home' },
{
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "vxe-pc-ui",
"version": "4.1.29",
"version": "4.1.30",
"description": "A vue based PC component library",
"scripts": {
"update": "npm install --legacy-peer-deps",
Expand Down
233 changes: 183 additions & 50 deletions packages/menu/src/menu.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { defineComponent, ref, h, reactive, PropType, inject, resolveComponent, createCommentVNode, nextTick, watch, VNode, onMounted, computed } from 'vue'
import { defineComponent, ref, h, reactive, PropType, inject, resolveComponent, createCommentVNode, watch, VNode, computed, nextTick, onBeforeUnmount, onMounted } from 'vue'
import XEUtils from 'xe-utils'
import { getConfig, getIcon, createEvent, permission, useSize } from '../../ui'
import VxeLoadingComponent from '../../loading/index'
import { getConfig, getIcon, createEvent, permission, useSize, globalEvents } from '../../ui'
import { toCssUnit } from '../../ui/src/dom'
import { getLastZIndex, nextZIndex } from '../../ui/src/utils'
import VxeLoadingComponent from '../../loading/src/loading'

import type { VxeMenuDefines, VxeMenuPropTypes, MenuReactData, VxeMenuEmits, MenuMethods, MenuPrivateMethods, MenuPrivateRef, VxeMenuPrivateComputed, VxeMenuConstructor, VxeMenuPrivateMethods, ValueOf, VxeLayoutAsideConstructor, VxeLayoutAsidePrivateMethods } from '../../../types'
import type { VxeMenuDefines, VxeMenuPropTypes, MenuReactData, VxeMenuEmits, MenuMethods, VxeLayoutAsidePropTypes, MenuPrivateMethods, MenuPrivateRef, VxeMenuPrivateComputed, VxeMenuConstructor, VxeMenuPrivateMethods, ValueOf, VxeLayoutAsideConstructor, VxeLayoutAsidePrivateMethods } from '../../../types'

export default defineComponent({
name: 'VxeMenu',
Expand Down Expand Up @@ -36,11 +38,15 @@ export default defineComponent({
const $xeLayoutAside = inject<(VxeLayoutAsideConstructor & VxeLayoutAsidePrivateMethods) | null>('$xeLayoutAside', null)

const refElem = ref<HTMLDivElement>()
const refWrapperElem = ref<HTMLDivElement>()
const refCollapseElem = ref<HTMLDivElement>()

const { computeSize } = useSize(props)

const reactData = reactive<MenuReactData>({
initialized: !!props.collapsed,
isEnterCollapse: false,
collapseStyle: {},
collapseZindex: 0,
activeName: props.modelValue,
menuList: [],
itemHeight: 1
Expand All @@ -61,6 +67,22 @@ export default defineComponent({
return false
})

const computeCollapseWidth = computed(() => {
let collapseWidth: VxeLayoutAsidePropTypes.CollapseWidth = ''
if ($xeLayoutAside) {
collapseWidth = $xeLayoutAside.props.collapseWidth || ''
}
return collapseWidth
})

const computeCollapseEnterWidth = computed(() => {
let width: VxeLayoutAsidePropTypes.Width = ''
if ($xeLayoutAside) {
width = $xeLayoutAside.props.width || ''
}
return width
})

const computeMaps: VxeMenuPrivateComputed = {
computeSize
}
Expand All @@ -79,34 +101,12 @@ export default defineComponent({
return `${item.title || item.name}`
}

const updateItemHeight = () => {
const wrapperElem = refWrapperElem.value
const childEls = wrapperElem ? wrapperElem.children : []
if (childEls.length) {
reactData.itemHeight = (childEls[0] as HTMLDivElement).offsetHeight
const updateZindex = () => {
if (reactData.collapseZindex < getLastZIndex()) {
reactData.collapseZindex = nextZIndex()
}
}

const getExpandChildSize = (item: VxeMenuDefines.MenuItem) => {
let size = 0
if (item.isExpand) {
item.childList.forEach(child => {
size += getExpandChildSize(child) + 1
})
}
return size
}

const updateStyle = () => {
XEUtils.eachTree(reactData.menuList, (item) => {
if (item.hasChild && item.isExpand) {
item.childHeight = getExpandChildSize(item) * reactData.itemHeight
} else {
item.childHeight = 0
}
}, { children: 'childList' })
}

const updateActiveMenu = (isDefExpand?: boolean) => {
const { activeName } = reactData
XEUtils.eachTree(reactData.menuList, (item, index, items, path, parent, nodes) => {
Expand Down Expand Up @@ -136,38 +136,102 @@ export default defineComponent({
isExactActive: false,
isActive: false,
isExpand: XEUtils.isBoolean(item.expanded) ? item.expanded : !!expandAll,
hasChild: item.children && item.children.length > 0,
childHeight: 0
hasChild: item.children && item.children.length > 0
} as VxeMenuDefines.MenuItem
return objItem
}, { children: 'children', mapChildren: 'childList' })
}

const updateCollapseStyle = () => {
nextTick(() => {
const { isEnterCollapse } = reactData
const isCollapsed = computeIsCollapsed.value
const collapseEnterWidth = computeCollapseEnterWidth.value
const collapseWidth = computeCollapseWidth.value
const el = refElem.value
if (el) {
const clientRect = el.getBoundingClientRect()
const parentNode = el.parentNode as HTMLElement
reactData.collapseStyle = isCollapsed
? {
top: toCssUnit(clientRect.top),
left: toCssUnit(clientRect.left),
height: toCssUnit(parentNode.clientHeight),
width: isEnterCollapse ? (collapseEnterWidth ? toCssUnit(collapseEnterWidth) : '') : (collapseWidth ? toCssUnit(collapseWidth) : ''),
zIndex: reactData.collapseZindex
}
: {}
}
})
}

const handleCollapseMenu = () => {
const { initialized } = reactData
const isCollapsed = computeIsCollapsed.value
if (isCollapsed) {
if (!initialized) {
reactData.initialized = true
nextTick(() => {
const collapseEl = refCollapseElem.value
if (collapseEl) {
document.body.appendChild(collapseEl)
}
})
}
}
reactData.isEnterCollapse = false
updateZindex()
updateCollapseStyle()
}

const handleClickIconCollapse = (evnt: KeyboardEvent, item: VxeMenuDefines.MenuItem) => {
const { hasChild, isExpand } = item
if (hasChild) {
evnt.stopPropagation()
evnt.preventDefault()
item.isExpand = !isExpand
updateItemHeight()
updateStyle()
}
}

const emitModel = (value: any) => {
reactData.activeName = value
emit('update:modelValue', value)
}

const handleClickMenu = (evnt: KeyboardEvent, item: VxeMenuDefines.MenuItem) => {
const { routerLink, hasChild } = item
const { itemKey, routerLink, hasChild } = item
if (routerLink) {
const value = item.itemKey
reactData.activeName = value
emit('update:modelValue', value)
emitModel(itemKey)
reactData.isEnterCollapse = false
} else {
if (hasChild) {
handleClickIconCollapse(evnt, item)
} else {
emitModel(itemKey)
reactData.isEnterCollapse = false
}
}
dispatchEvent('click', { menu: item }, evnt)
}

const handleMenuMouseenter = () => {
const { collapseStyle } = reactData
const collapseEnterWidth = computeCollapseEnterWidth.value
reactData.collapseStyle = Object.assign({}, collapseStyle, {
width: collapseEnterWidth ? toCssUnit(collapseEnterWidth) : ''
})
reactData.isEnterCollapse = true
}

const handleMenuMouseleave = () => {
const { collapseStyle } = reactData
const el = refElem.value
reactData.collapseStyle = Object.assign({}, collapseStyle, {
width: el ? toCssUnit(el.offsetWidth) : ''
})
reactData.isEnterCollapse = false
}

const dispatchEvent = (type: ValueOf<VxeMenuEmits>, params: Record<string, any>, evnt: Event | null) => {
emit(type, createEvent(evnt, { $menu: $xeMenu }, params))
}
Expand Down Expand Up @@ -213,8 +277,9 @@ export default defineComponent({
]
}

const renderChildren = (item: VxeMenuDefines.MenuItem): VNode => {
const renderDefaultChildren = (item: VxeMenuDefines.MenuItem): VNode => {
const { itemKey, level, hasChild, isActive, isExactActive, isExpand, routerLink, childList } = item
const { isEnterCollapse } = reactData
const isCollapsed = computeIsCollapsed.value
if (item.permissionCode) {
if (!permission.checkVisible(item.permissionCode)) {
Expand All @@ -226,7 +291,7 @@ export default defineComponent({
class: ['vxe-menu--item-wrapper', `vxe-menu--item-level${level}`, {
'is--exact-active': isExactActive,
'is--active': isActive,
'is--expand': !isCollapsed && isExpand
'is--expand': (!isCollapsed || isEnterCollapse) && isExpand
}]
}, [
routerLink
Expand All @@ -247,18 +312,53 @@ export default defineComponent({
}, renderMenuTitle(item)),
hasChild
? h('div', {
class: 'vxe-menu--item-group',
style: {
// height: `${childHeight}px`
class: 'vxe-menu--item-group'
}, childList.map(child => renderDefaultChildren(child)))
: createCommentVNode()
])
}

const renderCollapseChildren = (item: VxeMenuDefines.MenuItem): VNode => {
const { itemKey, level, hasChild, isActive, isExactActive, routerLink, childList } = item
if (item.permissionCode) {
if (!permission.checkVisible(item.permissionCode)) {
return createCommentVNode()
}
}
return h('div', {
key: itemKey,
class: ['vxe-menu--item-wrapper', `vxe-menu--item-level${level}`, {
'is--exact-active': isExactActive,
'is--active': isActive
}]
}, [
routerLink
? h(resolveComponent('router-link'), {
class: 'vxe-menu--item-link',
to: routerLink,
onClick (evnt: KeyboardEvent) {
handleClickMenu(evnt, item)
}
}, {
default: () => renderMenuTitle(item)
})
: h('div', {
class: 'vxe-menu--item-link',
onClick (evnt: KeyboardEvent) {
handleClickMenu(evnt, item)
}
}, childList.map(child => renderChildren(child)))
}, renderMenuTitle(item)),
hasChild
? h('div', {
class: 'vxe-menu--item-group'
}, childList.map(child => renderDefaultChildren(child)))
: createCommentVNode()
])
}

const renderVN = () => {
const { loading } = props
const { menuList } = reactData
const { initialized, menuList, collapseStyle, isEnterCollapse } = reactData
const vSize = computeSize.value
const isCollapsed = computeIsCollapsed.value
return h('div', {
Expand All @@ -270,9 +370,28 @@ export default defineComponent({
}]
}, [
h('div', {
ref: refWrapperElem,
class: 'vxe-menu--item-list'
}, menuList.map(child => renderChildren(child))),
}, menuList.map(child => isCollapsed ? renderCollapseChildren(child) : renderDefaultChildren(child))),
initialized
? h('div', {
ref: refCollapseElem,
class: ['vxe-menu--collapse-wrapper', {
[`size--${vSize}`]: vSize,
'is--collapsed': isCollapsed,
'is--enter': isEnterCollapse,
'is--loading': loading
}],
style: collapseStyle,
onMouseenter: handleMenuMouseenter,
onMouseleave: handleMenuMouseleave
}, [
isCollapsed
? h('div', {
class: 'vxe-menu--item-list'
}, menuList.map(child => renderDefaultChildren(child)))
: createCommentVNode()
])
: createCommentVNode(),
/**
* 加载中
*/
Expand Down Expand Up @@ -303,10 +422,24 @@ export default defineComponent({
updateActiveMenu(true)
})

watch(computeIsCollapsed, () => {
handleCollapseMenu()
})

onMounted(() => {
nextTick(() => {
updateItemHeight()
})
globalEvents.on($xeMenu, 'resize', updateCollapseStyle)
updateCollapseStyle()
})

onBeforeUnmount(() => {
globalEvents.off($xeMenu, 'resize')
const collapseEl = refCollapseElem.value
if (collapseEl) {
const parentNode = collapseEl.parentNode
if (parentNode) {
parentNode.removeChild(collapseEl)
}
}
})

updateMenuConfig()
Expand Down
5 changes: 1 addition & 4 deletions packages/tabs/src/tabs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -631,11 +631,8 @@ export default defineComponent({
})
})

nextTick(() => {
globalEvents.on($xeTabs, 'resize', updateTabStyle)
})

onMounted(() => {
globalEvents.on($xeTabs, 'resize', updateTabStyle)
updateTabStyle()
})

Expand Down
2 changes: 1 addition & 1 deletion packages/ui/src/dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export function addClass (elem: any, cls: string) {
}

export function toCssUnit (val?: number | string) {
if (/^\d+$/.test(`${val}`)) {
if (XEUtils.isNumber(val) || /^\d+$/.test(`${val}`)) {
return `${val}px`
}
return `${val || ''}`
Expand Down
Loading

0 comments on commit af0fb7a

Please sign in to comment.