pull/9/head
tangjinzhou 2018-01-04 19:06:54 +08:00
parent 066c727e49
commit b985efc438
13 changed files with 157 additions and 162 deletions

View File

@ -44,7 +44,7 @@ export function cloneElement (node, nodeProps) {
class: cls = data.class,
attrs = data.attrs,
} = nodeProps
node.data = Object.assign(data, { style, attrs, class: cls })
node.data = Object.assign(data, { style, attrs, class: cls, on: { ...(data.on || {}), ...on }})
if (key !== undefined) {
node.key = key
node.data.key = key

View File

@ -42,7 +42,7 @@
}
&-item-active,
&-submenu-active > &-submenu-title {
&-submenu-active > span > &-submenu-title {
background-color: #eaf8fe;
}
@ -193,7 +193,7 @@
}
.effect() {
animation-duration: .3s;
animation-duration: .5s;
animation-fill-mode: both;
transform-origin: 0 0;
}
@ -214,12 +214,14 @@
animation-play-state: paused;
}
&-slide-up-enter&-slide-up-enter-active, &-slide-up-appear&-slide-up-appear-active {
&-slide-up-enter-active, &-slide-up-appear-active {
.effect();
animation-name: rcMenuOpenSlideUpIn;
animation-play-state: running;
}
&-slide-up-leave&-slide-up-leave-active {
&-slide-up-leave-active {
.effect();
animation-name: rcMenuOpenSlideUpOut;
animation-play-state: running;
}
@ -236,6 +238,7 @@
transform: scaleY(1);
}
}
@keyframes rcMenuOpenSlideUpOut {
0% {
opacity: 1;
@ -284,7 +287,6 @@
}
@keyframes rcMenuOpenZoomOut {
0% {
transform: scale(1, 1);
}
100% {

View File

@ -52,46 +52,49 @@ export default {
},
render () {
// const nestSubMenu = (<SubMenu title={<span>sub menu 2</span>} key='4'>
// <MenuItem key='4-1'>inner inner</MenuItem>
// <Divider/>
// <SubMenu
// key='4-2'
// title={<span>sub menu 3</span>}
// >
// <SubMenu title='sub 4-2-0' key='4-2-0'>
// <MenuItem key='4-2-0-1'>inner inner</MenuItem>
// <MenuItem key='4-2-0-2'>inner inner2</MenuItem>
// </SubMenu>
// <MenuItem key='4-2-1'>inn</MenuItem>
// <SubMenu title={<span>sub menu 4</span>} key='4-2-2'>
// <MenuItem key='4-2-2-1'>inner inner</MenuItem>
// <MenuItem key='4-2-2-2'>inner inner2</MenuItem>
// </SubMenu>
// <SubMenu title='sub 4-2-3' key='4-2-3'>
// <MenuItem key='4-2-3-1'>inner inner</MenuItem>
// <MenuItem key='4-2-3-2'>inner inner2</MenuItem>
// </SubMenu>
// </SubMenu>
// </SubMenu>)
const nestSubMenu = (<SubMenu title={<span>sub menu 2</span>} key='4'>
<MenuItem key='4-1'>inner inner</MenuItem>
<Divider/>
<SubMenu
key='4-2'
title={<span>sub menu 3</span>}
>
<SubMenu title='sub 4-2-0' key='4-2-0'>
<MenuItem key='4-2-0-1'>inner inner</MenuItem>
<MenuItem key='4-2-0-2'>inner inner2</MenuItem>
</SubMenu>
<MenuItem key='4-2-1'>inn</MenuItem>
<SubMenu title={<span>sub menu 4</span>} key='4-2-2'>
<MenuItem key='4-2-2-1'>inner inner</MenuItem>
<MenuItem key='4-2-2-2'>inner inner2</MenuItem>
</SubMenu>
<SubMenu title='sub 4-2-3' key='4-2-3'>
<MenuItem key='4-2-3-1'>inner inner</MenuItem>
<MenuItem key='4-2-3-2'>inner inner2</MenuItem>
</SubMenu>
</SubMenu>
</SubMenu>)
function onOpenChange (value) {
console.log('onOpenChange', value)
}
const commonMenu = (<Menu class='test' onSelect={handleSelect} onOpenChange={onOpenChange}>
<SubMenu key='1'>
<template slot='title'><span>sub menu</span></template>
<SubMenu key='1' title={<span>sub menu</span>}>
<MenuItem key='1-1'>
0-1
<Icon type='search'/>
</MenuItem>
<MenuItem key='1-2'>0-2</MenuItem>
</SubMenu>
{nestSubMenu}
<MenuItem key='2'>1</MenuItem>
<MenuItem key='3'>outer</MenuItem>
<MenuItem disabled>disabled</MenuItem>
<MenuItem key='5'>outer3</MenuItem>
</Menu>)
const horizontalMenu = cloneElement(commonMenu, { props: {
mode: 'horizontal',
// use openTransition for antd
openAnimation: 'slide-up',
openAnimation: 'rc-menu-open-slide-up',
}})
// const horizontalMenu2 = cloneElement(commonMenu, { props: {

View File

@ -3,26 +3,19 @@ import PropTypes from '../../_util/vue-types'
import MenuMixin from './MenuMixin'
import StateMixin from '../../_util/StateMixin'
import hasProp from '../../_util/hasProp'
import commonPropsType from './commonPropsType'
const Menu = {
name: 'Menu',
props: {
defaultSelectedKeys: PropTypes.arrayOf(PropTypes.string).def([]),
selectedKeys: PropTypes.arrayOf(PropTypes.string),
defaultOpenKeys: PropTypes.arrayOf(PropTypes.string).def([]),
openKeys: PropTypes.arrayOf(PropTypes.string),
mode: PropTypes.oneOf(['horizontal', 'vertical', 'vertical-left', 'vertical-right', 'inline']).def('vertical'),
getPopupContainer: PropTypes.func,
openTransitionName: PropTypes.string,
openAnimation: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
subMenuOpenDelay: PropTypes.number.def(0),
subMenuCloseDelay: PropTypes.number.def(0.1),
forceSubMenuRender: PropTypes.bool,
triggerSubMenuAction: PropTypes.string.def('click'),
level: PropTypes.number.def(1),
selectable: PropTypes.bool.def(true),
multiple: PropTypes.bool,
children: PropTypes.any,
...commonPropsType,
},
mixins: [StateMixin, MenuMixin],

View File

@ -28,15 +28,11 @@ const MenuItem = {
clearSubMenuTimers: PropTypes.func.def(noop),
},
mixins: [StateMixin],
isMenuItem: true,
beforeDestroy () {
const props = this.$props
this.$emit('destroy', props.eventKey)
},
data () {
return {
isMenuItem: 1,
}
},
methods: {
onKeyDown (e) {
const keyCode = e.keyCode

View File

@ -12,11 +12,7 @@ const MenuItemGroup = {
disabled: PropTypes.bool.def(true),
title: PropTypes.any.def(''),
},
data () {
return {
isMenuItemGroup: true,
}
},
isMenuItemGroup: true,
methods: {
renderInnerMenuItem (item, subIndex) {
const { renderMenuItem, index } = this.$props

View File

@ -1,9 +1,8 @@
import PropTypes from '../../_util/vue-types'
import hasProp from '../../_util/hasProp'
import KeyCode from '../../_util/KeyCode'
import scrollIntoView from 'dom-scroll-into-view'
import { getKeyFromChildrenIndex, loopMenuItem } from './util'
import { cloneElement, cloneVNode } from '../../_util/vnode'
import { cloneElement } from '../../_util/vnode'
import DOMWrap from './DOMWrap'
function allDisabled (arr) {
@ -17,54 +16,11 @@ function allDisabled (arr) {
})
}
function getActiveKey (props, originalActiveKey) {
let activeKey = originalActiveKey
const { children, eventKey } = props
if (activeKey) {
let found
loopMenuItem(children, (c, i) => {
const propsData = c.componentOptions.propsData || {}
if (c && !propsData.disabled && activeKey === getKeyFromChildrenIndex(c, eventKey, i)) {
found = true
}
})
if (found) {
return activeKey
}
}
activeKey = null
if (props.defaultActiveFirst) {
loopMenuItem(children, (c, i) => {
const propsData = c.componentOptions.propsData || {}
if (!activeKey && c && !propsData.disabled) {
activeKey = getKeyFromChildrenIndex(c, eventKey, i)
}
})
return activeKey
}
return activeKey
}
export default {
props: {
test: PropTypes.any,
prefixCls: PropTypes.string.def('rc-menu'),
inlineIndent: PropTypes.number.def(24),
focusable: PropTypes.bool.def(true),
multiple: PropTypes.bool,
defaultActiveFirst: PropTypes.bool,
visible: PropTypes.bool.def(true),
activeKey: PropTypes.string,
selectedKeys: PropTypes.arrayOf(PropTypes.string),
defaultSelectedKeys: PropTypes.arrayOf(PropTypes.string),
defaultOpenKeys: PropTypes.arrayOf(PropTypes.string),
openKeys: PropTypes.arrayOf(PropTypes.string),
mode: PropTypes.oneOf(['horizontal', 'vertical', 'vertical-left', 'vertical-right', 'inline']).def('vertical'),
},
data () {
const props = this.$props
return {
sActiveKey: getActiveKey(props, props.activeKey),
sActiveKey: this.getActiveKey(props.activeKey),
}
},
watch: {
@ -73,11 +29,11 @@ export default {
let props
if (hasProp(this, 'activeKey')) {
props = {
sActiveKey: getActiveKey(nextProps, nextProps.activeKey),
sActiveKey: this.getActiveKey(nextProps.activeKey),
}
} else {
const originalActiveKey = this.$data.sActiveKey
const sActiveKey = getActiveKey(nextProps, originalActiveKey)
const sActiveKey = this.getActiveKey(originalActiveKey)
// fix: this.setState(), parent.render(),
if (sActiveKey !== originalActiveKey) {
props = {
@ -97,6 +53,34 @@ export default {
this.instanceArray = []
},
methods: {
getActiveKey (originalActiveKey) {
let activeKey = originalActiveKey
const { eventKey, defaultActiveFirst } = this.$props
const children = this.$slots.default
if (activeKey) {
let found
loopMenuItem(children, (c, i) => {
const propsData = c.componentOptions.propsData || {}
if (c && !propsData.disabled && activeKey === getKeyFromChildrenIndex(c, eventKey, i)) {
found = true
}
})
if (found) {
return activeKey
}
}
activeKey = null
if (defaultActiveFirst) {
loopMenuItem(children, (c, i) => {
const propsData = c.componentOptions.propsData || {}
if (!activeKey && c && !propsData.disabled) {
activeKey = getKeyFromChildrenIndex(c, eventKey, i)
}
})
return activeKey
}
return activeKey
},
saveRef (index, subIndex, c) {
if (c) {
if (subIndex !== undefined) {
@ -234,8 +218,8 @@ export default {
},
props: {
tag: 'ul',
hiddenClassName: `${props.prefixCls}-hidden`,
visible: props.visible,
// hiddenClassName: `${props.prefixCls}-hidden`,
// visible: props.visible,
},
class: className,
on: {},
@ -249,11 +233,11 @@ export default {
}
const newChildren = children.map(this.renderMenuItem)
return (
<ul
<DOMWrap
{...domProps}
>
{newChildren}
</ul>
</DOMWrap>
)
},

View File

@ -37,6 +37,10 @@ export default {
popupClassName: PropTypes.string,
getPopupContainer: PropTypes.func,
test: PropTypes.any,
forceSubMenuRender: PropTypes.bool,
openAnimation: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
disabled: PropTypes.bool,
subMenuCloseDelay: PropTypes.number,
// onDeselect: PropTypes.func,
// onDestroy: PropTypes.func,
// onMouseEnter: PropTypes.func,
@ -46,10 +50,10 @@ export default {
// onTitleClick: PropTypes.func,
},
mixins: [StateMixin],
isSubMenu: true,
data () {
return {
defaultActiveFirst: false,
isSubMenu: 1,
}
},
mounted () {
@ -160,7 +164,6 @@ export default {
domEvent: e,
})
}
// prevent popup menu and submenu gap
this.subMenuLeaveTimer = setTimeout(this.subMenuLeaveFn, 100)
},
@ -390,6 +393,7 @@ export default {
<div
{...titleProps}
>
{typeof props.title === 'function' ? props.title(h) : props.title}
{this.$slots.title}
<i class={`${prefixCls}-arrow`} />
</div>
@ -404,12 +408,38 @@ export default {
on: { ...mouseEvents },
class: className,
}
const { forceSubMenuRender, mode, openTransitionName, openAnimation } = this.$props
const haveRendered = this.haveRendered
this.haveRendered = true
this.haveOpened = this.haveOpened || isOpen || forceSubMenuRender
const transitionAppear = !(!haveRendered && isOpen && mode === 'inline')
let animProps = { appear: true }
if (openTransitionName) {
animProps.name = openTransitionName
} else if (typeof openAnimation === 'object') {
animProps = { ...animProps, ...openAnimation }
if (!transitionAppear) {
animProps.appear = false
}
} else if (typeof openAnimation === 'string') {
animProps.name = openAnimation
}
const transitionProps = {
props: animProps,
}
return (
<li {...liProps}>
{isInlineMode && title}
{isInlineMode && children}
{isInlineMode && (
<transition {...transitionProps}>
{children}
</transition>
)}
{!isInlineMode && (
<Trigger
prefixCls={prefixCls}
popupClassName={`${prefixCls}-popup ${popupClassName || ''}`}
@ -422,9 +452,11 @@ export default {
mouseLeaveDelay={props.subMenuCloseDelay}
onPopupVisibleChange={this.onPopupVisibleChange}
forceRender={props.forceSubMenuRender}
// popupTransitionName='rc-menu-open-slide-up'
popupAnimation={animProps}
>
<template slot='popup'>
{children}
{this.haveOpened ? children : null}
</template>
{title}
</Trigger>

View File

@ -2,19 +2,12 @@
import PropTypes from '../../_util/vue-types'
import MenuMixin from './MenuMixin'
import StateMixin from '../../_util/StateMixin'
import commonPropsType from './commonPropsType'
import { noop } from './util'
export default {
name: 'SubPopupMenu',
props: {
// onSelect: PropTypes.func,
// onClick: PropTypes.func,
// onDeselect: PropTypes.func,
// onOpenChange: PropTypes.func,
// onDestroy: PropTypes.func,
openTransitionName: PropTypes.string,
openAnimation: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
openKeys: PropTypes.arrayOf(PropTypes.string),
visible: PropTypes.bool,
props: { ...commonPropsType,
clearSubMenuTimers: PropTypes.func.def(noop),
},
mixins: [MenuMixin, StateMixin],
@ -36,7 +29,7 @@ export default {
},
onDestroy (key) {
this.$$emit('destroy', key)
this.$emit('destroy', key)
},
getOpenTransitionName () {
@ -58,36 +51,8 @@ export default {
},
},
render () {
const props = { ...this.$props }
const haveRendered = this.haveRendered
this.haveRendered = true
this.haveOpened = this.haveOpened || props.visible || props.forceSubMenuRender
if (!this.haveOpened) {
return null
}
const transitionAppear = !(!haveRendered && props.visible && props.mode === 'inline')
props.class = `${props.prefixCls}-sub`
const animProps = {}
if (props.openTransitionName) {
animProps.transitionName = props.openTransitionName
} else if (typeof props.openAnimation === 'object') {
animProps.animation = { ...props.openAnimation }
if (!transitionAppear) {
delete animProps.animation.appear
}
}
return (
<transition
appear
name={animProps.transitionName}
>
{this.renderRoot(props, this.$slots.default)}
</transition>
)
const { prefixCls } = this.$props
return this.renderRoot({ ...this.$props, class: `${prefixCls}-sub` }, this.$slots.default)
},
}
</script>

View File

@ -0,0 +1,18 @@
import PropTypes from '../../_util/vue-types'
export default {
prefixCls: PropTypes.string.def('rc-menu'),
inlineIndent: PropTypes.number.def(24),
focusable: PropTypes.bool.def(true),
multiple: PropTypes.bool,
defaultActiveFirst: PropTypes.bool,
visible: PropTypes.bool.def(true),
activeKey: PropTypes.string,
selectedKeys: PropTypes.arrayOf(PropTypes.string),
defaultSelectedKeys: PropTypes.arrayOf(PropTypes.string),
defaultOpenKeys: PropTypes.arrayOf(PropTypes.string),
openKeys: PropTypes.arrayOf(PropTypes.string),
openAnimation: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
mode: PropTypes.oneOf(['horizontal', 'vertical', 'vertical-left', 'vertical-right', 'inline']).def('vertical'),
triggerSubMenuAction: PropTypes.string.def('click'),
openTransitionName: PropTypes.string,
}

View File

@ -29,16 +29,18 @@ export function loopMenuItemRecusively (children, keys, ret) {
if (ret.find) {
return
}
if (c) {
console.log(c)
const construt = c.type
if (!construt || !(construt.isSubMenu || construt.isMenuItem || construt.isMenuItemGroup)) {
if (c.data && c.data.slot && c.data.slot !== 'default') {
return
}
if (c && c.componentOptions) {
const options = c.componentOptions.Ctor.options
if (!options || !(options.isSubMenu || options.isMenuItem || options.isMenuItemGroup)) {
return
}
if (keys.indexOf(c.key) !== -1) {
ret.find = true
} else if (c.$slots.default) {
loopMenuItemRecusively(c.$slots.default, keys, ret)
} else if (c.componentOptions.children) {
loopMenuItemRecusively(c.componentOptions.children, keys, ret)
}
}
})

View File

@ -75,8 +75,8 @@ export default {
getTransitionName () {
const props = this.$props
let transitionName = props.transitionName
if (!transitionName && props.animation) {
transitionName = `${props.prefixCls}-${props.animation}`
if (!transitionName && typeof props.animation === 'string') {
transitionName = `${props.animation}`
}
return transitionName
},
@ -100,7 +100,7 @@ export default {
},
getPopupElement () {
const { $props: props, onMouseEnter, onMouseLeave, $slots } = this
const { align, visible, prefixCls } = props
const { align, visible, prefixCls, animation } = props
const className = this.getClassName(this.currentAlignClassName ||
props.getClassNameFromAlign(align))
// const hiddenClassName = `${prefixCls}-hidden`
@ -121,9 +121,13 @@ export default {
ref: 'popupInstance',
style: { ...this.getZIndexStyle() },
}
const transitionProps = {
props: Object.assign({
appear: true,
}, typeof animation === 'object' ? animation : { name: this.getTransitionName() }),
}
return (<transition
appear
name={this.getTransitionName()}
{...transitionProps}
onBeforeEnter={this.beforeEnter}
onAfterLeave={this.afterLeave}
>

View File

@ -265,7 +265,7 @@ export default {
// mouseLeaveDelay={0.1}
action={Object.keys(state.trigger)}
builtinPlacements={builtinPlacements}
popupTransitionName={state.transitionName}
popupAnimation={state.transitionName}
>
<div slot='popup' style={{ border: '1px solid red', padding: '10px', background: 'white' }}>
i am a popup