ant-design-vue-pro
ant-design-vue-pro copied to clipboard
请问如何在展开一个菜单项时,不收缩其他菜单
Question (问题描述) 现在展开一个菜单项时,其他同级的菜单就被收缩了。
Describe the solution you'd like (你期待的是什么?) 在展开一个菜单项时,不收缩其他菜单
这个默认无法做到,之前 antd pro v3 的设计如此。
但你可以通过自定义渲染 menuRender 来自己渲染菜单。
一旦这么做,你需要自己控制 openKeys, selectedKeys
https://github.com/vueComponent/pro-layout/blob/master/examples/src/layouts/BasicLayout.vue#L13-L17
刚改了下 components/Menu/menu.js,可以实现。 在菜单meta里配置 "resident":true 即可。
import Menu from 'ant-design-vue/es/menu'
import Icon from 'ant-design-vue/es/icon'
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: [],
residentKeys: []
}
},
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 ? this.uniqueArr([latestOpenKey].concat(this.residentKeys)) : []
}
},
uniqueArr(array) {
var n = [];
for (var i = 0; i < array.length; i++) {
if (n.indexOf(array[i]) == -1) n.push(array[i]);
}
return n;
},
onSelect ({ item, key, selectedKeys }) {
this.selectedKeys = selectedKeys
this.$emit('select', { item, key, selectedKeys })
},
updateMenu () {
const that = this
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]
}
const openKeys = []
if (this.mode === 'inline') {
routes.forEach(item => {
openKeys.push(item.path)
if(item.meta.resident){
that.residentKeys.push(item.path)
that.residentKeys = that.uniqueArr(that.residentKeys)
}
})
}
this.collapsed ? (this.cachedOpenKeys = that.uniqueArr(openKeys.concat(that.residentKeys))) : (this.openKeys = that.uniqueArr(openKeys.concat(that.residentKeys)))
},
// render
renderItem (menu) {
if (!menu.hidden) {
return menu.children && !menu.hideChildrenInMenu ? this.renderSubMenu(menu) : this.renderMenuItem(menu)
}
return null
},
renderMenuItem (menu) {
const target = menu.meta.target || null
const CustomTag = target && 'a' || 'router-link'
const props = { to: { name: menu.name } }
const attrs = { href: menu.path, target: menu.meta.target }
if (menu.children && menu.hideChildrenInMenu) {
// 把有子菜单的 并且 父菜单是要隐藏子菜单的
// 都给子菜单增加一个 hidden 属性
// 用来给刷新页面时, selectedKeys 做控制用
menu.children.forEach(item => {
item.meta = Object.assign(item.meta, { hidden: true })
})
}
return (
<Menu.Item {...{ key: menu.path }}>
<CustomTag {...{ props, attrs }}>
{this.renderIcon(menu.meta.icon)}
<span>{menu.meta.title}</span>
</CustomTag>
</Menu.Item>
)
},
renderSubMenu (menu) {
const itemArr = []
if (!menu.hideChildrenInMenu) {
menu.children.forEach(item => itemArr.push(this.renderItem(item)))
}
return (
<Menu.SubMenu {...{ key: menu.path }}>
<span slot="title">
{this.renderIcon(menu.meta.icon)}
<span>{menu.meta.title}</span>
</span>
{itemArr}
</Menu.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 dynamicProps = {
props: {
mode: this.mode,
theme: this.theme,
openKeys: this.openKeys,
selectedKeys: this.selectedKeys
},
on: {
openChange: this.onOpenChange,
select: this.onSelect
}
}
const that = this
const menuTree = this.menu.map(item => {
if(!that.residentLoop && item.meta.resident){
that.residentKeys.push(item.path)
that.residentKeys = that.uniqueArr(that.residentKeys)
}
if (item.hidden) {
return null
}
return this.renderItem(item)
})
that.residentLoop = true
return (<Menu {...dynamicProps}>{menuTree}</Menu>)
}
}
我用的3.0版本,请问怎么升级vue-antd? "name": "vue-antd-pro", "version": "3.0.0",
哈哈,不知道,我还在用2.1.0
刚改了下 components/Menu/menu.js,可以实现。 在菜单meta里配置 "resident":true 即可。
import Menu from 'ant-design-vue/es/menu' import Icon from 'ant-design-vue/es/icon' 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: [], residentKeys: [] } }, 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 ? this.uniqueArr([latestOpenKey].concat(this.residentKeys)) : [] } }, uniqueArr(array) { var n = []; for (var i = 0; i < array.length; i++) { if (n.indexOf(array[i]) == -1) n.push(array[i]); } return n; }, onSelect ({ item, key, selectedKeys }) { this.selectedKeys = selectedKeys this.$emit('select', { item, key, selectedKeys }) }, updateMenu () { const that = this 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] } const openKeys = [] if (this.mode === 'inline') { routes.forEach(item => { openKeys.push(item.path) if(item.meta.resident){ that.residentKeys.push(item.path) that.residentKeys = that.uniqueArr(that.residentKeys) } }) } this.collapsed ? (this.cachedOpenKeys = that.uniqueArr(openKeys.concat(that.residentKeys))) : (this.openKeys = that.uniqueArr(openKeys.concat(that.residentKeys))) }, // render renderItem (menu) { if (!menu.hidden) { return menu.children && !menu.hideChildrenInMenu ? this.renderSubMenu(menu) : this.renderMenuItem(menu) } return null }, renderMenuItem (menu) { const target = menu.meta.target || null const CustomTag = target && 'a' || 'router-link' const props = { to: { name: menu.name } } const attrs = { href: menu.path, target: menu.meta.target } if (menu.children && menu.hideChildrenInMenu) { // 把有子菜单的 并且 父菜单是要隐藏子菜单的 // 都给子菜单增加一个 hidden 属性 // 用来给刷新页面时, selectedKeys 做控制用 menu.children.forEach(item => { item.meta = Object.assign(item.meta, { hidden: true }) }) } return ( <Menu.Item {...{ key: menu.path }}> <CustomTag {...{ props, attrs }}> {this.renderIcon(menu.meta.icon)} <span>{menu.meta.title}</span> </CustomTag> </Menu.Item> ) }, renderSubMenu (menu) { const itemArr = [] if (!menu.hideChildrenInMenu) { menu.children.forEach(item => itemArr.push(this.renderItem(item))) } return ( <Menu.SubMenu {...{ key: menu.path }}> <span slot="title"> {this.renderIcon(menu.meta.icon)} <span>{menu.meta.title}</span> </span> {itemArr} </Menu.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 dynamicProps = { props: { mode: this.mode, theme: this.theme, openKeys: this.openKeys, selectedKeys: this.selectedKeys }, on: { openChange: this.onOpenChange, select: this.onSelect } } const that = this const menuTree = this.menu.map(item => { if(!that.residentLoop && item.meta.resident){ that.residentKeys.push(item.path) that.residentKeys = that.uniqueArr(that.residentKeys) } if (item.hidden) { return null } return this.renderItem(item) }) that.residentLoop = true return (<Menu {...dynamicProps}>{menuTree}</Menu>) } }
老哥,我试了你写的代码,真的可以用,但是有个问题,当用户收缩一个默认展开的菜单后,点击任何一个菜单,收缩的菜单都会被打开,不能保持住用户点击的状态,当设置为顶部导航栏时问题更明显,请问这个问题怎么解决呢,感谢感谢
为什么当我有2层菜单的时候 即2个children的时候 发现收缩不了菜单了