mirror of
https://gitee.com/element-plus/element-plus.git
synced 2024-12-02 19:28:14 +08:00
feat(components): [el-menu] allow user to hide menu when clicking outside (#14742)
* fix(components): allow user to hide menu when clicking outside when user sets `menu-trigger` to `click` and then clicking outside, it should be close menu closed #14738 * revert settings.json config * fix: debounce hide menu when clicking out side * fix: only trigger click outside when menu is open * fix: hide parent menu * fix: only trigger close menu when its opened * refactor: remove redundant code * refactor: remove redundant code * fix(docs): `collapse-on-click-outside` prop * fix(docs): `collapse-on-click-outside` prop * fix: move `clickOutSide` to `menu.ts` * fix: submenu does not emit `close` when clicking outside * fix: submenu does not emit `close` when clicking outside * fix: ts type * fix: ts type * fix: only close when passing `props.collapseOnClickOutside` to `true` * refactor: create `directives` variable * improvement: allow `recusiveMouseInSubMenu` to receive array * refactor: remove redundant code * fix: rename `recusiveMouseInSubMenu` to `recursiveMouseInSubMenu` * feat: add `hide-timeout` prop * fix: revert code * fix: code owner * fix: coder owner * fix: menu closed when clicking on submenu * refactor: remove redundant code * fix: get correct index path * fix: build * refactor: update docs and remove `unref` * fix: change `collapseOnClickOutside` to `closeOnClickOutside` * fix: remove `hideTimeout` prop
This commit is contained in:
parent
1b4bc76f75
commit
7f687ae598
@ -63,23 +63,24 @@ menu/popper-offset
|
||||
|
||||
## Menu Attributes
|
||||
|
||||
| Name | Description | Type | Accepted Values | Default |
|
||||
| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- | --------------------- | -------- |
|
||||
| mode | menu display mode | string | horizontal / vertical | vertical |
|
||||
| collapse | whether the menu is collapsed (available only in vertical mode) | boolean | — | false |
|
||||
| ellipsis | whether the menu is ellipsis (available only in horizontal mode) | boolean | — | true |
|
||||
| ellipsis-icon^(2.5.0) | custom ellipsis icon (available only in horizontal mode and ellipsis is true) | `string \| Component` | — | — |
|
||||
| popper-offset^(2.5.0) | offset of the popper (effective for all submenus) | number | — | 6 |
|
||||
| background-color | background color of Menu (hex format) (deprecated, use `--bg-color` instead) | string | — | #ffffff |
|
||||
| text-color | text color of Menu (hex format) (deprecated, use `--text-color` instead) | string | — | #303133 |
|
||||
| active-text-color | text color of currently active menu item (hex format) (deprecated, use `--active-color` instead) | string | — | #409EFF |
|
||||
| default-active | index of active menu on page load | string | — | — |
|
||||
| default-openeds | array that contains indexes of currently active sub-menus | Array | — | — |
|
||||
| unique-opened | whether only one sub-menu can be active | boolean | — | false |
|
||||
| menu-trigger | how sub-menus are triggered, only works when `mode` is 'horizontal' | string | hover / click | hover |
|
||||
| router | whether `vue-router` mode is activated. If true, index will be used as 'path' to activate the route action. Use with `default-active` to set the active item on load. | boolean | — | false |
|
||||
| collapse-transition | whether to enable the collapse transition | boolean | — | true |
|
||||
| popper-effect ^(2.2.26) | Tooltip theme, built-in theme: `dark` / `light` when menu is collapsed | string | dark / light | dark |
|
||||
| Name | Description | Type | Accepted Values | Default |
|
||||
| ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- | --------------------- | -------- |
|
||||
| mode | menu display mode | string | horizontal / vertical | vertical |
|
||||
| collapse | whether the menu is collapsed (available only in vertical mode) | boolean | — | false |
|
||||
| ellipsis | whether the menu is ellipsis (available only in horizontal mode) | boolean | — | true |
|
||||
| ellipsis-icon^(2.5.0) | custom ellipsis icon (available only in horizontal mode and ellipsis is true) | `string \| Component` | — | — |
|
||||
| popper-offset^(2.5.0) | offset of the popper (effective for all submenus) | number | — | 6 |
|
||||
| background-color | background color of Menu (hex format) (deprecated, use `--bg-color` instead) | string | — | #ffffff |
|
||||
| text-color | text color of Menu (hex format) (deprecated, use `--text-color` instead) | string | — | #303133 |
|
||||
| active-text-color | text color of currently active menu item (hex format) (deprecated, use `--active-color` instead) | string | — | #409EFF |
|
||||
| default-active | index of active menu on page load | string | — | — |
|
||||
| default-openeds | array that contains indexes of currently active sub-menus | Array | — | — |
|
||||
| unique-opened | whether only one sub-menu can be active | boolean | — | false |
|
||||
| menu-trigger | how sub-menus are triggered, only works when `mode` is 'horizontal' | string | hover / click | hover |
|
||||
| router | whether `vue-router` mode is activated. If true, index will be used as 'path' to activate the route action. Use with `default-active` to set the active item on load. | boolean | — | false |
|
||||
| collapse-transition | whether to enable the collapse transition | boolean | — | true |
|
||||
| popper-effect ^(2.2.26) | Tooltip theme, built-in theme: `dark` / `light` when menu is collapsed | string | dark / light | dark |
|
||||
| close-on-click-outside ^(2.5.0) | optional, whether menu is collapsed when clicking outside | `boolean` | — | false |
|
||||
|
||||
## Menu Methods
|
||||
|
||||
|
@ -10,7 +10,9 @@ import {
|
||||
ref,
|
||||
watch,
|
||||
watchEffect,
|
||||
withDirectives,
|
||||
} from 'vue'
|
||||
|
||||
import { useResizeObserver } from '@vueuse/core'
|
||||
import { isNil } from 'lodash-unified'
|
||||
import ElIcon from '@element-plus/components/icon'
|
||||
@ -25,6 +27,7 @@ import {
|
||||
mutable,
|
||||
} from '@element-plus/utils'
|
||||
import { useNamespace } from '@element-plus/hooks'
|
||||
import { ClickOutside as vClickoutside } from '@element-plus/directives'
|
||||
import Menubar from './utils/menu-bar'
|
||||
import ElMenuCollapseTransition from './menu-collapse-transition.vue'
|
||||
import ElSubMenu from './sub-menu'
|
||||
@ -34,6 +37,7 @@ import type { MenuItemClicked, MenuProvider, SubMenuProvider } from './types'
|
||||
import type { NavigationFailure, Router } from 'vue-router'
|
||||
import type {
|
||||
Component,
|
||||
DirectiveArguments,
|
||||
ExtractPropTypes,
|
||||
VNode,
|
||||
VNodeArrayChildren,
|
||||
@ -65,6 +69,7 @@ export const menuProps = buildProps({
|
||||
backgroundColor: String,
|
||||
textColor: String,
|
||||
activeTextColor: String,
|
||||
closeOnClickOutside: Boolean,
|
||||
collapseTransition: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
@ -270,6 +275,8 @@ export default defineComponent({
|
||||
return sliceIndex === items.length ? -1 : sliceIndex
|
||||
}
|
||||
|
||||
const getIndexPath = (index: string) => subMenus.value[index].indexPath
|
||||
|
||||
// Common computer monitor FPS is 60Hz, which means 60 redraws per second. Calculation formula: 1000ms/60 ≈ 16.67ms, In order to avoid a certain chance of repeated triggering when `resize`, set wait to 16.67 * 2 = 33.34
|
||||
const debounce = (fn: () => void, wait = 33.34) => {
|
||||
let timmer: ReturnType<typeof setTimeout> | null
|
||||
@ -320,6 +327,8 @@ export default defineComponent({
|
||||
else resizeStopper?.()
|
||||
})
|
||||
|
||||
const mouseInChild = ref(false)
|
||||
|
||||
// provide
|
||||
{
|
||||
const addSubMenu: MenuProvider['addSubMenu'] = (item) => {
|
||||
@ -360,7 +369,7 @@ export default defineComponent({
|
||||
provide<SubMenuProvider>(`subMenu:${instance.uid}`, {
|
||||
addSubMenu,
|
||||
removeSubMenu,
|
||||
mouseInChild: ref(false),
|
||||
mouseInChild,
|
||||
level: 0,
|
||||
})
|
||||
}
|
||||
@ -429,20 +438,42 @@ export default defineComponent({
|
||||
|
||||
const ulStyle = useMenuCssVar(props, 0)
|
||||
|
||||
const vMenu = h(
|
||||
'ul',
|
||||
{
|
||||
key: String(props.collapse),
|
||||
role: 'menubar',
|
||||
ref: menu,
|
||||
style: ulStyle.value,
|
||||
class: {
|
||||
[nsMenu.b()]: true,
|
||||
[nsMenu.m(props.mode)]: true,
|
||||
[nsMenu.m('collapse')]: props.collapse,
|
||||
const directives: DirectiveArguments = props.closeOnClickOutside
|
||||
? [
|
||||
[
|
||||
vClickoutside,
|
||||
() => {
|
||||
if (!openedMenus.value.length) return
|
||||
|
||||
if (!mouseInChild.value) {
|
||||
openedMenus.value.forEach((openedMenu) =>
|
||||
emit('close', openedMenu, getIndexPath(openedMenu))
|
||||
)
|
||||
|
||||
openedMenus.value = []
|
||||
}
|
||||
},
|
||||
],
|
||||
]
|
||||
: []
|
||||
|
||||
const vMenu = withDirectives(
|
||||
h(
|
||||
'ul',
|
||||
{
|
||||
key: String(props.collapse),
|
||||
role: 'menubar',
|
||||
ref: menu,
|
||||
style: ulStyle.value,
|
||||
class: {
|
||||
[nsMenu.b()]: true,
|
||||
[nsMenu.m(props.mode)]: true,
|
||||
[nsMenu.m('collapse')]: props.collapse,
|
||||
},
|
||||
},
|
||||
},
|
||||
[...slot, ...vShowMore]
|
||||
[...slot, ...vShowMore]
|
||||
),
|
||||
directives
|
||||
)
|
||||
|
||||
if (props.collapseTransition && props.mode === 'vertical') {
|
||||
|
@ -239,6 +239,7 @@ export default defineComponent({
|
||||
(!rootMenu.props.collapse && rootMenu.props.mode === 'vertical') ||
|
||||
props.disabled
|
||||
) {
|
||||
subMenu.mouseInChild.value = true
|
||||
return
|
||||
}
|
||||
subMenu.mouseInChild.value = true
|
||||
@ -259,6 +260,7 @@ export default defineComponent({
|
||||
rootMenu.props.mode === 'horizontal') ||
|
||||
(!rootMenu.props.collapse && rootMenu.props.mode === 'vertical')
|
||||
) {
|
||||
subMenu.mouseInChild.value = false
|
||||
return
|
||||
}
|
||||
timeout?.()
|
||||
|
Loading…
Reference in New Issue
Block a user