|
|
|
@ -3,23 +3,31 @@ import Icon from 'ant-design-vue/es/icon'
|
|
|
|
|
|
|
|
|
|
const { Item, SubMenu } = Menu
|
|
|
|
|
|
|
|
|
|
export default {
|
|
|
|
|
// 导出一个默认对象,该对象是一个名为SMenu的组件
|
|
|
|
|
render (h)
|
|
|
|
|
export default {
|
|
|
|
|
// 组件的名称
|
|
|
|
|
name: 'SMenu',
|
|
|
|
|
// 组件的属性
|
|
|
|
|
props: {
|
|
|
|
|
// 菜单数据,类型为数组,必填
|
|
|
|
|
menu: {
|
|
|
|
|
type: Array,
|
|
|
|
|
required: true
|
|
|
|
|
},
|
|
|
|
|
// 主题,类型为字符串,非必填,默认值为'dark'
|
|
|
|
|
theme: {
|
|
|
|
|
type: String,
|
|
|
|
|
required: false,
|
|
|
|
|
default: 'dark'
|
|
|
|
|
},
|
|
|
|
|
// 模式,类型为字符串,非必填,默认值为'inline'
|
|
|
|
|
mode: {
|
|
|
|
|
type: String,
|
|
|
|
|
required: false,
|
|
|
|
|
default: 'inline'
|
|
|
|
|
},
|
|
|
|
|
// 是否折叠,类型为布尔值,非必填,默认值为false
|
|
|
|
|
collapsed: {
|
|
|
|
|
type: Boolean,
|
|
|
|
|
required: false,
|
|
|
|
@ -27,6 +35,7 @@ export default {
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
data () {
|
|
|
|
|
// 定义三个变量,openKeys用于存储当前打开的菜单项,selectedKeys用于存储当前选中的菜单项,cachedOpenKeys用于存储折叠前的菜单项
|
|
|
|
|
return {
|
|
|
|
|
openKeys: [],
|
|
|
|
|
selectedKeys: [],
|
|
|
|
@ -34,123 +43,183 @@ export default {
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
computed: {
|
|
|
|
|
// 计算属性,用于获取根菜单项的key
|
|
|
|
|
rootSubmenuKeys: vm => {
|
|
|
|
|
const keys = []
|
|
|
|
|
// 遍历menu数组,将每个菜单项的path添加到keys数组中
|
|
|
|
|
vm.menu.forEach(item => keys.push(item.path))
|
|
|
|
|
return keys
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
created () {
|
|
|
|
|
// 组件创建时,调用updateMenu方法
|
|
|
|
|
this.updateMenu()
|
|
|
|
|
},
|
|
|
|
|
watch: {
|
|
|
|
|
// 监听collapsed属性,当折叠状态改变时,更新openKeys和cachedOpenKeys
|
|
|
|
|
collapsed (val) {
|
|
|
|
|
if (val) {
|
|
|
|
|
// 如果折叠,将当前打开的菜单项保存到cachedOpenKeys中,并将openKeys置空
|
|
|
|
|
this.cachedOpenKeys = this.openKeys.concat()
|
|
|
|
|
this.openKeys = []
|
|
|
|
|
} else {
|
|
|
|
|
// 如果展开,将cachedOpenKeys赋值给openKeys
|
|
|
|
|
this.openKeys = this.cachedOpenKeys
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
// 监听$route属性,当路由改变时,调用updateMenu方法
|
|
|
|
|
$route: function () {
|
|
|
|
|
this.updateMenu()
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
methods: {
|
|
|
|
|
// 渲染图标
|
|
|
|
|
renderIcon: function (h, icon) {
|
|
|
|
|
// 如果图标为空或未定义,则返回null
|
|
|
|
|
if (icon === 'none' || icon === undefined) {
|
|
|
|
|
return null
|
|
|
|
|
}
|
|
|
|
|
// 定义props对象
|
|
|
|
|
const props = {}
|
|
|
|
|
// 如果图标是对象,则将图标赋值给props.component,否则将图标赋值给props.type
|
|
|
|
|
typeof (icon) === 'object' ? props.component = icon : props.type = icon
|
|
|
|
|
// 返回Icon组件,并传入props对象
|
|
|
|
|
return h(Icon, { props: { ...props } })
|
|
|
|
|
},
|
|
|
|
|
// 渲染菜单项
|
|
|
|
|
renderMenuItem: function (h, menu, pIndex, index) {
|
|
|
|
|
// 获取菜单的target属性,如果不存在,则赋值为null
|
|
|
|
|
const target = menu.meta.target || null
|
|
|
|
|
// 返回Item组件,并传入key属性和子组件
|
|
|
|
|
return h(Item, { key: menu.path ? menu.path : 'item_' + pIndex + '_' + index }, [
|
|
|
|
|
// 返回router-link组件,并传入to属性和target属性
|
|
|
|
|
h('router-link', { attrs: { to: { name: menu.name }, target: target } }, [
|
|
|
|
|
// 调用renderIcon方法,传入h和菜单的icon属性
|
|
|
|
|
this.renderIcon(h, menu.meta.icon),
|
|
|
|
|
// 返回span组件,并传入菜单的title属性
|
|
|
|
|
h('span', [menu.meta.title])
|
|
|
|
|
])
|
|
|
|
|
])
|
|
|
|
|
},
|
|
|
|
|
renderSubMenu: function (h, menu, pIndex, index) {
|
|
|
|
|
// 渲染子菜单
|
|
|
|
|
renderSubMenu: function (h, menu, pIndex, index) {
|
|
|
|
|
// 定义this2_为当前对象
|
|
|
|
|
const this2_ = this
|
|
|
|
|
// 定义subItem为子菜单项
|
|
|
|
|
const subItem = [h('span', { slot: 'title' }, [this.renderIcon(h, menu.meta.icon), h('span', [menu.meta.title])])]
|
|
|
|
|
// 定义itemArr为子菜单项数组
|
|
|
|
|
const itemArr = []
|
|
|
|
|
// 定义pIndex_为父菜单项索引
|
|
|
|
|
const pIndex_ = pIndex + '_' + index
|
|
|
|
|
// 打印menu
|
|
|
|
|
console.log('menu', menu)
|
|
|
|
|
// 如果菜单项不隐藏子菜单
|
|
|
|
|
if (!menu.hideChildrenInMenu) {
|
|
|
|
|
// 遍历子菜单项
|
|
|
|
|
menu.children.forEach(function (item, i) {
|
|
|
|
|
// 将子菜单项添加到itemArr数组中
|
|
|
|
|
itemArr.push(this2_.renderItem(h, item, pIndex_, i))
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
// 返回子菜单
|
|
|
|
|
return h(SubMenu, { key: menu.path ? menu.path : 'submenu_' + pIndex + '_' + index }, subItem.concat(itemArr))
|
|
|
|
|
},
|
|
|
|
|
// 渲染菜单项
|
|
|
|
|
renderItem: function (h, menu, pIndex, index) {
|
|
|
|
|
// 如果菜单项不隐藏
|
|
|
|
|
if (!menu.hidden) {
|
|
|
|
|
// 如果菜单项有子菜单且不隐藏子菜单,则渲染子菜单
|
|
|
|
|
return menu.children && !menu.hideChildrenInMenu
|
|
|
|
|
? this.renderSubMenu(h, menu, pIndex, index)
|
|
|
|
|
// 否则渲染菜单项
|
|
|
|
|
: this.renderMenuItem(h, menu, pIndex, index)
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
renderMenu: function (h, menuTree) {
|
|
|
|
|
// 渲染菜单
|
|
|
|
|
renderMenu: function (h, menuTree) {
|
|
|
|
|
// 定义this2_为当前对象
|
|
|
|
|
const this2_ = this
|
|
|
|
|
// 定义menuArr为空数组
|
|
|
|
|
const menuArr = []
|
|
|
|
|
// 遍历menuTree
|
|
|
|
|
menuTree.forEach(function (menu, i) {
|
|
|
|
|
// 如果menu不隐藏
|
|
|
|
|
if (!menu.hidden) {
|
|
|
|
|
// 将renderItem方法返回的值添加到menuArr数组中
|
|
|
|
|
menuArr.push(this2_.renderItem(h, menu, '0', i))
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
// 返回menuArr数组
|
|
|
|
|
return menuArr
|
|
|
|
|
},
|
|
|
|
|
// 打开菜单
|
|
|
|
|
onOpenChange (openKeys) {
|
|
|
|
|
// 定义latestOpenKey为openKeys中不包含在this.openKeys中的值
|
|
|
|
|
const latestOpenKey = openKeys.find(key => !this.openKeys.includes(key))
|
|
|
|
|
// 如果latestOpenKey不包含在rootSubmenuKeys中
|
|
|
|
|
if (!this.rootSubmenuKeys.includes(latestOpenKey)) {
|
|
|
|
|
// 将openKeys赋值给this.openKeys
|
|
|
|
|
this.openKeys = openKeys
|
|
|
|
|
} else {
|
|
|
|
|
// 如果latestOpenKey存在,将latestOpenKey赋值给this.openKeys
|
|
|
|
|
// 否则将this.openKeys赋值为空数组
|
|
|
|
|
this.openKeys = latestOpenKey ? [latestOpenKey] : []
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
updateMenu () {
|
|
|
|
|
// 更新菜单
|
|
|
|
|
updateMenu () {
|
|
|
|
|
// 获取当前路由匹配的路径
|
|
|
|
|
const routes = this.$route.matched.concat()
|
|
|
|
|
|
|
|
|
|
// 如果路由长度大于等于4且meta中hidden属性为true
|
|
|
|
|
if (routes.length >= 4 && this.$route.meta.hidden) {
|
|
|
|
|
// 移除最后一个路径
|
|
|
|
|
routes.pop()
|
|
|
|
|
// 设置选中的路径为倒数第二个路径
|
|
|
|
|
this.selectedKeys = [routes[2].path]
|
|
|
|
|
} else {
|
|
|
|
|
// 否则设置选中的路径为最后一个路径
|
|
|
|
|
this.selectedKeys = [routes.pop().path]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 定义打开的路径
|
|
|
|
|
const openKeys = []
|
|
|
|
|
// 如果模式为inline
|
|
|
|
|
if (this.mode === 'inline') {
|
|
|
|
|
// 遍历路径
|
|
|
|
|
routes.forEach(item => {
|
|
|
|
|
// 将路径添加到打开的路径中
|
|
|
|
|
openKeys.push(item.path)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.collapsed ? (this.cachedOpenKeys = openKeys) : (this.openKeys = openKeys)
|
|
|
|
|
},
|
|
|
|
|
this:collapsed ? (this.cachedOpenKeys = openKeys) : (this.openKeys = openKeys)
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
render (h) {
|
|
|
|
|
};{
|
|
|
|
|
// 使用h函数渲染Menu组件
|
|
|
|
|
return h(
|
|
|
|
|
Menu,
|
|
|
|
|
{
|
|
|
|
|
// 设置Menu组件的props属性
|
|
|
|
|
props: {
|
|
|
|
|
theme: this.$props.theme,
|
|
|
|
|
mode: this.$props.mode,
|
|
|
|
|
openKeys: this.openKeys,
|
|
|
|
|
selectedKeys: this.selectedKeys
|
|
|
|
|
},
|
|
|
|
|
// 设置Menu组件的事件
|
|
|
|
|
on: {
|
|
|
|
|
openChange: this.onOpenChange,
|
|
|
|
|
select: obj => {
|
|
|
|
|
// 设置selectedKeys属性
|
|
|
|
|
this.selectedKeys = obj.selectedKeys
|
|
|
|
|
// 触发select事件
|
|
|
|
|
this.$emit('select', obj)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
// 渲染菜单
|
|
|
|
|
this.renderMenu(h, this.menu)
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|