mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-04-06 03:57:59 +08:00
[new feature] add DropdownMenu component
This commit is contained in:
parent
9c9642ee1f
commit
a26be4819c
@ -52,6 +52,7 @@
|
||||
## 新特性
|
||||
|
||||
- 新增`Skeleton`骨架屏组件
|
||||
- 新增`DropdownMenu`下拉菜单组件
|
||||
|
||||
### ActionSheet
|
||||
|
||||
|
@ -18,6 +18,7 @@ export default {
|
||||
'coupon-list': () => wrapper(import('../../packages/coupon-list/demo'), 'coupon-list'),
|
||||
'datetime-picker': () => wrapper(import('../../packages/datetime-picker/demo'), 'datetime-picker'),
|
||||
'dialog': () => wrapper(import('../../packages/dialog/demo'), 'dialog'),
|
||||
'dropdown-menu': () => wrapper(import('../../packages/dropdown-menu/demo'), 'dropdown-menu'),
|
||||
'field': () => wrapper(import('../../packages/field/demo'), 'field'),
|
||||
'goods-action': () => wrapper(import('../../packages/goods-action/demo'), 'goods-action'),
|
||||
'icon': () => wrapper(import('../../packages/icon/demo'), 'icon'),
|
||||
|
@ -175,6 +175,10 @@ module.exports = {
|
||||
path: '/dialog',
|
||||
title: 'Dialog 弹出框'
|
||||
},
|
||||
{
|
||||
path: '/dropdown-menu',
|
||||
title: 'DropdownMenu 下拉菜单'
|
||||
},
|
||||
{
|
||||
path: '/loading',
|
||||
title: 'Loading 加载'
|
||||
@ -486,6 +490,10 @@ module.exports = {
|
||||
path: '/dialog',
|
||||
title: 'Dialog'
|
||||
},
|
||||
{
|
||||
path: '/dropdown-menu',
|
||||
title: 'DropdownMenu'
|
||||
},
|
||||
{
|
||||
path: '/loading',
|
||||
title: 'Loading'
|
||||
|
@ -43,6 +43,8 @@ export default {
|
||||
'datetime-picker.zh-CN': () => import('../../packages/datetime-picker/zh-CN.md'),
|
||||
'dialog.en-US': () => import('../../packages/dialog/en-US.md'),
|
||||
'dialog.zh-CN': () => import('../../packages/dialog/zh-CN.md'),
|
||||
'dropdown-menu.en-US': () => import('../../packages/dropdown-menu/en-US.md'),
|
||||
'dropdown-menu.zh-CN': () => import('../../packages/dropdown-menu/zh-CN.md'),
|
||||
'field.en-US': () => import('../../packages/field/en-US.md'),
|
||||
'field.zh-CN': () => import('../../packages/field/zh-CN.md'),
|
||||
'goods-action.en-US': () => import('../../packages/goods-action/en-US.md'),
|
||||
|
85
packages/dropdown-item/index.js
Normal file
85
packages/dropdown-item/index.js
Normal file
@ -0,0 +1,85 @@
|
||||
import { use, isDef } from '../utils';
|
||||
import Cell from '../cell';
|
||||
import Icon from '../icon';
|
||||
import Popup from '../popup';
|
||||
|
||||
const [sfc, bem] = use('dropdown-item');
|
||||
|
||||
export default sfc({
|
||||
props: {
|
||||
value: null,
|
||||
title: String,
|
||||
options: Array
|
||||
},
|
||||
|
||||
inject: ['vanDropdownMenu'],
|
||||
|
||||
data() {
|
||||
return {
|
||||
show: false
|
||||
};
|
||||
},
|
||||
|
||||
created() {
|
||||
const { items } = this.vanDropdownMenu;
|
||||
const index = this.vanDropdownMenu.slots().indexOf(this.$vnode);
|
||||
items.splice(index === -1 ? items.length : index, 0, this);
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
this.vanDropdownMenu.items = this.vanDropdownMenu.items.filter(item => item !== this);
|
||||
},
|
||||
|
||||
computed: {
|
||||
displayTitle() {
|
||||
if (this.title) {
|
||||
return this.title;
|
||||
}
|
||||
|
||||
const match = this.options.filter(option => option.value === this.value);
|
||||
return match.length ? match[0].text : '';
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
toggle(show) {
|
||||
this.show = isDef(show) ? show : !this.show;
|
||||
}
|
||||
},
|
||||
|
||||
render(h) {
|
||||
const { top, zIndex, activeColor } = this.vanDropdownMenu;
|
||||
|
||||
const Options = this.options.map(option => {
|
||||
const active = option.value === this.value;
|
||||
return (
|
||||
<Cell
|
||||
clickable
|
||||
title={option.text}
|
||||
titleStyle={{ color: active ? activeColor : '' }}
|
||||
onClick={() => {
|
||||
this.show = false;
|
||||
this.$emit('input', option.value);
|
||||
}}
|
||||
>
|
||||
{active && <Icon class={bem('icon')} color={activeColor} name="success" />}
|
||||
</Cell>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<div vShow={this.show} style={{ top: `${top}px`, zIndex }} class={bem()}>
|
||||
<Popup
|
||||
vModel={this.show}
|
||||
position="top"
|
||||
duration={0.2}
|
||||
class={bem('content')}
|
||||
overlayStyle={{ position: 'absolute' }}
|
||||
>
|
||||
{Options}
|
||||
{this.slots('default')}
|
||||
</Popup>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
18
packages/dropdown-item/index.less
Normal file
18
packages/dropdown-item/index.less
Normal file
@ -0,0 +1,18 @@
|
||||
@import '../style/var';
|
||||
|
||||
.van-dropdown-item {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
overflow: hidden;
|
||||
|
||||
&__content {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
display: block;
|
||||
line-height: inherit;
|
||||
}
|
||||
}
|
109
packages/dropdown-menu/demo/index.vue
Normal file
109
packages/dropdown-menu/demo/index.vue
Normal file
@ -0,0 +1,109 @@
|
||||
<template>
|
||||
<demo-section>
|
||||
<demo-block :title="$t('basicUsage')">
|
||||
<van-dropdown-menu>
|
||||
<van-dropdown-item
|
||||
v-model="value1"
|
||||
:options="option1"
|
||||
/>
|
||||
<van-dropdown-item
|
||||
v-model="value2"
|
||||
:options="option2"
|
||||
/>
|
||||
</van-dropdown-menu>
|
||||
</demo-block>
|
||||
|
||||
<demo-block :title="$t('customContent')">
|
||||
<van-dropdown-menu>
|
||||
<van-dropdown-item
|
||||
v-model="value1"
|
||||
:options="option1"
|
||||
/>
|
||||
<van-dropdown-item
|
||||
:title="$t('itemTitle')"
|
||||
ref="item"
|
||||
>
|
||||
<van-switch-cell
|
||||
v-model="switch1"
|
||||
:title="$t('switchTitle1')"
|
||||
/>
|
||||
<van-switch-cell
|
||||
v-model="switch2"
|
||||
:title="$t('switchTitle2')"
|
||||
/>
|
||||
<van-button
|
||||
type="info"
|
||||
block
|
||||
@click="onConfirm"
|
||||
>
|
||||
{{ $t('confirm') }}
|
||||
</van-button>
|
||||
</van-dropdown-item>
|
||||
</van-dropdown-menu>
|
||||
</demo-block>
|
||||
</demo-section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
i18n: {
|
||||
'zh-CN': {
|
||||
customContent: '自定义菜单内容',
|
||||
switchTitle1: '包邮',
|
||||
switchTitle2: '团购',
|
||||
itemTitle: '筛选',
|
||||
option1: [
|
||||
{ text: '全部商品', value: 0 },
|
||||
{ text: '新款商品', value: 1 },
|
||||
{ text: '活动商品', value: 2 }
|
||||
],
|
||||
option2: [
|
||||
{ text: '默认排序', value: 'a' },
|
||||
{ text: '好评排序', value: 'b' },
|
||||
{ text: '销量排序', value: 'c' },
|
||||
]
|
||||
},
|
||||
'en-US': {
|
||||
customContent: 'Custom Content',
|
||||
switchTitle1: 'Title',
|
||||
switchTitle2: 'Title',
|
||||
itemTitle: 'Title',
|
||||
option1: [
|
||||
{ text: 'Option1', value: 0 },
|
||||
{ text: 'Option2', value: 1 },
|
||||
{ text: 'Option3', value: 2 }
|
||||
],
|
||||
option2: [
|
||||
{ text: 'Option A', value: 'a' },
|
||||
{ text: 'Option B', value: 'b' },
|
||||
{ text: 'Option C', value: 'c' },
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
switch1: true,
|
||||
switch2: false,
|
||||
value1: 0,
|
||||
value2: 'a'
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
option1() {
|
||||
return this.$t('option1');
|
||||
},
|
||||
|
||||
option2() {
|
||||
return this.$t('option2');
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onConfirm() {
|
||||
this.$refs.item.toggle();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
100
packages/dropdown-menu/en-US.md
Normal file
100
packages/dropdown-menu/en-US.md
Normal file
@ -0,0 +1,100 @@
|
||||
## DropdownMenu
|
||||
|
||||
### Install
|
||||
|
||||
``` javascript
|
||||
import { DropdownMenu, DropdownItem } from 'vant';
|
||||
|
||||
Vue.use(DropdownMenu).use(DropdownItem);
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
#### Basic Usage
|
||||
|
||||
```html
|
||||
<van-dropdown-menu>
|
||||
<van-dropdown-item v-model="value1" :options="option1" />
|
||||
<van-dropdown-item v-model="value2" :options="option2" />
|
||||
</van-dropdown-menu>
|
||||
```
|
||||
|
||||
```js
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
value1: 0,
|
||||
value2: 'a',
|
||||
option1: [
|
||||
{ text: 'Option1', value: 0 },
|
||||
{ text: 'Option2', value: 1 },
|
||||
{ text: 'Option3', value: 2 }
|
||||
],
|
||||
option2: [
|
||||
{ text: 'Option A', value: 'a' },
|
||||
{ text: 'Option B', value: 'b' },
|
||||
{ text: 'Option C', value: 'c' },
|
||||
]
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### Custom Content
|
||||
|
||||
```html
|
||||
<van-dropdown-menu>
|
||||
<van-dropdown-item v-model="value" :options="option" />
|
||||
<van-dropdown-item title="Title" ref="item">
|
||||
<van-switch-cell v-model="switch1" title="Title" />
|
||||
<van-switch-cell v-model="switch2" title="Title" />
|
||||
<van-button block type="info" @click="onConfirm">Confirm</van-button>
|
||||
</van-dropdown-item>
|
||||
</van-dropdown-menu>
|
||||
```
|
||||
|
||||
```js
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
value: 0,
|
||||
switch1: false,
|
||||
switch2: false,
|
||||
option: [
|
||||
{ text: 'Option1', value: 0 },
|
||||
{ text: 'Option2', value: 1 },
|
||||
{ text: 'Option3', value: 2 }
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onConfirm() {
|
||||
this.$refs.item.toggle();
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### DropdownMenu Props
|
||||
|
||||
| Attribute | Description | Type | Default |
|
||||
|------|------|------|------|------|
|
||||
| active-color | Active color of title and option | `String` | `#1989fa` |
|
||||
| z-index | z-index of menu item | `Number` | `10` |
|
||||
|
||||
### DropdownItem Props
|
||||
|
||||
| Attribute | Description | Type | Default |
|
||||
|------|------|------|------|------|
|
||||
| value | Value of current option,can use `v-model` | `String | Number` | - |
|
||||
| title | Item title | `String` | Text of selected option |
|
||||
| options | Options | `Array` | `[]` |
|
||||
|
||||
### DropdownItem Methods
|
||||
|
||||
Use ref to get DropdownItem instance and call instance methods
|
||||
|
||||
| Name | Attribute | Return value | Description |
|
||||
|------|------|------|------|
|
||||
| toggle | show: boolean | - | Toggle display |
|
71
packages/dropdown-menu/index.js
Normal file
71
packages/dropdown-menu/index.js
Normal file
@ -0,0 +1,71 @@
|
||||
import { use } from '../utils';
|
||||
import { BLUE } from '../utils/color';
|
||||
|
||||
const [sfc, bem] = use('dropdown-menu');
|
||||
|
||||
export default sfc({
|
||||
props: {
|
||||
zIndex: {
|
||||
type: Number,
|
||||
default: 10
|
||||
},
|
||||
activeColor: {
|
||||
type: String,
|
||||
default: BLUE
|
||||
}
|
||||
},
|
||||
|
||||
provide() {
|
||||
return {
|
||||
vanDropdownMenu: this
|
||||
};
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
top: 0,
|
||||
items: []
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
toggleItem(active) {
|
||||
const { menu } = this.$refs;
|
||||
const rect = menu.getBoundingClientRect();
|
||||
this.top = rect.y + rect.height;
|
||||
|
||||
this.items.forEach((item, index) => {
|
||||
if (index === active) {
|
||||
item.toggle();
|
||||
} else {
|
||||
item.toggle(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
render(h) {
|
||||
const Titles = this.items.map((item, index) => (
|
||||
<div
|
||||
class={bem('item')}
|
||||
onClick={() => {
|
||||
this.toggleItem(index);
|
||||
}}
|
||||
>
|
||||
<span
|
||||
class={bem('title', { active: item.show })}
|
||||
style={{ color: item.show ? this.activeColor : '' }}
|
||||
>
|
||||
{item.displayTitle}
|
||||
</span>
|
||||
</div>
|
||||
));
|
||||
|
||||
return (
|
||||
<div ref="menu" class={[bem(), 'van-hairline--top-bottom']}>
|
||||
{Titles}
|
||||
{this.slots('default')}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
43
packages/dropdown-menu/index.less
Normal file
43
packages/dropdown-menu/index.less
Normal file
@ -0,0 +1,43 @@
|
||||
@import '../style/var';
|
||||
|
||||
.van-dropdown-menu {
|
||||
display: flex;
|
||||
height: 50px;
|
||||
user-select: none;
|
||||
background-color: @white;
|
||||
|
||||
&__item {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&:active {
|
||||
opacity: .7;
|
||||
}
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: 15px;
|
||||
position: relative;
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
content: '';
|
||||
top: 3px;
|
||||
right: -12px;
|
||||
opacity: .6;
|
||||
border: 3px solid;
|
||||
transform: rotate(-45deg);
|
||||
border-color: transparent transparent currentColor currentColor;
|
||||
}
|
||||
|
||||
&--active {
|
||||
&::after {
|
||||
top: 7px;
|
||||
opacity: 1;
|
||||
transform: rotate(135deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
26
packages/dropdown-menu/test/__snapshots__/demo.spec.js.snap
Normal file
26
packages/dropdown-menu/test/__snapshots__/demo.spec.js.snap
Normal file
@ -0,0 +1,26 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders demo correctly 1`] = `
|
||||
<div>
|
||||
<div>
|
||||
<div class="van-dropdown-menu van-hairline--top-bottom">
|
||||
<div class="van-dropdown-item" style="top:0px;z-index:10;display:none;">
|
||||
<!---->
|
||||
</div>
|
||||
<div class="van-dropdown-item" style="top:0px;z-index:10;display:none;">
|
||||
<!---->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="van-dropdown-menu van-hairline--top-bottom">
|
||||
<div class="van-dropdown-item" style="top:0px;z-index:10;display:none;">
|
||||
<!---->
|
||||
</div>
|
||||
<div class="van-dropdown-item" style="top:0px;z-index:10;display:none;">
|
||||
<!---->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
137
packages/dropdown-menu/test/__snapshots__/index.spec.js.snap
Normal file
137
packages/dropdown-menu/test/__snapshots__/index.spec.js.snap
Normal file
@ -0,0 +1,137 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`click option 1`] = `
|
||||
<div class="van-dropdown-menu van-hairline--top-bottom">
|
||||
<div class="van-dropdown-menu__item"><span class="van-dropdown-menu__title">B</span></div>
|
||||
<div class="van-dropdown-menu__item"><span class="van-dropdown-menu__title">B</span></div>
|
||||
<div class="van-dropdown-item" style="top: 0px; z-index: 10; display: none;">
|
||||
<div class="van-popup van-popup--top van-dropdown-item__content" style="transition-duration: 0.2s; display: none;" name="van-popup-slide-top">
|
||||
<div class="van-cell van-cell--clickable">
|
||||
<div class="van-cell__title" style=""><span>A</span></div>
|
||||
</div>
|
||||
<div class="van-cell van-cell--clickable">
|
||||
<div class="van-cell__title" style="color: rgb(25, 137, 250);"><span>B</span></div>
|
||||
<div class="van-cell__value"><i class="van-icon van-icon-success van-dropdown-item__icon" style="color: rgb(25, 137, 250);">
|
||||
<!----></i></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="van-dropdown-item" style="top: 0px; z-index: 10; display: none;">
|
||||
<!---->
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`destroy one item 1`] = `
|
||||
<div class="van-dropdown-menu van-hairline--top-bottom">
|
||||
<div class="van-dropdown-menu__item"><span class="van-dropdown-menu__title">A</span></div>
|
||||
<!---->
|
||||
<div class="van-dropdown-item" style="top: 0px; z-index: 10; display: none;">
|
||||
<!---->
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`didn\`t find matched option 1`] = `
|
||||
<div class="van-dropdown-menu van-hairline--top-bottom">
|
||||
<div class="van-dropdown-menu__item"><span class="van-dropdown-menu__title"></span></div>
|
||||
<div class="van-dropdown-menu__item"><span class="van-dropdown-menu__title"></span></div>
|
||||
<div class="van-dropdown-item" style="top: 0px; z-index: 10; display: none;">
|
||||
<!---->
|
||||
</div>
|
||||
<div class="van-dropdown-item" style="top: 0px; z-index: 10; display: none;">
|
||||
<!---->
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`show dropdown item 1`] = `
|
||||
<div class="van-dropdown-menu van-hairline--top-bottom">
|
||||
<div class="van-dropdown-menu__item"><span class="van-dropdown-menu__title van-dropdown-menu__title--active" style="color: rgb(25, 137, 250);">A</span></div>
|
||||
<div class="van-dropdown-menu__item"><span class="van-dropdown-menu__title">A</span></div>
|
||||
<div class="van-dropdown-item" style="top: 0px; z-index: 10;">
|
||||
<div class="van-popup van-popup--top van-dropdown-item__content" style="transition-duration: 0.2s;" name="van-popup-slide-top">
|
||||
<div class="van-cell van-cell--clickable">
|
||||
<div class="van-cell__title" style="color: rgb(25, 137, 250);"><span>A</span></div>
|
||||
<div class="van-cell__value"><i class="van-icon van-icon-success van-dropdown-item__icon" style="color: rgb(25, 137, 250);">
|
||||
<!----></i></div>
|
||||
</div>
|
||||
<div class="van-cell van-cell--clickable">
|
||||
<div class="van-cell__title"><span>B</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="van-overlay van-fade-enter van-fade-enter-active" style="z-index: 2000; z-index: 2000; position: absolute;"></div>
|
||||
</div>
|
||||
<div class="van-dropdown-item" style="top: 0px; z-index: 10; display: none;">
|
||||
<!---->
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`show dropdown item 2`] = `
|
||||
<div class="van-dropdown-menu van-hairline--top-bottom">
|
||||
<div class="van-dropdown-menu__item"><span class="van-dropdown-menu__title" style="">A</span></div>
|
||||
<div class="van-dropdown-menu__item"><span class="van-dropdown-menu__title">A</span></div>
|
||||
<div class="van-dropdown-item" style="top: 0px; z-index: 10; display: none;">
|
||||
<div class="van-popup van-popup--top van-dropdown-item__content" style="transition-duration: 0.2s; display: none;" name="van-popup-slide-top">
|
||||
<div class="van-cell van-cell--clickable">
|
||||
<div class="van-cell__title" style="color: rgb(25, 137, 250);"><span>A</span></div>
|
||||
<div class="van-cell__value"><i class="van-icon van-icon-success van-dropdown-item__icon" style="color: rgb(25, 137, 250);">
|
||||
<!----></i></div>
|
||||
</div>
|
||||
<div class="van-cell van-cell--clickable">
|
||||
<div class="van-cell__title"><span>B</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="van-overlay van-fade-leave van-fade-leave-active" style="z-index: 2000; z-index: 2000; position: absolute;"></div>
|
||||
</div>
|
||||
<div class="van-dropdown-item" style="top: 0px; z-index: 10; display: none;">
|
||||
<!---->
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`show dropdown item 3`] = `
|
||||
<div class="van-dropdown-menu van-hairline--top-bottom">
|
||||
<div class="van-dropdown-menu__item"><span class="van-dropdown-menu__title" style="">A</span></div>
|
||||
<div class="van-dropdown-menu__item"><span class="van-dropdown-menu__title van-dropdown-menu__title--active" style="color: rgb(25, 137, 250);">A</span></div>
|
||||
<div class="van-dropdown-item" style="top: 0px; z-index: 10; display: none;">
|
||||
<div class="van-popup van-popup--top van-dropdown-item__content" style="transition-duration: 0.2s; display: none;" name="van-popup-slide-top">
|
||||
<div class="van-cell van-cell--clickable">
|
||||
<div class="van-cell__title" style="color: rgb(25, 137, 250);"><span>A</span></div>
|
||||
<div class="van-cell__value"><i class="van-icon van-icon-success van-dropdown-item__icon" style="color: rgb(25, 137, 250);">
|
||||
<!----></i></div>
|
||||
</div>
|
||||
<div class="van-cell van-cell--clickable">
|
||||
<div class="van-cell__title"><span>B</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="van-dropdown-item" style="top: 0px; z-index: 10;">
|
||||
<div class="van-popup van-popup--top van-dropdown-item__content" style="transition-duration: 0.2s;" name="van-popup-slide-top">
|
||||
<div class="van-cell van-cell--clickable">
|
||||
<div class="van-cell__title" style="color: rgb(25, 137, 250);"><span>A</span></div>
|
||||
<div class="van-cell__value"><i class="van-icon van-icon-success van-dropdown-item__icon" style="color: rgb(25, 137, 250);">
|
||||
<!----></i></div>
|
||||
</div>
|
||||
<div class="van-cell van-cell--clickable">
|
||||
<div class="van-cell__title"><span>B</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="van-overlay van-fade-enter van-fade-enter-active" style="z-index: 2001; z-index: 2001; position: absolute;"></div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`title prop 1`] = `
|
||||
<div class="van-dropdown-menu van-hairline--top-bottom">
|
||||
<div class="van-dropdown-menu__item"><span class="van-dropdown-menu__title">Title</span></div>
|
||||
<div class="van-dropdown-menu__item"><span class="van-dropdown-menu__title">Title</span></div>
|
||||
<div class="van-dropdown-item" style="top: 0px; z-index: 10; display: none;">
|
||||
<!---->
|
||||
</div>
|
||||
<div class="van-dropdown-item" style="top: 0px; z-index: 10; display: none;">
|
||||
<!---->
|
||||
</div>
|
||||
</div>
|
||||
`;
|
4
packages/dropdown-menu/test/demo.spec.js
Normal file
4
packages/dropdown-menu/test/demo.spec.js
Normal file
@ -0,0 +1,4 @@
|
||||
import Demo from '../demo';
|
||||
import demoTest from '../../../test/demo-test';
|
||||
|
||||
demoTest(Demo);
|
100
packages/dropdown-menu/test/index.spec.js
Normal file
100
packages/dropdown-menu/test/index.spec.js
Normal file
@ -0,0 +1,100 @@
|
||||
import { mount, later } from '../../../test/utils';
|
||||
import DropdownMenu from '..';
|
||||
import DropdownItem from '../../dropdown-item';
|
||||
|
||||
function renderWrapper(options = {}) {
|
||||
return mount({
|
||||
template: `
|
||||
<dropdown-menu>
|
||||
<dropdown-item v-model="value" :title="title" :options="options" />
|
||||
<dropdown-item v-model="value" :title="title" :options="options" />
|
||||
</dropdown-menu>
|
||||
`,
|
||||
components: {
|
||||
DropdownItem,
|
||||
DropdownMenu
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
value: options.value || 0,
|
||||
title: options.title || '',
|
||||
options: [
|
||||
{ text: 'A', value: 0 },
|
||||
{ text: 'B', value: 1 }
|
||||
]
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
test('show dropdown item', async () => {
|
||||
const wrapper = renderWrapper();
|
||||
|
||||
await later();
|
||||
|
||||
const titles = wrapper.findAll('.van-dropdown-menu__title');
|
||||
|
||||
titles.at(0).trigger('click');
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
|
||||
titles.at(0).trigger('click');
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
|
||||
titles.at(1).trigger('click');
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('click option', async () => {
|
||||
const wrapper = renderWrapper();
|
||||
|
||||
await later();
|
||||
|
||||
const titles = wrapper.findAll('.van-dropdown-menu__title');
|
||||
titles.at(0).trigger('click');
|
||||
|
||||
const options = wrapper.findAll('.van-dropdown-item .van-cell');
|
||||
|
||||
options.at(1).trigger('click');
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('title prop', async () => {
|
||||
const wrapper = renderWrapper({ title: 'Title' });
|
||||
await later();
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('didn`t find matched option', async () => {
|
||||
const wrapper = renderWrapper({ value: -1 });
|
||||
await later();
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('destroy one item', async () => {
|
||||
const wrapper = mount({
|
||||
template: `
|
||||
<dropdown-menu>
|
||||
<dropdown-item v-if="render" v-model="value" :options="options" />
|
||||
<dropdown-item v-model="value" :options="options" />
|
||||
</dropdown-menu>
|
||||
`,
|
||||
components: {
|
||||
DropdownItem,
|
||||
DropdownMenu
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
value: 0,
|
||||
render: true,
|
||||
options: [
|
||||
{ text: 'A', value: 0 },
|
||||
{ text: 'B', value: 1 }
|
||||
]
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
await later();
|
||||
wrapper.setData({ render: false });
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
102
packages/dropdown-menu/zh-CN.md
Normal file
102
packages/dropdown-menu/zh-CN.md
Normal file
@ -0,0 +1,102 @@
|
||||
## DropdownMenu 下拉菜单
|
||||
|
||||
### 使用指南
|
||||
|
||||
``` javascript
|
||||
import { DropdownMenu, DropdownItem } from 'vant';
|
||||
|
||||
Vue.use(DropdownMenu).use(DropdownItem);
|
||||
```
|
||||
|
||||
### 代码演示
|
||||
|
||||
#### 基础用法
|
||||
|
||||
```html
|
||||
<van-dropdown-menu>
|
||||
<van-dropdown-item v-model="value1" :options="option1" />
|
||||
<van-dropdown-item v-model="value2" :options="option2" />
|
||||
</van-dropdown-menu>
|
||||
```
|
||||
|
||||
```js
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
value1: 0,
|
||||
value2: 'a',
|
||||
option1: [
|
||||
{ text: '全部商品', value: 0 },
|
||||
{ text: '新款商品', value: 1 },
|
||||
{ text: '活动商品', value: 2 }
|
||||
],
|
||||
option2: [
|
||||
{ text: '默认排序', value: 'a' },
|
||||
{ text: '好评排序', value: 'b' },
|
||||
{ text: '销量排序', value: 'c' },
|
||||
]
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### 自定义菜单内容
|
||||
|
||||
通过插槽可以自定义`DropdownItem`的内容,此时需要使用实例上的`toggle`方法手动控制菜单的显示
|
||||
|
||||
```html
|
||||
<van-dropdown-menu>
|
||||
<van-dropdown-item v-model="value" :options="option" />
|
||||
<van-dropdown-item title="筛选" ref="item">
|
||||
<van-switch-cell v-model="switch1" title="包邮" />
|
||||
<van-switch-cell v-model="switch2" title="团购" />
|
||||
<van-button block type="info" @click="onConfirm">确认</van-button>
|
||||
</van-dropdown-item>
|
||||
</van-dropdown-menu>
|
||||
```
|
||||
|
||||
```js
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
value: 0,
|
||||
switch1: false,
|
||||
switch2: false,
|
||||
option: [
|
||||
{ text: '全部商品', value: 0 },
|
||||
{ text: '新款商品', value: 1 },
|
||||
{ text: '活动商品', value: 2 }
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onConfirm() {
|
||||
this.$refs.item.toggle();
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### DropdownMenu Props
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
|------|------|------|------|------|
|
||||
| active-color | 菜单标题和选项的选中态颜色 | `String` | `#1989fa` | - |
|
||||
| z-index | 菜单栏 z-index 层级 | `Number` | `10` | - |
|
||||
|
||||
### DropdownItem Props
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
|------|------|------|------|------|
|
||||
| value | 当前选中项对应的 value,可以通过`v-model`双向绑定 | `String | Number` | - | - |
|
||||
| title | 菜单项标题 | `String` | 当前选中项文字 | - |
|
||||
| options | 选项数组 | `Array` | `[]` | - |
|
||||
|
||||
### DropdownItem 方法
|
||||
|
||||
通过 ref 可以获取到 DropdownItem 实例并调用实例方法
|
||||
|
||||
| 方法名 | 参数 | 返回值 | 介绍 |
|
||||
|------|------|------|------|
|
||||
| toggle | show: boolean | - | 切换菜单是否展示 |
|
@ -47,6 +47,8 @@
|
||||
/* action components */
|
||||
@import './action-sheet/index';
|
||||
@import './dialog/index';
|
||||
@import './dropdown-item/index';
|
||||
@import './dropdown-menu/index';
|
||||
@import './picker/index';
|
||||
@import './pull-refresh/index';
|
||||
@import './notify/index';
|
||||
|
@ -23,6 +23,8 @@ import CouponCell from './coupon-cell';
|
||||
import CouponList from './coupon-list';
|
||||
import DatetimePicker from './datetime-picker';
|
||||
import Dialog from './dialog';
|
||||
import DropdownItem from './dropdown-item';
|
||||
import DropdownMenu from './dropdown-menu';
|
||||
import Field from './field';
|
||||
import GoodsAction from './goods-action';
|
||||
import GoodsActionButton from './goods-action-button';
|
||||
@ -104,6 +106,8 @@ const components = [
|
||||
CouponList,
|
||||
DatetimePicker,
|
||||
Dialog,
|
||||
DropdownItem,
|
||||
DropdownMenu,
|
||||
Field,
|
||||
GoodsAction,
|
||||
GoodsActionButton,
|
||||
@ -190,6 +194,8 @@ export {
|
||||
CouponList,
|
||||
DatetimePicker,
|
||||
Dialog,
|
||||
DropdownItem,
|
||||
DropdownMenu,
|
||||
Field,
|
||||
GoodsAction,
|
||||
GoodsActionButton,
|
||||
|
@ -47,6 +47,7 @@ export default {
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### Props
|
||||
|
||||
| Attribute | Description | Type | Default |
|
||||
|
Loading…
x
Reference in New Issue
Block a user