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: { ...this.$listeners, click: this.onClick, openChange: this.onOpenChange, deselect: this.onDeselect, select: this.onSelect, }, ref: 'innerMenu', }; return ( ); }, }; export default Menu;