You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
184 lines
5.0 KiB
184 lines
5.0 KiB
import PropTypes from '../_util/vue-types'
|
|
import { Provider, create } from '../_util/store'
|
|
import { default as SubPopupMenu, getActiveKey } from './SubPopupMenu'
|
|
import BaseMixin from '../_util/BaseMixin'
|
|
import hasProp, { getOptionProps, getComponentFromProp, filterEmpty } from '../_util/props-util'
|
|
import commonPropsType from './commonPropsType'
|
|
|
|
const Menu = {
|
|
name: 'Menu',
|
|
props: {
|
|
...commonPropsType,
|
|
selectable: PropTypes.bool.def(true),
|
|
},
|
|
mixins: [BaseMixin],
|
|
|
|
data () {
|
|
const props = getOptionProps(this)
|
|
let selectedKeys = props.defaultSelectedKeys
|
|
let openKeys = props.defaultOpenKeys
|
|
if ('selectedKeys' in props) {
|
|
selectedKeys = props.selectedKeys || []
|
|
}
|
|
if ('openKeys' in props) {
|
|
openKeys = props.openKeys || []
|
|
}
|
|
|
|
this.store = create({
|
|
selectedKeys,
|
|
openKeys,
|
|
activeKey: { '0-menu-': getActiveKey({ ...props, children: this.$slots.default || [] }, props.activeKey) },
|
|
})
|
|
|
|
// this.isRootMenu = true // 声明在props上
|
|
return {}
|
|
},
|
|
mounted () {
|
|
this.updateMiniStore()
|
|
},
|
|
updated () {
|
|
this.updateMiniStore()
|
|
},
|
|
methods: {
|
|
|
|
onSelect (selectInfo) {
|
|
const props = this.$props
|
|
if (props.selectable) {
|
|
// root menu
|
|
let selectedKeys = this.store.getState().selectedKeys
|
|
const selectedKey = selectInfo.key
|
|
if (props.multiple) {
|
|
selectedKeys = selectedKeys.concat([selectedKey])
|
|
} else {
|
|
selectedKeys = [selectedKey]
|
|
}
|
|
if (!hasProp(this, 'selectedKeys')) {
|
|
this.store.setState({
|
|
selectedKeys,
|
|
})
|
|
}
|
|
this.__emit('select', {
|
|
...selectInfo,
|
|
selectedKeys: selectedKeys,
|
|
})
|
|
}
|
|
},
|
|
|
|
onClick (e) {
|
|
this.__emit('click', e)
|
|
},
|
|
// onKeyDown needs to be exposed as a instance method
|
|
// e.g., in rc-select, we need to navigate menu item while
|
|
// current active item is rc-select input box rather than the menu itself
|
|
onKeyDown (e, callback) {
|
|
this.$refs.innerMenu.getWrappedInstance().onKeyDown(e, callback)
|
|
},
|
|
onOpenChange (event) {
|
|
const openKeys = this.store.getState().openKeys.concat()
|
|
let changed = false
|
|
const processSingle = (e) => {
|
|
let oneChanged = false
|
|
if (e.open) {
|
|
oneChanged = openKeys.indexOf(e.key) === -1
|
|
if (oneChanged) {
|
|
openKeys.push(e.key)
|
|
}
|
|
} else {
|
|
const index = openKeys.indexOf(e.key)
|
|
oneChanged = index !== -1
|
|
if (oneChanged) {
|
|
openKeys.splice(index, 1)
|
|
}
|
|
}
|
|
changed = changed || oneChanged
|
|
}
|
|
if (Array.isArray(event)) {
|
|
// batch change call
|
|
event.forEach(processSingle)
|
|
} else {
|
|
processSingle(event)
|
|
}
|
|
if (changed) {
|
|
if (!hasProp(this, 'openKeys')) {
|
|
this.store.setState({ openKeys })
|
|
}
|
|
this.__emit('openChange', openKeys)
|
|
}
|
|
},
|
|
|
|
onDeselect (selectInfo) {
|
|
const props = this.$props
|
|
if (props.selectable) {
|
|
const selectedKeys = this.store.getState().selectedKeys.concat()
|
|
const selectedKey = selectInfo.key
|
|
const index = selectedKeys.indexOf(selectedKey)
|
|
if (index !== -1) {
|
|
selectedKeys.splice(index, 1)
|
|
}
|
|
if (!hasProp(this, 'selectedKeys')) {
|
|
this.store.setState({
|
|
selectedKeys,
|
|
})
|
|
}
|
|
this.__emit('deselect', {
|
|
...selectInfo,
|
|
selectedKeys: selectedKeys,
|
|
})
|
|
}
|
|
},
|
|
|
|
getOpenTransitionName () {
|
|
const props = this.$props
|
|
let transitionName = props.openTransitionName
|
|
const animationName = props.openAnimation
|
|
if (!transitionName && typeof animationName === 'string') {
|
|
transitionName = `${props.prefixCls}-open-${animationName}`
|
|
}
|
|
return transitionName
|
|
},
|
|
updateMiniStore () {
|
|
const props = getOptionProps(this)
|
|
if ('selectedKeys' in props) {
|
|
this.store.setState({
|
|
selectedKeys: props.selectedKeys || [],
|
|
})
|
|
}
|
|
if ('openKeys' in props) {
|
|
this.store.setState({
|
|
openKeys: props.openKeys || [],
|
|
})
|
|
}
|
|
},
|
|
},
|
|
|
|
render () {
|
|
const props = getOptionProps(this)
|
|
const subPopupMenuProps = {
|
|
props: {
|
|
...props,
|
|
itemIcon: getComponentFromProp(this, 'itemIcon', props),
|
|
expandIcon: getComponentFromProp(this, 'expandIcon', props),
|
|
overflowedIndicator: getComponentFromProp(this, 'overflowedIndicator', props),
|
|
openTransitionName: this.getOpenTransitionName(),
|
|
parentMenu: this,
|
|
children: filterEmpty(this.$slots.default || []),
|
|
},
|
|
class: `${props.prefixCls}-root`,
|
|
on: {
|
|
click: this.onClick,
|
|
openChange: this.onOpenChange,
|
|
deselect: this.onDeselect,
|
|
select: this.onSelect,
|
|
},
|
|
ref: 'innerMenu',
|
|
}
|
|
return (
|
|
<Provider store={this.store}>
|
|
<SubPopupMenu {...subPopupMenuProps} />
|
|
</Provider>
|
|
)
|
|
},
|
|
}
|
|
export default Menu
|
|
|