一、下载elementUI源码并运行
二、修改element源码实现自己的导航栏菜单
1、实现需求
实现大概效果,鼠标悬浮到以及目录是,同时出现二级目录和三级目录
2、实现思路
1、 首选调整样式所有菜单都显示在父级菜单的下面
2、第二级菜单横着排列,其他竖向排列
3、为子菜单设置固定宽度和都显示出来
<style>
.el-menu li[role="menuitem"]:not(li[tabindex="0"]) {
width:200px;
}
.el-menu li[role="menuitem"]:not(li[tabindex="0"]) .el-menu--horizontal {
display: block !important;
}
</style>
//在saber 项目中的样式代码为
.el-menu .menu-wrapper:not(.menu-wrapper[tabindex="0"]) li[role="menuitem"] {
width: 200px;
}
.el-menu .menu-wrapper:not(.menu-wrapper[tabindex="0"]) .el-menu--horizontal {
display: block !important;
}
4、判断鼠标悬浮是菜单的第几级,如果是一级,则悬浮展示,其他级菜单不做任何处理
3、源代码 = package/menu/src/submenu
<script>
import ElCollapseTransition from "element-ui/src/transitions/collapse-transition";
import menuMixin from "./menu-mixin";
import Emitter from "element-ui/src/mixins/emitter";
import Popper from "element-ui/src/utils/vue-popper";
const poperMixins = {
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, poperMixins],
components: { ElCollapseTransition },
props: {
index: {
type: String,
required: true
},
showTimeout: {
type: Number,
default: 300
},
hideTimeout: {
type: Number,
default: 300
},
popperClass: String,
disabled: Boolean,
popperAppendToBody: {
type: Boolean,
default: undefined
}
},
data() {
return {
popperJS: null,
timeout: null,
items: {},
submenus: {},
mouseInChild: false
};
},
watch: {
opened(val) {
if (this.isMenuPopup) {
this.$nextTick(_ => {
this.updatePopper();
});
}
}
},
computed: {
// popper option
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.indexOf(this.index) > -1;
},
active() {
let isActive = false;
const submenus = this.submenus;
const items = this.items;
Object.keys(items).forEach(index => {
if (items[index].active) {
isActive = true;
}
});
Object.keys(submenus).forEach(index => {
if (submenus[index].active) {
isActive = true;
}
});
return isActive;
},
hoverBackground() {
return this.rootMenu.hoverBackground;
},
backgroundColor() {
return this.rootMenu.backgroundColor || "";
},
activeTextColor() {
return this.rootMenu.activeTextColor || "";
},
textColor() {
return this.rootMenu.textColor || "";
},
mode() {
return this.rootMenu.mode;
},
isMenuPopup() {
return this.rootMenu.isMenuPopup;
},
titleStyle() {
if (this.mode !== "horizontal") {
return {
color: this.textColor
};
}
return {
borderBottomColor: this.active
? this.rootMenu.activeTextColor
? this.activeTextColor
: ""
: "transparent",
color: this.active ? this.activeTextColor : this.textColor
};
},
isFirstLevel() {
let isFirstLevel = true;
let parent = this.$parent;
while (parent && parent !== this.rootMenu) {
if (
["ElSubmenu", "ElMenuItemGroup"].indexOf(
parent.$options.componentName
) > -1
) {
isFirstLevel = false;
break;
} else {
parent = parent.$parent;
}
}
return isFirstLevel;
}
},
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) {
//menubar 说明是第一级菜单,一级菜单悬浮展示,其他菜单悬浮不做处理
let menubar = event.target.parentElement.parentElement.outerHTML.indexOf(
"menubar"
);
if (menubar == -1) return;
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);
}
}
},
handleTitleMouseenter() {
if (this.mode === "horizontal" && !this.rootMenu.backgroundColor) return;
const title = this.$refs["submenu-title"];
title && (title.style.backgroundColor = this.rootMenu.hoverBackground);
},
handleTitleMouseleave() {
if (this.mode === "horizontal" && !this.rootMenu.backgroundColor) return;
const title = this.$refs["submenu-title"];
title &&
(title.style.backgroundColor = this.rootMenu.backgroundColor || "");
},
updatePlacement() {
this.currentPlacement =
this.mode === "horizontal" && this.isFirstLevel
? "bottom-start"
: "bottom-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(h) {
const {
active,
opened,
paddingStyle,
titleStyle,
backgroundColor,
rootMenu,
currentPlacement,
menuTransitionName,
mode,
disabled,
popperClass,
$slots,
isFirstLevel
} = this;
const popupMenu = (
<transition name={menuTransitionName}>
<div
ref="menu"
v-show={opened}
class={[`el-menu--${mode}`, popperClass]}
on-mouseenter={$event => this.handleMouseenter($event, 100)}
on-mouseleave={() => this.handleMouseleave(true)}
on-focus={$event => this.handleMouseenter($event, 100)}
>
<ul
role="menu"
class={[
"el-menu el-menu--popup",
`el-menu--popup-${currentPlacement}`
]}
style={{
backgroundColor: rootMenu.backgroundColor,
display: isFirstLevel ? "flex" : "block" || ""
}}
>
{$slots.default}
</ul>
</div>
</transition>
);
const inlineMenu = (
<el-collapse-transition>
<ul
role="menu"
class="el-menu el-menu--inline"
v-show={opened}
style={{ backgroundColor: rootMenu.backgroundColor || "" }}
>
{$slots.default}
</ul>
</el-collapse-transition>
);
const submenuTitleIcon =
(rootMenu.mode === "horizontal" && isFirstLevel) ||
(rootMenu.mode === "vertical" && !rootMenu.collapse)
? "el-icon-arrow-down"
: "el-icon-arrow-right";
return (
<li
class={{
"el-submenu": true,
"is-active": active,
"is-opened": opened,
"is-disabled": disabled
}}
role="menuitem"
aria-haspopup="true"
style="width:200px"
aria-expanded={opened}
on-mouseenter={this.handleMouseenter}
on-mouseleave={() => this.handleMouseleave(false)}
on-focus={this.handleMouseenter}
>
<div
class="el-submenu__title"
ref="submenu-title"
on-click={this.handleClick}
on-mouseenter={this.handleTitleMouseenter}
on-mouseleave={this.handleTitleMouseleave}
style={[paddingStyle, titleStyle, { backgroundColor }]}
>
{$slots.title}
<i class={["el-submenu__icon-arrow", submenuTitleIcon]} />
</div>
{this.isMenuPopup ? popupMenu : inlineMenu}
</li>
);
}
};
</script>
<style>
.el-menu li[tabindex="0"] {
width: auto !important;
}
.el-menu li[role="menuitem"]:not(li[tabindex="0"]) .el-menu--horizontal {
display: block !important;
}
</style>