// menu.js
export default [
{
title: '住院病人病情评估表',
key: '0',
meta: '',
}, {
title: '医护各类常用表格',
key: '1',
meta: '',
children: [{
title: '医疗安全不良事件报告表',
key: '1-0',
meta: ''
}, {
title: '科室不良事件记录表',
key: '1-1',
meta: ''
}, {
title: '病危告知书',
key: '1-2',
meta: '',
children: [{
title: 'A类病危通知书',
key: '1-2-0',
meta: ''
}, {
title: 'B类病危通知书',
key: '1-2-1',
meta: ''
}, {
title: 'C类病危通知书',
key: '1-2-2',
meta: '',
}]
}]
}, {
title: '全国通用标准模板',
key: '2',
meta: '',
children: [{
title: '出院记录模板',
key: '2-0',
meta: ''
},{
title: '手术记录模板',
key: '2-1',
meta: ''
},{
title: '手术知情同意书',
key: '2-2',
meta: ''
}]
}
]
注:菜单项的 meta
字段可以是任意数据类型,建议是对象,预留这个字段的目的是为了让菜单项携带其他需要的数据。
有些项目中的图片路径、样式等等,我没有删除,大家自行过滤。
<template>
<div
class="menu-item"
:class="openList.includes(menu.key) ? 'open-menu' : ''"
>
<div
class="menu-title"
@click="handleTab(menu)"
:class="menu.key === current.key ? 'active-menu' : ''"
>
<i
class="icon"
:class="openList.includes(menu.key) ? 'el-icon-folder-remove' : 'el-icon-folder-add'"
:style="{opacity: menu.children ? '1' : '0'}"
>i>
<img src="../../assets/imgs/template-list/icon.png" alt="">
<span>{{ menu.title }}span>
div>
<div v-if="menu.children" class="sub-menu">
<menu-item
v-for="subItem in menu.children"
:currentMenu="currentMenu"
:key="subItem.key"
:menu="subItem"
:tap-menu="tapMenu"
:tap-submenu="tapSubmenu"
/>
div>
div>
template>
<script>
export default {
name: "menu-item",
props: ['menu', 'currentMenu', 'tapMenu', 'tapSubmenu'],
data() {
return {
openList: ['1']
}
},
computed: {
current() {
return this.$store.state.templateEdit.currentTemplateMenu;
}
},
methods: {
handleTab(menu) {
if(menu.children) {
// 点击父级菜单,展开或合并子菜单
const index = this.openList.indexOf(menu.key);
if(index < 0) this.openList.push(menu.key);
else this.openList.splice(index, 1);
// 点击某个父级菜单的回调,可以在调用时传入
this.tapMenu && this.tapMenu(menu);
} else {
// 点击无子级的某个菜单,代表选中了某个菜单并且要执行动作,示范中向 store 提交了一个设置当前菜单值的事件
this.$store.commit('set_template_menu', menu);
// 点击无子级的某个菜单的回调
this.tapSubmenu && this.tapSubmenu(menu);
}
}
}
}
script>
<style scoped lang="less">
.menu-item {
color: #999;
font-size: 12px;
* {
vertical-align: middle;
}
img {
width: 12px;
margin-right: 5px;
}
.icon {
margin-right: 5px;
}
.sub-menu {
padding-left: 15px;
color: #999;
height: 0;
overflow-y: hidden;
}
.menu-title {
padding: 5px 0;
cursor: pointer;
:hover {
color: #333;
}
}
.active-menu {
background: #f7f8fd;
}
}
.menu-item.open-menu {
>.sub-menu {
height: auto;
}
}
style>
<template>
<div class="template-menu">
<MenuItem
v-for="item in menuList"
:menu="item"
:key="item.key"
:tap-menu="tapMenu"
:tap-submenu="tapSubmenu"
/>
div>
template>
<script>
import MenuItem from './menu-item.vue'
import menuList from './menu.js'
export default {
name: "template-menu",
components: {
MenuItem
},
data() {
return {
menuList
}
},
methods: {
tapMenu(menu) {
console.log(menu);
},
tapSubmenu(menu) {
console.log(menu);
}
}
}
script>
之所以要将当前被选中的菜单项保留在 store
中,是因为菜单项在递归的过程中,形成了类似于闭包的嵌套上下文环境,数据各自独立,要整体使用并查看选中效果时,无法通过 $emit
或父级的数据确定选中项,所以需要借助 store
。
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
export default new Vuex.Store({
state: {
templateEdit: {
currentTemplateMenu: {}
}
},
mutations: {
set_template_menu(state, v) {
state.templateEdit.currentTemplateMenu = v;
}
}
})