tangjinzhou
7 years ago
28 changed files with 1161 additions and 43 deletions
@ -0,0 +1,30 @@
|
||||
<cn> |
||||
#### 基本 |
||||
最简单的下拉菜单。 |
||||
</cn> |
||||
|
||||
<us> |
||||
#### Basic |
||||
The most basic dropdown menu. |
||||
</us> |
||||
|
||||
```html |
||||
<template> |
||||
<a-dropdown> |
||||
<a class="ant-dropdown-link" href="#"> |
||||
Hover me <a-icon type="down" /> |
||||
</a> |
||||
<a-menu slot="overlay"> |
||||
<a-menu-item> |
||||
<a href="javascript:;">1st menu item</a> |
||||
</a-menu-item> |
||||
<a-menu-item> |
||||
<a href="javascript:;">2nd menu item</a> |
||||
</a-menu-item> |
||||
<a-menu-item> |
||||
<a href="javascript:;">3rd menu item</a> |
||||
</a-menu-item> |
||||
</a-menu> |
||||
</a-dropdown> |
||||
</template> |
||||
``` |
@ -0,0 +1,22 @@
|
||||
<cn> |
||||
#### 右键菜单 |
||||
默认是移入触发菜单,可以鼠标右键触发。 |
||||
</cn> |
||||
|
||||
<us> |
||||
#### Context Menu |
||||
The default trigger mode is `hover`, you can change it to `right click`. |
||||
</us> |
||||
|
||||
```html |
||||
<template> |
||||
<a-dropdown :trigger="['contextmenu']"> |
||||
<span style="user-select: none">Right Click on Me</span> |
||||
<a-menu slot="overlay"> |
||||
<a-menu-item key="1">1st menu item</a-menu-item> |
||||
<a-menu-item key="2">2nd menu item</a-menu-item> |
||||
<a-menu-item key="3">3rd menu item</a-menu-item> |
||||
</a-menu> |
||||
</a-dropdown> |
||||
</template> |
||||
``` |
@ -0,0 +1,59 @@
|
||||
<cn> |
||||
#### 带下拉框的按钮 |
||||
左边是按钮,右边是额外的相关功能菜单。 |
||||
</cn> |
||||
|
||||
<us> |
||||
#### Button with dropdown menu |
||||
A button is on the left, and a related functional menu is on the right. |
||||
</us> |
||||
|
||||
```html |
||||
<template> |
||||
<div> |
||||
<a-dropdown-button @click="handleMenuClick"> |
||||
Dropdown |
||||
<a-menu slot="overlay" @click="handleMenuClick"> |
||||
<a-menu-item key="1">1st menu item</a-menu-item> |
||||
<a-menu-item key="2">2nd menu item</a-menu-item> |
||||
<a-menu-item key="3">3rd item</a-menu-item> |
||||
</a-menu> |
||||
</a-dropdown-button> |
||||
<a-dropdown-button |
||||
@click="handleButtonClick" |
||||
disabled |
||||
style="margin-left: 8px" |
||||
> |
||||
Dropdown |
||||
<a-menu slot="overlay" @click="handleMenuClick"> |
||||
<a-menu-item key="1">1st menu item</a-menu-item> |
||||
<a-menu-item key="2">2nd menu item</a-menu-item> |
||||
<a-menu-item key="3">3rd item</a-menu-item> |
||||
</a-menu> |
||||
</a-dropdown-button> |
||||
<a-dropdown> |
||||
<a-menu slot="overlay" @click="handleMenuClick"> |
||||
<a-menu-item key="1">1st menu item</a-menu-item> |
||||
<a-menu-item key="2">2nd menu item</a-menu-item> |
||||
<a-menu-item key="3">3rd item</a-menu-item> |
||||
</a-menu> |
||||
<a-button style="margin-left: 8px"> |
||||
Button <a-icon type="down" /> |
||||
</a-button> |
||||
</a-dropdown> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
export default { |
||||
methods: { |
||||
handleButtonClick(e) { |
||||
console.log('click left button', e); |
||||
}, |
||||
handleMenuClick(e) { |
||||
console.log('click', e); |
||||
}, |
||||
} |
||||
} |
||||
</script> |
||||
``` |
@ -0,0 +1,34 @@
|
||||
<cn> |
||||
#### 触发事件 |
||||
点击菜单项后会触发事件,用户可以通过相应的菜单项 key 进行不同的操作。 |
||||
</cn> |
||||
|
||||
<us> |
||||
#### Click event |
||||
An event will be triggered when you click menu items, in which you can make different operations according to item's key. |
||||
</us> |
||||
|
||||
```html |
||||
<template> |
||||
<a-dropdown> |
||||
<a class="ant-dropdown-link" href="#"> |
||||
Hover me, Click menu item <a-icon type="down" /> |
||||
</a> |
||||
<a-menu slot="overlay" @click="onClick"> |
||||
<a-menu-item key="1">1st menu item</a-menu-item> |
||||
<a-menu-item key="2">2nd menu item</a-menu-item> |
||||
<a-menu-item key="3">3rd menu item</a-menu-item> |
||||
</a-menu> |
||||
</a-dropdown> |
||||
</template> |
||||
|
||||
<script> |
||||
export default { |
||||
methods: { |
||||
onClick({ key }) { |
||||
console.log(`Click on item ${key}`); |
||||
} |
||||
} |
||||
} |
||||
</script> |
||||
``` |
@ -0,0 +1,46 @@
|
||||
<script> |
||||
import Basic from './basic' |
||||
import ContextMenu from './context-menu' |
||||
import DropdownButton from './dropdown-button' |
||||
import Event from './event' |
||||
import Item from './item' |
||||
import OverlayVisible from './overlay-visible' |
||||
import Placement from './placement' |
||||
import SubMenu from './sub-menu' |
||||
import Trigger from './trigger' |
||||
import CN from '../index.zh-CN.md' |
||||
import US from '../index.en-US.md' |
||||
const md = { |
||||
cn: `# 下拉菜单 |
||||
向下弹出的列表。 |
||||
## 何时使用 |
||||
当页面上的操作命令过多时,用此组件可以收纳操作元素。点击或移入触点,会出现一个下拉菜单。可在列表中进行选择,并执行相应的命令。 |
||||
## 代码演示`, |
||||
us: `# Dropdown |
||||
A dropdown list. |
||||
## When To Use |
||||
If there are too many operations to display, you can wrap them in a \`Dropdown\`. By clicking/hovering on the trigger, a dropdown menu should appear, which allows you to choose one option and execute relevant actions.`, |
||||
} |
||||
export default { |
||||
render () { |
||||
return ( |
||||
<div> |
||||
<md cn={md.cn} us={md.us}/> |
||||
<Basic /> |
||||
<ContextMenu /> |
||||
<DropdownButton /> |
||||
<Event /> |
||||
<Item/> |
||||
<OverlayVisible /> |
||||
<Placement /> |
||||
<SubMenu /> |
||||
<Trigger /> |
||||
<api> |
||||
<CN slot='cn' /> |
||||
<US/> |
||||
</api> |
||||
</div> |
||||
) |
||||
}, |
||||
} |
||||
</script> |
@ -0,0 +1,29 @@
|
||||
<cn> |
||||
#### 其他元素 |
||||
分割线和不可用菜单项。 |
||||
</cn> |
||||
|
||||
<us> |
||||
#### Other elements |
||||
Divider and disabled menu item. |
||||
</us> |
||||
|
||||
```html |
||||
<template> |
||||
<a-dropdown> |
||||
<a class="ant-dropdown-link" href="#"> |
||||
Hover me <a-icon type="down" /> |
||||
</a> |
||||
<a-menu slot="overlay"> |
||||
<a-menu-item key="0"> |
||||
<a target="_blank" rel="noopener noreferrer" href="http://www.alipay.com/">1st menu item</a> |
||||
</a-menu-item> |
||||
<a-menu-item key="1"> |
||||
<a target="_blank" rel="noopener noreferrer" href="http://www.taobao.com/">2nd menu item</a> |
||||
</a-menu-item> |
||||
<a-menu-divider /> |
||||
<a-menu-item key="3" disabled>3rd menu item(disabled)</a-menu-item> |
||||
</a-menu> |
||||
</a-dropdown> |
||||
</template> |
||||
``` |
@ -0,0 +1,41 @@
|
||||
<cn> |
||||
#### 菜单隐藏方式 |
||||
默认是点击关闭菜单,可以关闭此功能。 |
||||
</cn> |
||||
|
||||
<us> |
||||
#### The way of hiding menu. |
||||
The default is to close the menu when you click on menu items, this feature can be turned off. |
||||
</us> |
||||
|
||||
```html |
||||
<template> |
||||
<a-dropdown v-model="visible"> |
||||
<a class="ant-dropdown-link" href="#"> |
||||
Hover me <a-icon type="down" /> |
||||
</a> |
||||
<a-menu slot="overlay" @click="handleMenuClick"> |
||||
<a-menu-item key="1">Clicking me will not close the menu.</a-menu-item> |
||||
<a-menu-item key="2">Clicking me will not close the menu also.</a-menu-item> |
||||
<a-menu-item key="3">Clicking me will close the menu</a-menu-item> |
||||
</a-menu> |
||||
</a-dropdown> |
||||
</template> |
||||
|
||||
<script> |
||||
export default { |
||||
data(){ |
||||
return { |
||||
visible: false, |
||||
} |
||||
}, |
||||
methods: { |
||||
handleMenuClick (e) { |
||||
if (e.key === '3') { |
||||
this.visible = false |
||||
} |
||||
}, |
||||
} |
||||
} |
||||
</script> |
||||
``` |
@ -0,0 +1,49 @@
|
||||
<cn> |
||||
#### 弹出位置 |
||||
支持 6 个弹出位置。 |
||||
</cn> |
||||
|
||||
<us> |
||||
#### Placement |
||||
Support 6 placements. |
||||
</us> |
||||
|
||||
```html |
||||
<template> |
||||
<div id="components-dropdown-demo-placement"> |
||||
<template v-for="(placement, index) in placements"> |
||||
<a-dropdown :placement="placement"> |
||||
<a-button>{{placement}}</a-button> |
||||
<a-menu slot="overlay"> |
||||
<a-menu-item> |
||||
<a target="_blank" rel="noopener noreferrer" href="http://www.alipay.com/">1st menu item</a> |
||||
</a-menu-item> |
||||
<a-menu-item> |
||||
<a target="_blank" rel="noopener noreferrer" href="http://www.taobao.com/">2nd menu item</a> |
||||
</a-menu-item> |
||||
<a-menu-item> |
||||
<a target="_blank" rel="noopener noreferrer" href="http://www.tmall.com/">3rd menu item</a> |
||||
</a-menu-item> |
||||
</a-menu> |
||||
</a-dropdown> |
||||
<br v-if="index === 2"/> |
||||
</template> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
export default { |
||||
data(){ |
||||
return { |
||||
placements: ['bottomLeft', 'bottomCenter', 'bottomRight', 'topLeft', 'topCenter', 'topRight'], |
||||
} |
||||
}, |
||||
} |
||||
</script> |
||||
<style> |
||||
#components-dropdown-demo-placement .ant-btn { |
||||
margin-right: 8px; |
||||
margin-bottom: 8px; |
||||
} |
||||
</style> |
||||
``` |
@ -0,0 +1,31 @@
|
||||
<cn> |
||||
#### 多级菜单 |
||||
传入的菜单里有多个层级。 |
||||
</cn> |
||||
|
||||
<us> |
||||
#### Cascading menu |
||||
The menu has multiple levels. |
||||
</us> |
||||
|
||||
```html |
||||
<template> |
||||
<a-dropdown> |
||||
<a class="ant-dropdown-link" href="#"> |
||||
Cascading menu <a-icon type="down" /> |
||||
</a> |
||||
<a-menu slot="overlay"> |
||||
<a-menu-item>1st menu item</a-menu-item> |
||||
<a-menu-item>2nd menu item</a-menu-item> |
||||
<a-sub-menu title="sub menu" key="test"> |
||||
<a-menu-item>3rd menu item</a-menu-item> |
||||
<a-menu-item>4th menu item</a-menu-item> |
||||
</a-sub-menu> |
||||
<a-sub-menu title="disabled sub menu" disabled> |
||||
<a-menu-item>5d menu item</a-menu-item> |
||||
<a-menu-item>6th menu item</a-menu-item> |
||||
</a-sub-menu> |
||||
</a-menu> |
||||
</a-dropdown> |
||||
</template> |
||||
``` |
@ -0,0 +1,29 @@
|
||||
<cn> |
||||
#### 触发方式 |
||||
默认是移入触发菜单,可以点击触发。 |
||||
</cn> |
||||
|
||||
<us> |
||||
#### Trigger mode |
||||
The default trigger mode is `hover`, you can change it to `click`. |
||||
</us> |
||||
|
||||
```html |
||||
<template> |
||||
<a-dropdown :trigger="['click']"> |
||||
<a class="ant-dropdown-link" href="#"> |
||||
Click me <a-icon type="down" /> |
||||
</a> |
||||
<a-menu slot="overlay"> |
||||
<a-menu-item key="0"> |
||||
<a href="http://www.alipay.com/">1st menu item</a> |
||||
</a-menu-item> |
||||
<a-menu-item key="1"> |
||||
<a href="http://www.taobao.com/">2nd menu item</a> |
||||
</a-menu-item> |
||||
<a-menu-divider /> |
||||
<a-menu-item key="3">3rd menu item</a-menu-item> |
||||
</a-menu> |
||||
</a-dropdown> |
||||
</template> |
||||
``` |
@ -0,0 +1,81 @@
|
||||
<script> |
||||
import Button from '../button' |
||||
import { ButtonGroupProps } from '../button/button-group' |
||||
import Icon from '../icon' |
||||
import Dropdown from './dropdown' |
||||
import PropTypes from '../_util/vue-types' |
||||
import { hasProp, getComponentFromProp } from '../_util/props-util' |
||||
import getDropdownProps from './getDropdownProps' |
||||
const DropdownProps = getDropdownProps() |
||||
const ButtonGroup = Button.Group |
||||
export default { |
||||
props: { |
||||
...ButtonGroupProps, |
||||
...DropdownProps, |
||||
type: PropTypes.oneOf(['primary', 'ghost', 'dashed', 'default']).def('default'), |
||||
disabled: PropTypes.bool, |
||||
prefixCls: PropTypes.string.def('ant-dropdown-button'), |
||||
placement: DropdownProps.placement.def('bottomRight'), |
||||
}, |
||||
methods: { |
||||
onClick (e) { |
||||
this.$emit('click', e) |
||||
}, |
||||
onVisibleChange (val) { |
||||
this.$emit('visibleChange', val) |
||||
}, |
||||
}, |
||||
model: { |
||||
prop: 'visible', |
||||
event: 'visibleChange', |
||||
}, |
||||
render () { |
||||
const { |
||||
type, disabled, |
||||
prefixCls, trigger, align, |
||||
visible, placement, getPopupContainer, |
||||
...restProps |
||||
} = this.$props |
||||
|
||||
const dropdownProps = { |
||||
props: { |
||||
align, |
||||
disabled, |
||||
trigger: disabled ? [] : trigger, |
||||
placement, |
||||
getPopupContainer, |
||||
}, |
||||
on: { |
||||
visibleChange: this.onVisibleChange, |
||||
}, |
||||
} |
||||
if (hasProp(this, 'visible')) { |
||||
dropdownProps.visible = visible |
||||
} |
||||
|
||||
return ( |
||||
<ButtonGroup |
||||
{...restProps} |
||||
class={prefixCls} |
||||
> |
||||
<Button |
||||
type={type} |
||||
disabled={disabled} |
||||
onClick={this.onClick} |
||||
> |
||||
{this.$slots.default} |
||||
</Button> |
||||
<Dropdown {...dropdownProps}> |
||||
<template slot='overlay'> |
||||
{getComponentFromProp(this, 'overlay')} |
||||
</template> |
||||
<Button type={type}> |
||||
<Icon type='down' /> |
||||
</Button> |
||||
</Dropdown> |
||||
</ButtonGroup> |
||||
) |
||||
}, |
||||
} |
||||
|
||||
</script> |
@ -0,0 +1,76 @@
|
||||
<script> |
||||
import RcDropdown from './src/dropdown' |
||||
import DropdownButton from './dropdown-button' |
||||
// import warning from '../_util/warning' |
||||
import PropTypes from '../_util/vue-types' |
||||
import { cloneElement, getPropsData } from '../_util/vnode' |
||||
import { getOptionProps } from '../_util/props-util' |
||||
import getDropdownProps from './getDropdownProps' |
||||
const DropdownProps = getDropdownProps() |
||||
const Dropdown = { |
||||
props: { |
||||
...DropdownProps, |
||||
prefixCls: PropTypes.string.def('ant-dropdown'), |
||||
mouseEnterDelay: PropTypes.number.def(0.15), |
||||
mouseLeaveDelay: PropTypes.number.def(0.1), |
||||
placement: DropdownProps.placement.def('bottomLeft'), |
||||
}, |
||||
model: { |
||||
prop: 'visible', |
||||
event: 'visibleChange', |
||||
}, |
||||
methods: { |
||||
getTransitionName () { |
||||
const { placement = '', transitionName } = this.$props |
||||
if (transitionName !== undefined) { |
||||
return transitionName |
||||
} |
||||
if (placement.indexOf('top') >= 0) { |
||||
return 'slide-down' |
||||
} |
||||
return 'slide-up' |
||||
}, |
||||
}, |
||||
|
||||
render () { |
||||
const { $slots, prefixCls, trigger, disabled, $listeners } = this |
||||
const dropdownTrigger = cloneElement($slots.default, { |
||||
class: `${prefixCls}-trigger`, |
||||
disabled, |
||||
}) |
||||
const overlay = $slots.overlay && $slots.overlay[0] |
||||
// menu cannot be selectable in dropdown defaultly |
||||
const overlayProps = overlay && getPropsData(overlay) |
||||
const selectable = (overlayProps && 'selectable' in overlayProps) |
||||
? overlayProps.selectable : false |
||||
const fixedModeOverlay = cloneElement(overlay, { |
||||
props: { |
||||
mode: 'vertical', |
||||
selectable, |
||||
}, |
||||
}) |
||||
const dropdownProps = { |
||||
props: { |
||||
...getOptionProps(this), |
||||
transitionName: this.getTransitionName(), |
||||
trigger: disabled ? [] : trigger, |
||||
}, |
||||
on: $listeners, |
||||
} |
||||
return ( |
||||
<RcDropdown |
||||
{...dropdownProps} |
||||
> |
||||
{dropdownTrigger} |
||||
<template slot='overlay'> |
||||
{fixedModeOverlay} |
||||
</template> |
||||
</RcDropdown> |
||||
) |
||||
}, |
||||
} |
||||
|
||||
Dropdown.Button = DropdownButton |
||||
export default Dropdown |
||||
|
||||
</script> |
@ -0,0 +1,13 @@
|
||||
import PropTypes from '../_util/vue-types' |
||||
export default () => ({ |
||||
trigger: PropTypes.array.def(['hover']), |
||||
overlay: PropTypes.any, |
||||
visible: PropTypes.bool, |
||||
disabled: PropTypes.bool, |
||||
align: PropTypes.object, |
||||
getPopupContainer: PropTypes.func, |
||||
prefixCls: PropTypes.string, |
||||
transitionName: PropTypes.string, |
||||
placement: PropTypes.oneOf(['topLeft', 'topCenter', 'topRight', 'bottomLeft', 'bottomCenter', 'bottomRight']), |
||||
forceRender: PropTypes.bool, |
||||
}) |
@ -0,0 +1,43 @@
|
||||
## API |
||||
|
||||
### Dropdown |
||||
|
||||
| Property | Description | Type | Default | |
||||
| -------- | ----------- | ---- | ------- | |
||||
| disabled | whether the dropdown menu is disabled | boolean | - | |
||||
| getPopupContainer | to set the container of the dropdown menu. The default is to create a `div` element in `body`, you can reset it to the scrolling area and make a relative reposition. [example](https://codepen.io/afc163/pen/zEjNOy?editors=0010) | Function(triggerNode) | `() => document.body` | |
||||
| overlay(slot) | the dropdown menu | [Menu](#/components/us/menu) | - | |
||||
| placement | placement of pop menu: `bottomLeft` `bottomCenter` `bottomRight` `topLeft` `topCenter` `topRight` | String | `bottomLeft` | |
||||
| trigger | the trigger mode which executes the drop-down action | Array<`click`\|`hover`\|`contextMenu`> | `['hover']` | |
||||
| visible(v-model) | whether the dropdown menu is visible | boolean | - | |
||||
|
||||
### events |
||||
| Events Name | Description | Arguments | |
||||
| --- | --- | --- | |
||||
| visibleChange | a callback function takes an argument: `visible`, is executed when the visible state is changed | function(visible) | |
||||
|
||||
You should use [Menu](#/components/us/menu/) as `overlay`. The menu items and dividers are also available by using `Menu.Item` and `Menu.Divider`. |
||||
|
||||
> Warning: You must set a unique `key` for `Menu.Item`. |
||||
> |
||||
> Menu of Dropdown is unselectable by default, you can make it selectable via `<Menu selectable>`. |
||||
|
||||
### Dropdown.Button |
||||
|
||||
| Property | Description | Type | Default | |
||||
| -------- | ----------- | ---- | ------- | |
||||
| disabled | whether the dropdown menu is disabled | boolean | - | |
||||
| overlay(slot) | the dropdown menu | [Menu](#/components/us/menu) | - | |
||||
| placement | placement of pop menu: `bottomLeft` `bottomCenter` `bottomRight` `topLeft` `topCenter` `topRight` | String | `bottomLeft` | |
||||
| size | size of the button, the same as [Button](#/components/us/button) | string | `default` | |
||||
| trigger | the trigger mode which executes the drop-down action | Array<`click`\|`hover`\|`contextMenu`> | `['hover']` | |
||||
| type | type of the button, the same as [Button](#/components/us/button) | string | `default` | |
||||
| visible | whether the dropdown menu is visible | boolean | - | |
||||
|
||||
|
||||
|
||||
### Dropdown.Button events |
||||
| Events Name | Description | Arguments | |
||||
| --- | --- | --- | |
||||
| click | a callback function, the same as [Button](#/components/us/button), which will be executed when you click the button on the left | Function | |
||||
| visibleChange | a callback function takes an argument: `visible`, is executed when the visible state is changed | Function | |
@ -0,0 +1,8 @@
|
||||
import Dropdown from './dropdown' |
||||
import DropdownButton from './dropdown-button' |
||||
|
||||
export { DropDownProps } from './dropdown' |
||||
export { DropdownButtonProps } from './dropdown-button' |
||||
|
||||
Dropdown.Button = DropdownButton |
||||
export default Dropdown |
@ -0,0 +1,42 @@
|
||||
## API |
||||
|
||||
属性如下 |
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | |
||||
| --- | --- | --- | --- | |
||||
| disabled | 菜单是否禁用 | boolean | - | |
||||
| getPopupContainer | 菜单渲染父节点。默认渲染到 body 上,如果你遇到菜单滚动定位问题,试试修改为滚动的区域,并相对其定位。 | Function(triggerNode) | `() => document.body` | |
||||
| overlay(slot) | 菜单 | [Menu](#/components/cn/menu) | - | |
||||
| placement | 菜单弹出位置:`bottomLeft` `bottomCenter` `bottomRight` `topLeft` `topCenter` `topRight` | String | `bottomLeft` | |
||||
| trigger | 触发下拉的行为 | Array<`click`\|`hover`\|`contextMenu`> | `['hover']` | |
||||
| visible(v-model) | 菜单是否显示 | boolean | - | |
||||
|
||||
`overlay` 菜单使用 [Menu](#/components/cn/menu/),还包括菜单项 `Menu.Item`,分割线 `Menu.Divider`。 |
||||
|
||||
> 注意: Menu.Item 必须设置唯一的 key 属性。 |
||||
> |
||||
> Dropdown 下的 Menu 默认不可选中。如果需要菜单可选中,可以指定 `<Menu selectable>`. |
||||
|
||||
### 事件 |
||||
| 事件名称 | 说明 | 回调参数 | |
||||
| --- | --- | --- | |
||||
| visibleChange | 菜单显示状态改变时调用,参数为 visible | function(visible) | |
||||
|
||||
|
||||
### Dropdown.Button |
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | |
||||
| --- | --- | --- | --- | |
||||
| disabled | 菜单是否禁用 | boolean | - | |
||||
| overlay(slot) | 菜单 | [Menu](#/components/cn/menu/) | - | |
||||
| placement | 菜单弹出位置:`bottomLeft` `bottomCenter` `bottomRight` `topLeft` `topCenter` `topRight` | String | `bottomLeft` | |
||||
| size | 按钮大小,和 [Button](#/components/cn/button/) 一致 | string | 'default' | |
||||
| trigger | 触发下拉的行为 | Array<`click`\|`hover`\|`contextMenu`> | `['hover']` | |
||||
| type | 按钮类型,和 [Button](#/components/cn/button/) 一致 | string | 'default' | |
||||
| visible(v-model) | 菜单是否显示 | boolean | - | |
||||
|
||||
### Dropdown.Button事件 |
||||
| 事件名称 | 说明 | 回调参数 | |
||||
| --- | --- | --- | |
||||
| click | 点击左侧按钮的回调,和 [Button](#/components/cn/button/) 一致 | Function | |
||||
| visibleChange | 菜单显示状态改变时调用,参数为 visible | function(visible) | |
@ -0,0 +1,157 @@
|
||||
<script> |
||||
import PropTypes from '../../_util/vue-types' |
||||
import Trigger from '../../trigger' |
||||
import placements from './placements' |
||||
import { hasProp } from '../../_util/props-util' |
||||
import BaseMixin from '../../_util/BaseMixin' |
||||
import { cloneElement, getEvents } from '../../_util/vnode' |
||||
|
||||
export default { |
||||
mixins: [BaseMixin], |
||||
props: { |
||||
minOverlayWidthMatchTrigger: PropTypes.bool.def(true), |
||||
prefixCls: PropTypes.string.def('rc-dropdown'), |
||||
transitionName: PropTypes.string, |
||||
overlayClassName: PropTypes.string.def(''), |
||||
animation: PropTypes.any, |
||||
align: PropTypes.object, |
||||
overlayStyle: PropTypes.object.def({}), |
||||
placement: PropTypes.string.def('bottomLeft'), |
||||
trigger: PropTypes.array.def(['hover']), |
||||
showAction: PropTypes.array.def([]), |
||||
hideAction: PropTypes.array.def([]), |
||||
getPopupContainer: PropTypes.func, |
||||
visible: PropTypes.bool, |
||||
defaultVisible: PropTypes.bool.def(false), |
||||
mouseEnterDelay: PropTypes.number.def(0.15), |
||||
mouseLeaveDelay: PropTypes.number.def(0.1), |
||||
}, |
||||
data () { |
||||
let sVisible = this.defaultVisible |
||||
if (hasProp(this, 'visible')) { |
||||
sVisible = this.visible |
||||
} |
||||
return { |
||||
sVisible, |
||||
} |
||||
}, |
||||
watch: { |
||||
visible (val) { |
||||
if (val !== undefined) { |
||||
this.setState({ |
||||
sVisible: val, |
||||
}) |
||||
} |
||||
}, |
||||
}, |
||||
methods: { |
||||
onClick (e) { |
||||
// do no call onVisibleChange, if you need click to hide, use onClick and control visible |
||||
if (!hasProp(this, 'visible')) { |
||||
this.setState({ |
||||
sVisible: false, |
||||
}) |
||||
} |
||||
this.$emit('overlayClick', e) |
||||
if (this.childOriginEvents.click) { |
||||
this.childOriginEvents.click(e) |
||||
} |
||||
}, |
||||
|
||||
onVisibleChange (visible) { |
||||
if (!hasProp(this, 'visible')) { |
||||
this.setState({ |
||||
sVisible: visible, |
||||
}) |
||||
} |
||||
this.__emit('visibleChange', visible) |
||||
}, |
||||
|
||||
getMenuElement () { |
||||
const child = this.$slots.overlay[0] |
||||
const events = getEvents(child) |
||||
if (!events._ANT_DROPDOWN_EVENT_HACK) { |
||||
this.childOriginEvents = events |
||||
} |
||||
const { prefixCls } = this.$props |
||||
const extraOverlayProps = { |
||||
prefixCls: `${prefixCls}-menu`, |
||||
} |
||||
const overlay = this.$slots.overlay[0] |
||||
return cloneElement(overlay, { |
||||
props: extraOverlayProps, |
||||
on: { |
||||
click: this.onClick, |
||||
_ANT_DROPDOWN_EVENT_HACK: () => {}, |
||||
}, |
||||
}) |
||||
}, |
||||
|
||||
getPopupDomNode () { |
||||
return this.$refs.trigger.getPopupDomNode() |
||||
}, |
||||
|
||||
afterVisibleChange (visible) { |
||||
if (visible && this.$props.minOverlayWidthMatchTrigger) { |
||||
const overlayNode = this.getPopupDomNode() |
||||
const rootNode = this.$el |
||||
if (rootNode && overlayNode && rootNode.offsetWidth > overlayNode.offsetWidth) { |
||||
overlayNode.style.width = `${rootNode.offsetWidth}px` |
||||
if (this.$refs.trigger && |
||||
this.$refs.trigger._component && |
||||
this.$refs.trigger._component.alignInstance) { |
||||
this.$refs.trigger._component.alignInstance.forceAlign() |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
}, |
||||
|
||||
render () { |
||||
const { |
||||
prefixCls, |
||||
transitionName, animation, |
||||
align, placement, getPopupContainer, |
||||
showAction, hideAction, |
||||
overlayClassName, overlayStyle, |
||||
trigger, ...otherProps |
||||
} = this.$props |
||||
|
||||
const triggerProps = { |
||||
props: { |
||||
...otherProps, |
||||
prefixCls, |
||||
popupClassName: overlayClassName, |
||||
popupStyle: overlayStyle, |
||||
builtinPlacements: placements, |
||||
action: trigger, |
||||
showAction, |
||||
hideAction, |
||||
popupPlacement: placement, |
||||
popupAlign: align, |
||||
popupTransitionName: transitionName, |
||||
popupAnimation: animation, |
||||
popupVisible: this.sVisible, |
||||
afterPopupVisibleChange: this.afterVisibleChange, |
||||
getPopupContainer: getPopupContainer, |
||||
}, |
||||
on: { |
||||
popupVisibleChange: this.onVisibleChange, |
||||
}, |
||||
ref: 'trigger', |
||||
} |
||||
const child = this.$slots.default && this.$slots.default[0] |
||||
return ( |
||||
<Trigger {...triggerProps}> |
||||
{child && !child.tag |
||||
? <span>{child}</span> |
||||
: child} |
||||
<template slot='popup'> |
||||
{this.$slots.overlay && this.getMenuElement()} |
||||
</template> |
||||
</Trigger> |
||||
) |
||||
}, |
||||
} |
||||
|
||||
</script> |
@ -0,0 +1,2 @@
|
||||
import Dropdown from './Dropdown' |
||||
export default Dropdown |
@ -0,0 +1,47 @@
|
||||
const autoAdjustOverflow = { |
||||
adjustX: 1, |
||||
adjustY: 1, |
||||
} |
||||
|
||||
const targetOffset = [0, 0] |
||||
|
||||
export const placements = { |
||||
topLeft: { |
||||
points: ['bl', 'tl'], |
||||
overflow: autoAdjustOverflow, |
||||
offset: [0, -4], |
||||
targetOffset, |
||||
}, |
||||
topCenter: { |
||||
points: ['bc', 'tc'], |
||||
overflow: autoAdjustOverflow, |
||||
offset: [0, -4], |
||||
targetOffset, |
||||
}, |
||||
topRight: { |
||||
points: ['br', 'tr'], |
||||
overflow: autoAdjustOverflow, |
||||
offset: [0, -4], |
||||
targetOffset, |
||||
}, |
||||
bottomLeft: { |
||||
points: ['tl', 'bl'], |
||||
overflow: autoAdjustOverflow, |
||||
offset: [0, 4], |
||||
targetOffset, |
||||
}, |
||||
bottomCenter: { |
||||
points: ['tc', 'bc'], |
||||
overflow: autoAdjustOverflow, |
||||
offset: [0, 4], |
||||
targetOffset, |
||||
}, |
||||
bottomRight: { |
||||
points: ['tr', 'br'], |
||||
overflow: autoAdjustOverflow, |
||||
offset: [0, 4], |
||||
targetOffset, |
||||
}, |
||||
} |
||||
|
||||
export default placements |
@ -0,0 +1,5 @@
|
||||
import '../../style/index.less' |
||||
import './index.less' |
||||
|
||||
// style dependencies
|
||||
import '../../button/style' |
@ -0,0 +1,250 @@
|
||||
@import "../../style/themes/default"; |
||||
@import "../../style/mixins/index"; |
||||
|
||||
@dropdown-prefix-cls: ~"@{ant-prefix}-dropdown"; |
||||
|
||||
.@{dropdown-prefix-cls} { |
||||
.reset-component; |
||||
position: absolute; |
||||
left: -9999px; |
||||
top: -9999px; |
||||
z-index: @zindex-dropdown; |
||||
display: block; |
||||
|
||||
&-wrap { |
||||
position: relative; |
||||
|
||||
.@{ant-prefix}-btn > .@{iconfont-css-prefix}-down { |
||||
.iconfont-size-under-12px(10px); |
||||
} |
||||
|
||||
.@{iconfont-css-prefix}-down:before { |
||||
transition: transform .2s; |
||||
} |
||||
} |
||||
|
||||
&-wrap-open { |
||||
.@{iconfont-css-prefix}-down:before { |
||||
transform: rotate(180deg); |
||||
} |
||||
} |
||||
|
||||
&-hidden, |
||||
&-menu-hidden { |
||||
display: none; |
||||
} |
||||
|
||||
&-menu { |
||||
outline: none; |
||||
position: relative; |
||||
list-style-type: none; |
||||
padding: 0; |
||||
margin: 0; |
||||
text-align: left; |
||||
background-color: @component-background; |
||||
border-radius: @border-radius-base; |
||||
box-shadow: @box-shadow-base; |
||||
background-clip: padding-box; |
||||
|
||||
&-item-group-title { |
||||
color: @text-color-secondary; |
||||
padding: 5px @control-padding-horizontal; |
||||
transition: all .3s; |
||||
} |
||||
|
||||
&-submenu-popup { |
||||
position: absolute; |
||||
} |
||||
|
||||
&-item, |
||||
&-submenu-title { |
||||
padding: 5px @control-padding-horizontal; |
||||
margin: 0; |
||||
clear: both; |
||||
font-size: @font-size-base; |
||||
font-weight: normal; |
||||
color: @text-color; |
||||
white-space: nowrap; |
||||
cursor: pointer; |
||||
transition: all .3s; |
||||
line-height: 22px; |
||||
|
||||
> a { |
||||
color: @text-color; |
||||
display: block; |
||||
padding: 5px @control-padding-horizontal; |
||||
margin: -5px -@control-padding-horizontal; |
||||
transition: all .3s; |
||||
&:focus { |
||||
text-decoration: none; |
||||
} |
||||
} |
||||
|
||||
&-selected, |
||||
&-selected > a { |
||||
color: @primary-color; |
||||
background-color: @item-active-bg; |
||||
} |
||||
|
||||
&:hover { |
||||
background-color: @item-hover-bg; |
||||
} |
||||
|
||||
&-disabled { |
||||
color: @disabled-color; |
||||
cursor: not-allowed; |
||||
|
||||
&:hover { |
||||
color: @disabled-color; |
||||
background-color: @component-background; |
||||
cursor: not-allowed; |
||||
} |
||||
} |
||||
|
||||
&:first-child, |
||||
&:first-child > a { |
||||
border-radius: @border-radius-base @border-radius-base 0 0; |
||||
} |
||||
|
||||
&:last-child, |
||||
&:last-child > a { |
||||
border-radius: 0 0 @border-radius-base @border-radius-base; |
||||
} |
||||
|
||||
&:only-child, |
||||
&:only-child > a { |
||||
border-radius: @border-radius-base; |
||||
} |
||||
|
||||
&-divider { |
||||
height: 1px; |
||||
overflow: hidden; |
||||
background-color: @border-color-split; |
||||
line-height: 0; |
||||
} |
||||
.@{dropdown-prefix-cls}-menu-submenu-arrow { |
||||
position: absolute; |
||||
right: @padding-xs; |
||||
&:after { |
||||
font-family: "anticon" !important; |
||||
font-style: normal; |
||||
content: "\e61f"; |
||||
color: @text-color-secondary; |
||||
.iconfont-size-under-12px(10px); |
||||
} |
||||
} |
||||
} |
||||
|
||||
&-submenu-title { |
||||
padding-right: 26px; |
||||
&:first-child, |
||||
&:last-child { |
||||
border-radius: 0; |
||||
} |
||||
} |
||||
|
||||
&-submenu-vertical { |
||||
position: relative; |
||||
} |
||||
|
||||
&-submenu-vertical > & { |
||||
top: 0; |
||||
left: 100%; |
||||
position: absolute; |
||||
min-width: 100%; |
||||
margin-left: 4px; |
||||
transform-origin: 0 0; |
||||
} |
||||
|
||||
&-submenu&-submenu-disabled .@{dropdown-prefix-cls}-menu-submenu-title { |
||||
&, |
||||
.@{dropdown-prefix-cls}-menu-submenu-arrow:after { |
||||
color: @disabled-color; |
||||
} |
||||
} |
||||
&-submenu:first-child &-submenu-title { |
||||
border-radius: @border-radius-base @border-radius-base 0 0; |
||||
} |
||||
|
||||
&-submenu:last-child &-submenu-title { |
||||
border-radius: 0 0 @border-radius-base @border-radius-base; |
||||
} |
||||
} |
||||
|
||||
&.slide-down-enter.slide-down-enter-active&-placement-bottomLeft, |
||||
&.slide-down-appear.slide-down-appear-active&-placement-bottomLeft, |
||||
&.slide-down-enter.slide-down-enter-active&-placement-bottomCenter, |
||||
&.slide-down-appear.slide-down-appear-active&-placement-bottomCenter, |
||||
&.slide-down-enter.slide-down-enter-active&-placement-bottomRight, |
||||
&.slide-down-appear.slide-down-appear-active&-placement-bottomRight { |
||||
animation-name: antSlideUpIn; |
||||
} |
||||
|
||||
&.slide-up-enter.slide-up-enter-active&-placement-topLeft, |
||||
&.slide-up-appear.slide-up-appear-active&-placement-topLeft, |
||||
&.slide-up-enter.slide-up-enter-active&-placement-topCenter, |
||||
&.slide-up-appear.slide-up-appear-active&-placement-topCenter, |
||||
&.slide-up-enter.slide-up-enter-active&-placement-topRight, |
||||
&.slide-up-appear.slide-up-appear-active&-placement-topRight { |
||||
animation-name: antSlideDownIn; |
||||
} |
||||
|
||||
&.slide-down-leave.slide-down-leave-active&-placement-bottomLeft, |
||||
&.slide-down-leave.slide-down-leave-active&-placement-bottomCenter, |
||||
&.slide-down-leave.slide-down-leave-active&-placement-bottomRight { |
||||
animation-name: antSlideUpOut; |
||||
} |
||||
|
||||
&.slide-up-leave.slide-up-leave-active&-placement-topLeft, |
||||
&.slide-up-leave.slide-up-leave-active&-placement-topCenter, |
||||
&.slide-up-leave.slide-up-leave-active&-placement-topRight { |
||||
animation-name: antSlideDownOut; |
||||
} |
||||
} |
||||
|
||||
.@{dropdown-prefix-cls}-trigger, |
||||
.@{dropdown-prefix-cls}-link { |
||||
.@{iconfont-css-prefix}-down { |
||||
.iconfont-size-under-12px(10px); |
||||
} |
||||
} |
||||
|
||||
.@{dropdown-prefix-cls}-button { |
||||
white-space: nowrap; |
||||
|
||||
&.@{ant-prefix}-btn-group > .@{ant-prefix}-btn:last-child:not(:first-child) { |
||||
padding-left: @padding-xs; |
||||
padding-right: @padding-xs; |
||||
} |
||||
.@{iconfont-css-prefix}-down { |
||||
.iconfont-size-under-12px(10px); |
||||
} |
||||
} |
||||
|
||||
// https://github.com/ant-design/ant-design/issues/4903 |
||||
.@{dropdown-prefix-cls}-menu-dark { |
||||
&, |
||||
.@{dropdown-prefix-cls}-menu { |
||||
background: @menu-dark-bg; |
||||
} |
||||
.@{dropdown-prefix-cls}-menu-item, |
||||
.@{dropdown-prefix-cls}-menu-submenu-title, |
||||
.@{dropdown-prefix-cls}-menu-item > a { |
||||
color: @text-color-secondary-dark; |
||||
.@{dropdown-prefix-cls}-menu-submenu-arrow:after { |
||||
color: @text-color-secondary-dark; |
||||
} |
||||
&:hover { |
||||
color: #fff; |
||||
background: transparent; |
||||
} |
||||
} |
||||
.@{dropdown-prefix-cls}-menu-item-selected { |
||||
&, |
||||
&:hover, |
||||
> a { |
||||
background: @primary-color; |
||||
color: #fff; |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue