123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- 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>
- )
- }
- }
|