import Menu from 'ant-design-vue/es/menu' import Icon from 'ant-design-vue/es/icon' const {Item, SubMenu} = Menu export default { name: 'SMenu', props: { menu: { type: Array, required: true }, theme: { type: String, required: false, default: 'dark' }, mode: { type: String, required: false, default: 'inline' }, collapsed: { type: Boolean, required: false, default: false } }, data() { return { openKeys: [], selectedKeys: [], cachedOpenKeys: [] } }, computed: { rootSubmenuKeys: vm => { const keys = [] vm.menu.forEach(item => keys.push(item.path)) return keys } }, mounted() { this.updateMenu() }, watch: { collapsed(val) { if (val) { this.cachedOpenKeys = this.openKeys.concat() this.openKeys = [] } else { this.openKeys = this.cachedOpenKeys } }, $route: function () { this.updateMenu() } }, methods: { // select menu item onOpenChange(openKeys) { // 在水平模式下时执行,并且不再执行后续 if (this.mode === 'horizontal') { this.openKeys = openKeys return } // 非水平模式时 const latestOpenKey = openKeys.find(key => !this.openKeys.includes(key)) if (!this.rootSubmenuKeys.includes(latestOpenKey)) { this.openKeys = openKeys } else { this.openKeys = latestOpenKey ? [latestOpenKey] : [] } }, updateMenu() { const routes = this.$route.matched.concat() const {hidden} = this.$route.meta if (routes.length >= 3 && hidden) { routes.pop() this.selectedKeys = [routes[routes.length - 1].path] } else { this.selectedKeys = [routes.pop().path] } let openKeys = [] if (this.mode === 'inline') { routes.forEach(item => { openKeys.push(item.path) }) } // update-begin-author:sunjianlei date:20210409 for: 修复动态功能测试菜单、带参数菜单标题错误、展开错误的问题 // 包含冒号的是动态菜单 if (this.selectedKeys[0].includes(':')) { let selectedKey = this.$route.fullPath this.selectedKeys = [selectedKey] let newOpenKeys = [] this.fullOpenKeys(this.menu, selectedKey, newOpenKeys) if (newOpenKeys.length > 0) { openKeys = newOpenKeys.reverse() } } // update-end-author:sunjianlei date:20210409 for: 修复动态功能测试菜单、带参数菜单标题错误、展开错误的问题 //update-begin-author:taoyan date:20190510 for:online表单菜单点击展开的一级目录不对 if (!this.selectedKeys || this.selectedKeys[0].indexOf(":") < 0) { this.collapsed ? (this.cachedOpenKeys = openKeys) : (this.openKeys = openKeys) } //update-end-author:taoyan date:20190510 for:online表单菜单点击展开的一级目录不对 }, // update-begin-author:sunjianlei date:20210409 for: 修复动态功能测试菜单、带参数菜单标题错误、展开错误的问题 // 递归查找当前选中的菜单和父级菜单,填充openKeys fullOpenKeys(menus, selectedKey, openKeys) { for (let item of menus) { if (item.path === selectedKey) { openKeys.push(item.path) this.$emit('updateMenuTitle', item) return true } else if (Array.isArray(item.children)) { if (this.fullOpenKeys(item.children, selectedKey, openKeys)) { openKeys.push(item.path) return true } } } }, // update-end-author:sunjianlei date:20210409 for: 修复动态功能测试菜单、带参数菜单标题错误、展开错误的问题 // render renderItem(menu) { if (!menu.hidden) { return menu.children && !menu.alwaysShow ? this.renderSubMenu(menu) : this.renderMenuItem(menu) } return null }, renderMenuItem(menu) { const target = menu.meta.target || null const tag = target && 'a' || 'router-link' let props = {to: {name: menu.name}} if (menu.route && menu.route === '0') { props = {to: {path: menu.path}} } const attrs = {href: menu.path, target: menu.meta.target} if (menu.children && menu.alwaysShow) { // 把有子菜单的 并且 父菜单是要隐藏子菜单的 // 都给子菜单增加一个 hidden 属性 // 用来给刷新页面时, selectedKeys 做控制用 menu.children.forEach(item => { item.meta = Object.assign(item.meta, {hidden: true}) }) } return ( <Item {...{key: menu.path}}> <tag {...{props, attrs}}> {this.renderIcon(menu.meta.icon)} <span>{menu.meta.title}</span> </tag> </Item> ) }, renderSubMenu(menu) { const itemArr = [] if (!menu.alwaysShow) { menu.children.forEach(item => itemArr.push(this.renderItem(item))) } return ( <SubMenu {...{key: menu.path}}> <span slot="title"> {this.renderIcon(menu.meta.icon)} <span>{menu.meta.title}</span> </span> {itemArr} </SubMenu> ) }, renderIcon(icon) { if (icon === 'none' || icon === undefined) { return null } const props = {} typeof (icon) === 'object' ? props.component = icon : props.type = icon return ( <Icon {...{props}}/> ) } }, render() { const {mode, theme, menu} = this const props = { mode: mode, theme: theme, openKeys: this.openKeys } const on = { select: obj => { this.selectedKeys = obj.selectedKeys this.$emit('select', obj) }, openChange: this.onOpenChange } const menuTree = menu.map(item => { if (item.hidden) { return null } return this.renderItem(item) }) // {...{ props, on: on }} return ( <Menu vModel={this.selectedKeys} {...{props, on: on}}> {menuTree} </Menu> ) } }