update menu

pull/9/head
tangjinzhou 2018-01-16 19:15:07 +08:00
parent 6e3caa6011
commit 94b420dbc3
12 changed files with 147 additions and 75 deletions

View File

@ -2,13 +2,8 @@ import warning from 'warning'
const warned = {} const warned = {}
export default (valid, message, throwError) => { export default (valid, message, throwError) => {
if (process.env.NODE_ENV !== 'production') { if (!valid && !warned[message]) {
if (!valid && !warned[message]) { warning(false, message)
warning(false, message) warned[message] = true
warned[message] = true
if (throwError) {
throw Error(message)
}
}
} }
} }

View File

@ -20,6 +20,7 @@ export default {
}, },
inject: { inject: {
checkboxGroupContext: { default: null }, checkboxGroupContext: { default: null },
test: { default: null },
}, },
data () { data () {
const { checkboxGroupContext, checked, defaultChecked, value } = this const { checkboxGroupContext, checked, defaultChecked, value } = this

View File

@ -33,3 +33,5 @@ export { default as Breadcrumb } from './breadcrumb'
export { default as Popover } from './popover' export { default as Popover } from './popover'
export { default as Popconfirm } from './popconfirm' export { default as Popconfirm } from './popconfirm'
export { default as Menu } from './menu'

View File

@ -0,0 +1,58 @@
<template>
<div>
<Menu
@click="handleClick"
:selectedKeys="[current]"
mode="horizontal"
>
<MenuItem key="mail">
<Icon type="mail" />Navigation One
</MenuItem>
<MenuItem key="app" disabled>
<Icon type="appstore" />Navigation Two
</MenuItem>
<SubMenu>
<template slot="title">
<span><Icon type="setting" />Navigation Three - Submenu</span>
</template>
<MenuItemGroup title="Item 1">
<MenuItem key="setting:1">Option 1</MenuItem>
<MenuItem key="setting:2">Option 2</MenuItem>
</MenuItemGroup>
<MenuItemGroup title="Item 2">
<MenuItem key="setting:3">Option 3</MenuItem>
<MenuItem key="setting:4">Option 4</MenuItem>
</MenuItemGroup>
</SubMenu>
<MenuItem key="alipay">
<a href="https://ant.design" target="_blank" rel="noopener noreferrer">Navigation Four - Link</a>
</MenuItem>
</Menu>
</div>
</template>
<script>
import { Menu, Icon } from 'antd'
const SubMenu = Menu.SubMenu
const MenuItemGroup = Menu.ItemGroup
const MenuItem = Menu.Item
export default {
data () {
return {
current: 'mail',
}
},
methods: {
handleClick (e) {
this.current = e.key
},
},
components: {
Menu,
Icon,
SubMenu,
MenuItemGroup,
MenuItem,
},
}
</script>

View File

@ -1 +0,0 @@
module.exports = require('./src/')

View File

@ -1,6 +1,8 @@
<script> <script>
import RcMenu, { Divider, ItemGroup, SubMenu } from '../src' import omit from 'omit.js'
import PropTypes from '../util/vue-types' import cloneDeep from 'lodash.clonedeep'
import RcMenu, { Divider, ItemGroup, SubMenu } from './src'
import PropTypes from '../_util/vue-types'
import animation from '../_util/openAnimation' import animation from '../_util/openAnimation'
import warning from '../_util/warning' import warning from '../_util/warning'
import Item from './MenuItem' import Item from './MenuItem'
@ -13,7 +15,7 @@ export const menuProps = {
theme: PropTypes.oneOf(['light', 'dark']).def('light'), theme: PropTypes.oneOf(['light', 'dark']).def('light'),
mode: MenuMode, mode: MenuMode,
selectable: PropTypes.bool, selectable: PropTypes.bool,
selectedKeys: PropTypes.array, selectedKeys: PropTypes.arrayOf(PropTypes.string),
defaultSelectedKeys: PropTypes.array, defaultSelectedKeys: PropTypes.array,
openKeys: PropTypes.array, openKeys: PropTypes.array,
defaultOpenKeys: PropTypes.array, defaultOpenKeys: PropTypes.array,
@ -43,8 +45,39 @@ export default {
}, },
mixins: [BaseMixin], mixins: [BaseMixin],
inject: { inject: {
siderCollapsed: { default: undefined }, layoutContext: { default: {}},
collapsedWidth: { default: undefined }, },
watch: {
'$props': {
handler: function (nextProps) {
},
deep: true,
},
},
beforeUpdate () {
const { preProps, $props: nextProps, layoutContext, preLayoutContext = {}} = this
const { prefixCls } = preProps
if (preProps.mode === 'inline' &&
nextProps.mode !== 'inline') {
this.switchModeFromInline = true
}
if (hasProp(this, 'openKeys')) {
this.setState({ sOpenKeys: nextProps.openKeys })
return
}
if ((nextProps.inlineCollapsed && !preProps.inlineCollapsed) ||
(layoutContext.siderCollapsed && !preLayoutContext.siderCollapsed)) {
this.switchModeFromInline =
!!this.state.openKeys.length && !!this.$el.querySelectorAll(`.${prefixCls}-submenu-open`).length
this.inlineOpenKeys = this.state.openKeys
this.setState({ sOpenKeys: [] })
}
if ((!nextProps.inlineCollapsed && preProps.inlineCollapsed) ||
(!layoutContext.siderCollapsed && preLayoutContext.siderCollapsed)) {
this.setState({ sOpenKeys: this.inlineOpenKeys })
this.inlineOpenKeys = []
}
}, },
data () { data () {
const props = this.$props const props = this.$props
@ -68,22 +101,15 @@ export default {
methods: { methods: {
handleClick (e) { handleClick (e) {
this.handleOpenChange([]) this.handleOpenChange([])
const { onClick } = this.props this.$emit('click', e)
if (onClick) {
onClick(e)
}
}, },
handleOpenChange (openKeys) { handleOpenChange (openKeys) {
this.setOpenKeys(openKeys) this.setOpenKeys(openKeys)
this.$emit('openChange', openKeys)
const { onOpenChange } = this.props
if (onOpenChange) {
onOpenChange(openKeys)
}
}, },
setOpenKeys (openKeys) { setOpenKeys (openKeys) {
if (!('openKeys' in this.props)) { if (!hasProp(this, 'openKeys')) {
this.setState({ openKeys }) this.setState({ sOpenKeys: openKeys })
} }
}, },
getRealMenuMode () { getRealMenuMode () {
@ -91,18 +117,18 @@ export default {
if (this.switchModeFromInline && inlineCollapsed) { if (this.switchModeFromInline && inlineCollapsed) {
return 'inline' return 'inline'
} }
const { mode } = this.props const { mode } = this.$props
return inlineCollapsed ? 'vertical' : mode return inlineCollapsed ? 'vertical' : mode
}, },
getInlineCollapsed () { getInlineCollapsed () {
const { inlineCollapsed } = this.props const { inlineCollapsed } = this.$props
if (this.context.siderCollapsed !== undefined) { if (this.layoutContext.siderCollapsed !== undefined) {
return this.context.siderCollapsed return this.layoutContext.siderCollapsed
} }
return inlineCollapsed return inlineCollapsed
}, },
getMenuOpenAnimation (menuMode) { getMenuOpenAnimation (menuMode) {
const { openAnimation, openTransitionName } = this.props const { openAnimation, openTransitionName } = this.$props
let menuOpenAnimation = openAnimation || openTransitionName let menuOpenAnimation = openAnimation || openTransitionName
if (openAnimation === undefined && openTransitionName === undefined) { if (openAnimation === undefined && openTransitionName === undefined) {
switch (menuMode) { switch (menuMode) {
@ -124,10 +150,11 @@ export default {
case 'inline': case 'inline':
menuOpenAnimation = { menuOpenAnimation = {
...animation, ...animation,
leave: (node, done: () => void) => animation.leave(node, () => { leave: (node, done) => animation.leave(node, () => {
// Make sure inline menu leave animation finished before mode is switched // Make sure inline menu leave animation finished before mode is switched
this.switchModeFromInline = false this.switchModeFromInline = false
this.setState({}) // this.setState({})
this.$forceUpdate()
// when inlineCollapsed change false to true, all submenu will be unmounted, // when inlineCollapsed change false to true, all submenu will be unmounted,
// so that we don't need handle animation leaving. // so that we don't need handle animation leaving.
if (this.getRealMenuMode() === 'vertical') { if (this.getRealMenuMode() === 'vertical') {
@ -143,32 +170,15 @@ export default {
return menuOpenAnimation return menuOpenAnimation
}, },
}, },
componentWillReceiveProps (nextProps, nextContext) {
const { prefixCls } = this.props
if (this.props.mode === 'inline' &&
nextProps.mode !== 'inline') {
this.switchModeFromInline = true
}
if ('openKeys' in nextProps) {
this.setState({ openKeys: nextProps.openKeys })
return
}
if ((nextProps.inlineCollapsed && !this.props.inlineCollapsed) ||
(nextContext.siderCollapsed && !this.context.siderCollapsed)) {
this.switchModeFromInline =
!!this.state.openKeys.length && !!this.$el.querySelectorAll(`.${prefixCls}-submenu-open`).length
this.inlineOpenKeys = this.state.openKeys
this.setState({ openKeys: [] })
}
if ((!nextProps.inlineCollapsed && this.props.inlineCollapsed) ||
(!nextContext.siderCollapsed && this.context.siderCollapsed)) {
this.setState({ openKeys: this.inlineOpenKeys })
this.inlineOpenKeys = []
}
},
render () { render () {
const { prefixCls, className, theme } = this.props const { $props, layoutContext, $slots } = this
const { collapsedWidth, siderCollapsed } = layoutContext
this.preProps = cloneDeep($props)
this.preLayoutContext = {
siderCollapsed,
collapsedWidth,
}
const { prefixCls, theme } = this.$props
const menuMode = this.getRealMenuMode() const menuMode = this.getRealMenuMode()
const menuOpenAnimation = this.getMenuOpenAnimation(menuMode) const menuOpenAnimation = this.getMenuOpenAnimation(menuMode)
@ -178,22 +188,26 @@ export default {
} }
const menuProps = { const menuProps = {
openKeys: this.state.openKeys, props: {
onOpenChange: this.handleOpenChange, ...omit(this.$props, ['inlineCollapsed']),
className: menuClassName, openKeys: this.sOpenKeys,
mode: menuMode, mode: menuMode,
},
on: {
openChange: this.handleOpenChange,
},
} }
if (menuMode !== 'inline') { if (menuMode !== 'inline') {
// closing vertical popup submenu after click it // closing vertical popup submenu after click it
menuProps.onClick = this.handleClick menuProps.on.click = this.handleClick
menuProps.openTransitionName = menuOpenAnimation menuProps.props.openTransitionName = menuOpenAnimation
} else { } else {
menuProps.openAnimation = menuOpenAnimation menuProps.props.openAnimation = menuOpenAnimation
} }
// https://github.com/ant-design/ant-design/issues/8587 // https://github.com/ant-design/ant-design/issues/8587
const { collapsedWidth } = this.context
if ( if (
this.getInlineCollapsed() && this.getInlineCollapsed() &&
(collapsedWidth === 0 || collapsedWidth === '0' || collapsedWidth === '0px') (collapsedWidth === 0 || collapsedWidth === '0' || collapsedWidth === '0px')
@ -201,7 +215,7 @@ export default {
return null return null
} }
return <RcMenu {...this.props} {...menuProps} /> return <RcMenu {...menuProps} class={menuClassName}>{$slots.default}</RcMenu>
}, },
} }

View File

@ -2,8 +2,9 @@ import hasProp from '../../_util/props-util'
import KeyCode from '../../_util/KeyCode' import KeyCode from '../../_util/KeyCode'
import scrollIntoView from 'dom-scroll-into-view' import scrollIntoView from 'dom-scroll-into-view'
import { getKeyFromChildrenIndex, loopMenuItem } from './util' import { getKeyFromChildrenIndex, loopMenuItem } from './util'
import { cloneElement } from '../../_util/vnode' import { cloneElement, getComponentName } from '../../_util/vnode'
import DOMWrap from './DOMWrap' import DOMWrap from './DOMWrap'
import warning from '../../_util/warning'
function allDisabled (arr) { function allDisabled (arr) {
if (!arr.length) { if (!arr.length) {
@ -133,6 +134,10 @@ export default {
}, },
renderCommonMenuItem (child, i, subIndex, extraProps) { renderCommonMenuItem (child, i, subIndex, extraProps) {
if (child.tag === undefined) { return child }
warning((getComponentName(child.componentOptions) || '').indexOf(['MenuItem', 'MenuItemGroup']) === -1,
'`Menu child just support MenuItem and MenuItemGroup',
)
const state = this.$data const state = this.$data
const props = this.$props const props = this.$props
const key = getKeyFromChildrenIndex(child, props.eventKey, i) const key = getKeyFromChildrenIndex(child, props.eventKey, i)

View File

@ -6,6 +6,7 @@ import SubPopupMenu from './SubPopupMenu'
import placements from './placements' import placements from './placements'
import { loopMenuItemRecusively, noop } from './util' import { loopMenuItemRecusively, noop } from './util'
import BaseMixin from '../../_util/BaseMixin' import BaseMixin from '../../_util/BaseMixin'
import { getComponentFromProp } from '../../_util/props-util'
let guid = 0 let guid = 0
@ -197,7 +198,6 @@ export default {
this.__emit('itemClick', { this.__emit('itemClick', {
key: eventKey, key: eventKey,
domEvent: e, domEvent: e,
test: 111,
}) })
if (triggerSubMenuAction === 'hover') { if (triggerSubMenuAction === 'hover') {
return return
@ -384,8 +384,7 @@ export default {
<div <div
{...titleProps} {...titleProps}
> >
{typeof props.title === 'function' ? props.title(h) : props.title} {getComponentFromProp(this, h, 'title')}
{this.$slots.title}
<i class={`${prefixCls}-arrow`} /> <i class={`${prefixCls}-arrow`} />
</div> </div>
) )

View File

@ -14,7 +14,7 @@ export default {
mode: PropTypes.oneOf(['horizontal', 'vertical', 'vertical-left', 'vertical-right', 'inline']).def('vertical'), mode: PropTypes.oneOf(['horizontal', 'vertical', 'vertical-left', 'vertical-right', 'inline']).def('vertical'),
triggerSubMenuAction: PropTypes.string.def('hover'), triggerSubMenuAction: PropTypes.string.def('hover'),
openTransitionName: PropTypes.string, openTransitionName: PropTypes.string,
subMenuOpenDelay: PropTypes.number.def(0), subMenuOpenDelay: PropTypes.number.def(0.1),
subMenuCloseDelay: PropTypes.number.def(0.1), subMenuCloseDelay: PropTypes.number.def(0.1),
level: PropTypes.number.def(1), level: PropTypes.number.def(1),
inlineIndent: PropTypes.number.def(24), inlineIndent: PropTypes.number.def(24),

View File

@ -13,10 +13,10 @@ export function loopMenuItem (children, cb) {
if (c && c.type && c.type.isMenuItemGroup) { if (c && c.type && c.type.isMenuItemGroup) {
c.$slots.default.forEach((c2) => { c.$slots.default.forEach((c2) => {
index++ index++
cb(c2, index) c.componentOptions && cb(c2, index)
}) })
} else { } else {
cb(c, index) c.componentOptions && cb(c, index)
} }
}) })
} }

View File

@ -13,5 +13,4 @@ import './input/style'
import './tooltip/style' import './tooltip/style'
import './popover/style' import './popover/style'
import './popconfirm/style' import './popconfirm/style'
import './menu/style' import './menu/style'

View File

@ -3,7 +3,7 @@ const AsyncComp = () => {
const com = pathnameArr[1] || 'button' const com = pathnameArr[1] || 'button'
const demo = pathnameArr[2] || 'index' const demo = pathnameArr[2] || 'index'
return { return {
component: import(`../components/avatar/demo/${demo}.vue`), component: import(`../components/menu/demo/${demo}.vue`),
} }
} }
export default [ export default [