parent
a8d317ac9f
commit
12770dcaf7
@ -0,0 +1,74 @@ |
|||||||
|
<template> |
||||||
|
<li |
||||||
|
class="el-menu-item" |
||||||
|
:style="paddingStyle" |
||||||
|
:class="{'is-active': active,'is-disabled': disabled}" |
||||||
|
@click="handleClick" |
||||||
|
> |
||||||
|
<el-tooltip |
||||||
|
v-if="parentMenu.$options.componentName === 'ElMenu' && rootMenu.collapse && $slots.title" |
||||||
|
effect="dark" |
||||||
|
placement="right" |
||||||
|
> |
||||||
|
<div slot="content"> |
||||||
|
<slot name="title"/> |
||||||
|
</div> |
||||||
|
<div style="position: absolute;left: 0;top: 0;height: 100%;width: 100%;display: inline-block;box-sizing: border-box;padding: 0 20px;"> |
||||||
|
<slot/> |
||||||
|
</div> |
||||||
|
</el-tooltip> |
||||||
|
|
||||||
|
<template v-else> |
||||||
|
<slot/> |
||||||
|
<slot name="title"/> |
||||||
|
</template> |
||||||
|
</li> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import MenuMixin from 'element-ui/packages/menu/src/menu-mixin' |
||||||
|
import Emitter from 'element-ui/lib/mixins/emitter' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'ElMenuItem', |
||||||
|
|
||||||
|
componentName: 'ElMenuItem', |
||||||
|
|
||||||
|
mixins: [MenuMixin, Emitter], |
||||||
|
|
||||||
|
data() { |
||||||
|
return {} |
||||||
|
}, |
||||||
|
|
||||||
|
props: { |
||||||
|
index: String, |
||||||
|
route: [String, Object], |
||||||
|
disabled: Boolean |
||||||
|
}, |
||||||
|
|
||||||
|
computed: { |
||||||
|
active() { |
||||||
|
return this.index === this.rootMenu.activeIndex |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
methods: { |
||||||
|
handleClick() { |
||||||
|
if (!this.disabled) { |
||||||
|
this.dispatch('ElMenu', 'item-click', this) |
||||||
|
this.$emit('click', this) |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
mounted() { |
||||||
|
this.parentMenu.addItem(this) |
||||||
|
this.rootMenu.addItem(this) |
||||||
|
}, |
||||||
|
|
||||||
|
beforeDestroy() { |
||||||
|
this.parentMenu.removeItem(this) |
||||||
|
this.rootMenu.removeItem(this) |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
@ -0,0 +1,278 @@ |
|||||||
|
<script type="text/jsx"> |
||||||
|
import MenuMixin from 'element-ui/packages/menu/src/menu-mixin' |
||||||
|
import Emitter from 'element-ui/lib/mixins/emitter' |
||||||
|
import Popper from 'element-ui/lib/utils/vue-popper' |
||||||
|
|
||||||
|
const PopperMixins = { |
||||||
|
props: { |
||||||
|
transformOrigin: {type: [Boolean, String], default: false}, |
||||||
|
offset: Popper.props.offset, |
||||||
|
boundariesPadding: Popper.props.boundariesPadding, |
||||||
|
popperOptions: Popper.props.popperOptions |
||||||
|
}, |
||||||
|
data: Popper.data, |
||||||
|
methods: Popper.methods, |
||||||
|
beforeDestroy: Popper.beforeDestroy, |
||||||
|
deactivated: Popper.deactivated |
||||||
|
} |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'ElSubmenu', |
||||||
|
|
||||||
|
componentName: 'ElSubmenu', |
||||||
|
|
||||||
|
mixins: [MenuMixin, Emitter, PopperMixins], |
||||||
|
|
||||||
|
props: { |
||||||
|
index: String, |
||||||
|
showTimeout: {type: Number, default: 300}, |
||||||
|
hideTimeout: {type: Number, default: 300}, |
||||||
|
popperClass: String, |
||||||
|
disabled: Boolean, |
||||||
|
popperAppendToBody: {type: Boolean, default: true} |
||||||
|
}, |
||||||
|
|
||||||
|
data() { |
||||||
|
return { |
||||||
|
popperJS: null, |
||||||
|
timeout: null, |
||||||
|
items: {}, |
||||||
|
submenus: {}, |
||||||
|
mouseInChild: false |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
computed: { |
||||||
|
appendToBody() { |
||||||
|
return this.popperAppendToBody === undefined |
||||||
|
? this.isFirstLevel |
||||||
|
: this.popperAppendToBody |
||||||
|
}, |
||||||
|
menuTransitionName() { |
||||||
|
return this.rootMenu.collapse ? 'el-zoom-in-left' : 'el-zoom-in-top' |
||||||
|
}, |
||||||
|
opened() { |
||||||
|
return this.rootMenu.openedMenus.includes(this.index) |
||||||
|
}, |
||||||
|
active() { |
||||||
|
const items = this.items |
||||||
|
|
||||||
|
const isActive = Object.keys(items).some(key => items[key].active) |
||||||
|
|
||||||
|
if (!isActive) { |
||||||
|
const submenus = this.submenus |
||||||
|
return Object.keys(submenus).some(key => submenus[key].active) |
||||||
|
} |
||||||
|
|
||||||
|
return isActive |
||||||
|
}, |
||||||
|
mode() { |
||||||
|
return this.rootMenu.mode |
||||||
|
}, |
||||||
|
isMenuPopup() { |
||||||
|
return this.rootMenu.isMenuPopup |
||||||
|
}, |
||||||
|
isFirstLevel() { |
||||||
|
const arr = ['ElSubmenu', 'ElMenuItemGroup'] |
||||||
|
let isFirstLevel = true |
||||||
|
let parent = this.$parent |
||||||
|
|
||||||
|
while (parent && parent !== this.rootMenu) { |
||||||
|
if (arr.includes(parent.$options.componentName)) { |
||||||
|
isFirstLevel = false |
||||||
|
break |
||||||
|
} |
||||||
|
else parent = parent.$parent |
||||||
|
} |
||||||
|
return isFirstLevel |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
watch: { |
||||||
|
opened() { |
||||||
|
this.isMenuPopup && this.$nextTick(this.updatePopper) |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
methods: { |
||||||
|
handleCollapseToggle(value) { |
||||||
|
if (value) { |
||||||
|
this.initPopper() |
||||||
|
} |
||||||
|
else { |
||||||
|
this.doDestroy() |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
addItem(item) { |
||||||
|
this.$set(this.items, item.index, item) |
||||||
|
}, |
||||||
|
|
||||||
|
removeItem(item) { |
||||||
|
delete this.items[item.index] |
||||||
|
}, |
||||||
|
|
||||||
|
addSubmenu(item) { |
||||||
|
this.$set(this.submenus, item.index, item) |
||||||
|
}, |
||||||
|
|
||||||
|
removeSubmenu(item) { |
||||||
|
delete this.submenus[item.index] |
||||||
|
}, |
||||||
|
|
||||||
|
handleClick() { |
||||||
|
const {rootMenu, disabled} = this |
||||||
|
if ( |
||||||
|
(rootMenu.menuTrigger === 'hover' && rootMenu.mode === 'horizontal') || |
||||||
|
(rootMenu.collapse && rootMenu.mode === 'vertical') || |
||||||
|
disabled |
||||||
|
) { |
||||||
|
return |
||||||
|
} |
||||||
|
this.dispatch('ElMenu', 'submenu-click', this) |
||||||
|
}, |
||||||
|
|
||||||
|
handleMouseenter(event, showTimeout = this.showTimeout) { |
||||||
|
|
||||||
|
if (!('ActiveXObject' in window) && event.type === 'focus' && !event.relatedTarget) { |
||||||
|
return |
||||||
|
} |
||||||
|
const {rootMenu, disabled} = this |
||||||
|
if ( |
||||||
|
(rootMenu.menuTrigger === 'click' && rootMenu.mode === 'horizontal') || |
||||||
|
(!rootMenu.collapse && rootMenu.mode === 'vertical') || |
||||||
|
disabled |
||||||
|
) { |
||||||
|
return |
||||||
|
} |
||||||
|
this.dispatch('ElSubmenu', 'mouse-enter-child') |
||||||
|
clearTimeout(this.timeout) |
||||||
|
this.timeout = setTimeout(() => { |
||||||
|
this.rootMenu.openMenu(this.index, this.indexPath) |
||||||
|
}, showTimeout) |
||||||
|
|
||||||
|
if (this.appendToBody) { |
||||||
|
this.$parent.$el.dispatchEvent(new MouseEvent('mouseenter')) |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
handleMouseleave(deepDispatch = false) { |
||||||
|
const {rootMenu} = this |
||||||
|
if ( |
||||||
|
(rootMenu.menuTrigger === 'click' && rootMenu.mode === 'horizontal') || |
||||||
|
(!rootMenu.collapse && rootMenu.mode === 'vertical') |
||||||
|
) { |
||||||
|
return |
||||||
|
} |
||||||
|
this.dispatch('ElSubmenu', 'mouse-leave-child') |
||||||
|
clearTimeout(this.timeout) |
||||||
|
this.timeout = setTimeout(() => { |
||||||
|
!this.mouseInChild && this.rootMenu.closeMenu(this.index) |
||||||
|
}, this.hideTimeout) |
||||||
|
|
||||||
|
if (this.appendToBody && deepDispatch) { |
||||||
|
if (this.$parent.$options.name === 'ElSubmenu') { |
||||||
|
this.$parent.handleMouseleave(true) |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
updatePlacement() { |
||||||
|
this.placement = this.mode === 'horizontal' && this.isFirstLevel |
||||||
|
? 'bottom-start' |
||||||
|
: 'right-start' |
||||||
|
}, |
||||||
|
|
||||||
|
initPopper() { |
||||||
|
this.referenceElm = this.$el |
||||||
|
this.popperElm = this.$refs.menu |
||||||
|
this.updatePlacement() |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
created() { |
||||||
|
this.$on('toggle-collapse', this.handleCollapseToggle) |
||||||
|
this.$on('mouse-enter-child', () => { |
||||||
|
this.mouseInChild = true |
||||||
|
clearTimeout(this.timeout) |
||||||
|
}) |
||||||
|
this.$on('mouse-leave-child', () => { |
||||||
|
this.mouseInChild = false |
||||||
|
clearTimeout(this.timeout) |
||||||
|
}) |
||||||
|
}, |
||||||
|
|
||||||
|
mounted() { |
||||||
|
this.parentMenu.addSubmenu(this) |
||||||
|
this.rootMenu.addSubmenu(this) |
||||||
|
this.initPopper() |
||||||
|
}, |
||||||
|
|
||||||
|
beforeDestroy() { |
||||||
|
this.parentMenu.removeSubmenu(this) |
||||||
|
this.rootMenu.removeSubmenu(this) |
||||||
|
}, |
||||||
|
|
||||||
|
render() { |
||||||
|
const {rootMenu, $slots} = this |
||||||
|
|
||||||
|
const popupMenu = ( |
||||||
|
<transition name={this.menuTransitionName}> |
||||||
|
<div |
||||||
|
ref="menu" |
||||||
|
v-show={this.opened} |
||||||
|
class={[`el-menu--${this.mode}`, this.popperClass]} |
||||||
|
on-mouseenter={e => this.handleMouseenter(e, 100)} |
||||||
|
on-mouseleave={() => this.handleMouseleave(true)} |
||||||
|
on-focus={e => this.handleMouseenter(e, 100)}> |
||||||
|
<ul class={['el-menu el-menu--popup', `el-menu--popup-${this.currentPlacement}`]}> |
||||||
|
{$slots.default} |
||||||
|
</ul> |
||||||
|
</div> |
||||||
|
</transition> |
||||||
|
) |
||||||
|
|
||||||
|
const inlineMenu = ( |
||||||
|
<el-collapse-transition> |
||||||
|
<ul v-show={this.opened} class="el-menu el-menu--inline"> |
||||||
|
{$slots.default} |
||||||
|
</ul> |
||||||
|
</el-collapse-transition> |
||||||
|
) |
||||||
|
|
||||||
|
const submenuTitleIcon = ( |
||||||
|
rootMenu.mode === 'horizontal' && this.isFirstLevel || |
||||||
|
rootMenu.mode === 'vertical' && !rootMenu.collapse |
||||||
|
) ? 'el-icon-arrow-down' : 'el-icon-arrow-right' |
||||||
|
|
||||||
|
return ( |
||||||
|
<li |
||||||
|
class={{ |
||||||
|
'el-submenu': true, |
||||||
|
'is-active': this.active, |
||||||
|
'is-opened': this.opened, |
||||||
|
'is-disabled': this.disabled |
||||||
|
}} |
||||||
|
on-mouseenter={this.handleMouseenter} |
||||||
|
on-mouseleave={() => this.handleMouseleave(false)} |
||||||
|
on-focus={this.handleMouseenter} |
||||||
|
> |
||||||
|
<div |
||||||
|
ref="submenu-title" |
||||||
|
class="el-submenu__title" |
||||||
|
style={this.paddingStyle} |
||||||
|
on-click={this.handleClick} |
||||||
|
> |
||||||
|
{$slots.title} |
||||||
|
<i class={['el-submenu__icon-arrow', submenuTitleIcon]}/> |
||||||
|
</div> |
||||||
|
{this.isMenuPopup ? popupMenu : inlineMenu} |
||||||
|
</li> |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style> |
||||||
|
|
||||||
|
</style> |
||||||
Loading…
Reference in new issue