feat: add DropdownMenu、DropdownItem component (#2181)

This commit is contained in:
aphasic 2019-10-23 12:00:24 +08:00 committed by neverland
parent 02dee88899
commit dd5d76dbb4
63 changed files with 1778 additions and 94 deletions

View File

@ -1 +1 @@
@import '../common/index.wxss';.van-action-sheet{max-height:90%!important;color:#333;color:var(--text-color,#333)}.van-action-sheet__cancel,.van-action-sheet__item{height:50px;font-size:16px;line-height:50px;text-align:center;background-color:#fff;background-color:var(--white,#fff)}.van-action-sheet__cancel--hover,.van-action-sheet__item--hover{background-color:#f2f3f5;background-color:var(--active-color,#f2f3f5)}.van-action-sheet__cancel{height:60px}.van-action-sheet__cancel:before{display:block;height:10px;content:" ";background-color:#f8f8f8;background-color:var(--background-color,#f8f8f8)}.van-action-sheet__item--disabled{color:#c9c9c9;color:var(--gray,#c9c9c9)}.van-action-sheet__item--disabled.van-action-sheet__item--hover{background-color:#fff;background-color:var(--white,#fff)}.van-action-sheet__subname{margin-left:5px;font-size:12px;color:#7d7e80;color:var(--gray-darker,#7d7e80)}.van-action-sheet__header{font-weight:500;font-size:16px;line-height:44px;text-align:center}.van-action-sheet__description{padding:16px;color:#7d7e80;font-size:14px;line-height:20px;text-align:center}.van-action-sheet__close{position:absolute!important;top:0;right:0;padding:0 15px;font-size:18px!important;line-height:inherit!important;color:#999;color:var(--gray-dark,#999)} @import '../common/index.wxss';.van-action-sheet{max-height:90%!important;color:#333;color:var(--action-sheet-item-text-color,#333)}.van-action-sheet__cancel,.van-action-sheet__item{font-size:16px;line-height:50px;text-align:center;background-color:#fff;background-color:var(--action-sheet-item-background,#fff)}.van-action-sheet__cancel--hover,.van-action-sheet__item--hover{background-color:#f2f3f5;background-color:var(--active-color,#f2f3f5)}.van-action-sheet__cancel{height:50px}.van-action-sheet__cancel:before{display:block;height:8px;content:" ";background-color:#f8f8f8;background-color:var(--action-sheet-cancel-padding-color,#f8f8f8)}.van-action-sheet__item--disabled{color:#c9c9c9;color:var(--action-sheet-item-disabled-text-color,#c9c9c9)}.van-action-sheet__item--disabled.van-action-sheet__item--hover{background-color:#fff;background-color:var(--action-sheet-item-background,#fff)}.van-action-sheet__subname{margin-left:4px;font-size:12px;color:#7d7e80;color:var(--action-sheet-subname-color,#7d7e80)}.van-action-sheet__header{font-weight:500;font-size:16px;line-height:44px;text-align:center}.van-action-sheet__description{padding:16px;color:#7d7e80;font-size:14px;line-height:20px;text-align:center}.van-action-sheet__close{position:absolute!important;top:0;right:0;padding:0 12px;font-size:18px!important;line-height:inherit!important;color:#999;color:var(--action-sheet-close-icon-color,#999)}

View File

@ -1 +1 @@
@import '../common/index.wxss';.van-button{position:relative;display:inline-block;box-sizing:border-box;height:44px;padding:0;font-size:16px;line-height:42px;text-align:center;vertical-align:middle;transition:opacity .2s;border-radius:2px;border-radius:var(--button-border-radius,2px);-webkit-appearance:none;-webkit-text-size-adjust:100%}.van-button:before{position:absolute;top:50%;left:50%;width:100%;height:100%;border:inherit;border-radius:inherit;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);opacity:0;content:" ";background-color:#000;background-color:var(--black,#000);border-color:#000;border-color:var(--black,#000)}.van-button:after{border-width:0}.van-button--active:before{opacity:.15}.van-button--unclickable:after{display:none}.van-button--default{color:#333;color:var(--button-default-color,#333);background-color:#fff;background-color:var(--button-default-background-color,#fff);border:1px solid #eee;border:1px solid var(--button-default-border-color,#eee)}.van-button--primary{color:#fff;color:var(--button-primary-color,#fff);background-color:#07c160;background-color:var(--button-primary-background-color,#07c160);border:1px solid #07c160;border:1px solid var(--button-primary-border-color,#07c160)}.van-button--info{color:#fff;color:var(--button-info-color,#fff);background-color:#1989fa;background-color:var(--button-info-background-color,#1989fa);border:1px solid #1989fa;border:1px solid var(--button-info-border-color,#1989fa)}.van-button--danger{color:#fff;color:var(--button-danger-color,#fff);background-color:#ee0a24;background-color:var(--button-danger-background-color,#ee0a24);border:1px solid #ee0a24;border:1px solid var(--button-danger-border-color,#ee0a24)}.van-button--warning{color:#fff;color:var(--button-warning-color,#fff);background-color:#ff976a;background-color:var(--button-warning-background-color,#ff976a);border:1px solid #ff976a;border:1px solid var(--button-warning-border-color,#ff976a)}.van-button--plain{background-color:#fff;background-color:var(--white,#fff)}.van-button--plain.van-button--primary{color:#07c160;color:var(--button-primary-background-color,#07c160)}.van-button--plain.van-button--info{color:#1989fa;color:var(--button-info-background-color,#1989fa)}.van-button--plain.van-button--danger{color:#ee0a24;color:var(--button-danger-background-color,#ee0a24)}.van-button--plain.van-button--warning{color:#ff976a;color:var(--button-warning-background-color,#ff976a)}.van-button--large{width:100%;height:50px;line-height:48px}.van-button--normal{padding:0 15px;font-size:14px}.van-button--small{min-width:60px;height:30px;padding:0 8px;font-size:12px;line-height:28px}.van-button--mini{display:inline-block;width:50px;height:22px;font-size:10px;line-height:20px}.van-button--mini+.van-button--mini{margin-left:5px}.van-button--block{display:block;width:100%}.van-button--round{border-radius:10em;border-radius:var(--button-round-border-radius,10em)}.van-button--square{border-radius:0}.van-button--disabled{opacity:.5}.van-button__text{display:inline}.van-button__loading-text{display:inline-block;margin-left:5px;vertical-align:middle}.van-button__icon{min-width:1em;line-height:inherit!important;vertical-align:top}.van-button__icon+.van-button__text:not(:empty){display:inline-block;margin-left:5px;vertical-align:top}.van-button--hairline{padding-top:1px;border-width:0}.van-button--hairline:after{border-color:inherit;border-width:1px;border-radius:4px;border-radius:calc(var(--button-border-radius, 2px)*2)}.van-button--hairline.van-button--round:after{border-radius:10em;border-radius:var(--button-round-border-radius,10em)}.van-button--hairline.van-button--square:after{border-radius:0} @import '../common/index.wxss';.van-button{position:relative;display:inline-block;box-sizing:border-box;height:44px;padding:0;font-size:16px;line-height:42px;text-align:center;vertical-align:middle;transition:opacity .2s;border-radius:2px;border-radius:var(--button-border-radius,2px);-webkit-appearance:none;-webkit-text-size-adjust:100%}.van-button:before{position:absolute;top:50%;left:50%;width:100%;height:100%;border:inherit;border-radius:inherit;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);opacity:0;content:" ";background-color:#000;background-color:var(--black,#000);border-color:#000;border-color:var(--black,#000)}.van-button:after{border-width:0}.van-button--active:before{opacity:.15}.van-button--unclickable:after{display:none}.van-button--default{color:#333;color:var(--button-default-color,#333);background-color:#fff;background-color:var(--button-default-background-color,#fff);border:1px solid #eee;border:1px solid var(--button-default-border-color,#eee)}.van-button--primary{color:#fff;color:var(--button-primary-color,#fff);background-color:#07c160;background-color:var(--button-primary-background-color,#07c160);border:1px solid #07c160;border:1px solid var(--button-primary-border-color,#07c160)}.van-button--info{color:#fff;color:var(--button-info-color,#fff);background-color:#1989fa;background-color:var(--button-info-background-color,#1989fa);border:1px solid #1989fa;border:1px solid var(--button-info-border-color,#1989fa)}.van-button--danger{color:#fff;color:var(--button-danger-color,#fff);background-color:#ee0a24;background-color:var(--button-danger-background-color,#ee0a24);border:1px solid #ee0a24;border:1px solid var(--button-danger-border-color,#ee0a24)}.van-button--warning{color:#fff;color:var(--button-warning-color,#fff);background-color:#ff976a;background-color:var(--button-warning-background-color,#ff976a);border:1px solid #ff976a;border:1px solid var(--button-warning-border-color,#ff976a)}.van-button--plain{background-color:#fff;background-color:var(--button-plain-background-color,#fff)}.van-button--plain.van-button--primary{color:#07c160;color:var(--button-primary-background-color,#07c160)}.van-button--plain.van-button--info{color:#1989fa;color:var(--button-info-background-color,#1989fa)}.van-button--plain.van-button--danger{color:#ee0a24;color:var(--button-danger-background-color,#ee0a24)}.van-button--plain.van-button--warning{color:#ff976a;color:var(--button-warning-background-color,#ff976a)}.van-button--large{width:100%;height:50px;line-height:48px}.van-button--normal{padding:0 15px;font-size:14px}.van-button--small{min-width:60px;height:30px;padding:0 8px;font-size:12px;line-height:28px}.van-button--mini{display:inline-block;width:50px;height:22px;font-size:10px;line-height:20px}.van-button--mini+.van-button--mini{margin-left:5px}.van-button--block{display:block;width:100%}.van-button--round{border-radius:10em;border-radius:var(--button-round-border-radius,10em)}.van-button--square{border-radius:0}.van-button--disabled{opacity:.5}.van-button__text{display:inline}.van-button__loading-text{display:inline-block;margin-left:5px;vertical-align:middle}.van-button__icon{min-width:1em;line-height:inherit!important;vertical-align:top}.van-button__icon+.van-button__text:not(:empty){display:inline-block;margin-left:5px;vertical-align:top}.van-button--hairline{padding-top:1px;border-width:0}.van-button--hairline:after{border-color:inherit;border-width:1px;border-radius:4px;border-radius:calc(var(--button-border-radius, 2px)*2)}.van-button--hairline.van-button--round:after{border-radius:10em;border-radius:var(--button-round-border-radius,10em)}.van-button--hairline.van-button--square:after{border-radius:0}

View File

@ -1 +1 @@
@import '../common/index.wxss';.van-card{position:relative;box-sizing:border-box;padding:5px 15px;font-size:12px;color:#333;color:var(--text-color,#333);background-color:#fafafa;background-color:var(--background-color-light,#fafafa)}.van-card__header{display:-webkit-flex;display:flex}.van-card__header--center{-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center}.van-card__thumb{position:relative;-webkit-flex:none;flex:none;width:90px;height:90px;margin-right:10px}.van-card__thumb:empty{display:none}.van-card__img{width:100%;height:100%}.van-card__content{position:relative;-webkit-flex:1;flex:1;min-width:0}.van-card__desc,.van-card__title{word-wrap:break-word}.van-card__title{font-weight:700;line-height:16px}.van-card__desc{color:#7d7e80;color:var(--gray-darker,#7d7e80)}.van-card__bottom,.van-card__desc{line-height:20px}.van-card__price{display:inline-block;font-weight:700;color:#ee0a24;color:var(--red,#ee0a24)}.van-card__origin-price{display:inline-block;margin-left:5px;font-size:10px;text-decoration:line-through;color:#7d7e80;color:var(--gray-darker,#7d7e80)}.van-card__num{float:right}.van-card__tag{position:absolute;top:2px;left:0}.van-card__footer{-webkit-flex:none;flex:none;width:100%;text-align:right} @import '../common/index.wxss';.van-card{position:relative;box-sizing:border-box;padding:8px 16px;font-size:12px;color:#333;color:var(--card-text-color,#333);background-color:#fafafa;background-color:var(--card-background-color,#fafafa)}.van-card__header{display:-webkit-flex;display:flex}.van-card__header--center{-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center}.van-card__thumb{position:relative;-webkit-flex:none;flex:none;width:90px;height:90px;margin-right:8px}.van-card__thumb:empty{display:none}.van-card__img{width:100%;height:100%}.van-card__content{position:relative;-webkit-flex:1;flex:1;min-width:0}.van-card__desc,.van-card__title{word-wrap:break-word}.van-card__title{font-weight:700;line-height:16px}.van-card__desc{color:#7d7e80;color:var(--card-desc-color,#7d7e80)}.van-card__bottom,.van-card__desc{line-height:20px}.van-card__price{display:inline-block;font-weight:700;color:#ee0a24;color:var(--card-price-color,#ee0a24)}.van-card__origin-price{display:inline-block;margin-left:5px;font-size:10px;text-decoration:line-through;color:#7d7e80;color:var(--card-origin-price-color,#7d7e80)}.van-card__num{float:right}.van-card__tag{position:absolute;top:2px;left:0}.van-card__footer{-webkit-flex:none;flex:none;width:100%;text-align:right}

View File

@ -1 +1 @@
@import '../common/index.wxss';.van-dialog{top:45%!important;width:320px;overflow:hidden;font-size:16px;border-radius:4px;background-color:#fff;background-color:var(--white,#fff)}@media (max-width:321px){.van-dialog{width:90%}}.van-dialog__header{padding-top:25px;font-weight:500;line-height:24px;text-align:center}.van-dialog__header--isolated{padding:25px 0}.van-dialog__message{max-height:60vh;padding:25px;overflow-y:auto;font-size:14px;line-height:20px;text-align:center;-webkit-overflow-scrolling:touch}.van-dialog__message-text{word-wrap:break-word}.van-dialog__message--has-title{padding-top:12px;color:#7d7e80;color:var(--gray-darker,#7d7e80)}.van-dialog__message--left{text-align:left}.van-dialog__message--right{text-align:right}.van-dialog__footer{display:-webkit-flex;display:flex}.van-dialog__button{-webkit-flex:1;flex:1}.van-dialog__cancel,.van-dialog__confirm{border:0!important}.van-dialog-bounce-enter{-webkit-transform:translate3d(-50%,-50%,0) scale(.7);transform:translate3d(-50%,-50%,0) scale(.7);opacity:0}.van-dialog-bounce-leave-active{-webkit-transform:translate3d(-50%,-50%,0) scale(.9);transform:translate3d(-50%,-50%,0) scale(.9);opacity:0} @import '../common/index.wxss';.van-dialog{top:45%!important;width:320px;overflow:hidden;font-size:16px;border-radius:16px;background-color:#fff;background-color:var(--white,#fff)}@media (max-width:321px){.van-dialog{width:90%}}.van-dialog__header{padding-top:25px;font-weight:500;line-height:24px;text-align:center}.van-dialog__header--isolated{padding:25px 0}.van-dialog__message{max-height:60vh;padding:25px;overflow-y:auto;font-size:14px;line-height:20px;text-align:center;-webkit-overflow-scrolling:touch}.van-dialog__message-text{word-wrap:break-word}.van-dialog__message--has-title{padding-top:12px;color:#7d7e80;color:var(--gray-darker,#7d7e80)}.van-dialog__message--left{text-align:left}.van-dialog__message--right{text-align:right}.van-dialog__footer{display:-webkit-flex;display:flex}.van-dialog__button{-webkit-flex:1;flex:1}.van-dialog__cancel,.van-dialog__confirm{border:0!important}.van-dialog-bounce-enter{-webkit-transform:translate3d(-50%,-50%,0) scale(.7);transform:translate3d(-50%,-50%,0) scale(.7);opacity:0}.van-dialog-bounce-leave-active{-webkit-transform:translate3d(-50%,-50%,0) scale(.9);transform:translate3d(-50%,-50%,0) scale(.9);opacity:0}

1
dist/dropdown-item/index.d.ts vendored Normal file
View File

@ -0,0 +1 @@
export {};

70
dist/dropdown-item/index.js vendored Normal file
View File

@ -0,0 +1,70 @@
import { VantComponent } from '../common/component';
VantComponent({
field: true,
relation: {
name: 'dropdown-menu',
type: 'ancestor',
linked(target) {
this.parent = target;
},
unlinked() {
this.parent = null;
}
},
props: {
value: null,
title: String,
disabled: Boolean,
titleClass: String,
options: {
type: Array,
value: []
}
},
data: {
transition: true,
showPopup: false,
showWrapper: false,
displayTitle: ''
},
created() {
this.setData({ displayTitle: this.computedDisplayTitle(this.data.value) });
},
methods: {
computedDisplayTitle(curValue) {
const { title, options } = this.data;
if (title) {
return title;
}
const match = options.filter(option => option.value === curValue);
const displayTitle = match.length ? match[0].text : '';
return displayTitle;
},
onClickOverlay() {
this.toggle();
this.$emit('close');
},
onOptionTap(event) {
let { value, displayTitle } = this.data;
const { option } = event.currentTarget.dataset;
const { value: optionValue } = option;
if (optionValue !== value) {
value = optionValue;
displayTitle = this.computedDisplayTitle(optionValue);
this.$emit('change', optionValue);
}
this.setData({ showPopup: false, value, displayTitle });
const time = this.data.duration || 0;
setTimeout(() => {
this.setData({ showWrapper: false });
}, time);
// parent 中的 itemListData 是 children 上的数据的集合
// 数据的更新由 children 各自维护,但是模板的更新需要额外触发 parent 的 setData
this.parent.setData({ itemListData: this.parent.data.itemListData });
},
toggle() {
const { childIndex } = this.data;
this.parent.toggleItem(childIndex);
}
}
});

8
dist/dropdown-item/index.json vendored Normal file
View File

@ -0,0 +1,8 @@
{
"component": true,
"usingComponents": {
"van-popup": "../popup/index",
"van-cell": "../cell/index",
"van-icon": "../icon/index"
}
}

44
dist/dropdown-item/index.wxml vendored Normal file
View File

@ -0,0 +1,44 @@
<wxs src="../wxs/utils.wxs" module="utils" />
<view
wx:if="{{ showWrapper }}"
class="{{ utils.bem('dropdown-item', direction) }}"
style="{{ wrapperStyle }}"
>
<van-popup
show="{{ showPopup }}"
custom-style="position: absolute;"
overlay-style="position: absolute;"
overlay="{{ overlay }}"
position="{{ direction === 'down' ? 'top' : 'bottom' }}"
duration="{{ transition ? duration : 0 }}"
close-on-click-overlay="{{ closeOnClickOverlay }}"
bind:close="onClickOverlay"
>
<van-cell
wx:for="{{ options }}"
wx:key="{{ item.value }}"
data-option="{{ item }}"
class="{{ utils.bem('dropdown-item__option', { active: item.value === value } ) }}"
clickable
icon="{{ item.icon }}"
bind:tap="onOptionTap"
>
<view
slot="title"
class="van-dropdown-item__title"
style="{{ item.value === value ? 'color:' + activeColor : '' }}"
>
{{ item.text }}
</view>
<van-icon
wx:if="{{ item.value === value }}"
name="success"
class="van-dropdown-item__icon"
color="{{ activeColor }}"
/>
</van-cell>
<slot />
</van-popup>
</view>

1
dist/dropdown-item/index.wxss vendored Normal file
View File

@ -0,0 +1 @@
@import '../common/index.wxss';.van-dropdown-item{position:fixed;right:0;left:0;overflow:hidden}.van-dropdown-item__option{text-align:left}.van-dropdown-item__option--active .van-dropdown-item__icon,.van-dropdown-item__option--active .van-dropdown-item__title{color:#1989fa}.van-dropdown-item--up{top:0}.van-dropdown-item--down{bottom:0}.van-dropdown-item__icon{display:block;line-height:inherit}

1
dist/dropdown-menu/index.d.ts vendored Normal file
View File

@ -0,0 +1 @@
export {};

148
dist/dropdown-menu/index.js vendored Normal file
View File

@ -0,0 +1,148 @@
import { VantComponent } from '../common/component';
import { addUnit } from '../common/utils';
let ARRAY = [];
VantComponent({
field: true,
relation: {
name: 'dropdown-item',
type: 'descendant',
linked(target) {
this.children = this.children || [];
// 透传 props 给 dropdown-item
const { overlay, duration, activeColor, closeOnClickOverlay, direction } = this.data;
this.updateChildData(target, {
overlay,
duration,
activeColor,
closeOnClickOverlay,
direction,
childIndex: this.children.length
});
this.children.push(target);
// 收集 dorpdown-item 的 data 挂在 data 上
target &&
this.setData({
itemListData: this.data.itemListData.concat([target.data])
});
},
unlinked(target) {
this.children = this.children.filter((child) => child !== target);
}
},
props: {
activeColor: String,
overlay: {
type: Boolean,
value: true
},
zIndex: {
type: Number,
value: 10
},
duration: {
type: Number,
value: 200
},
direction: {
type: String,
value: 'down'
},
closeOnClickOverlay: {
type: Boolean,
value: true
},
closeOnClickOutside: {
type: Boolean,
value: true
}
},
data: {
itemListData: []
},
created() {
ARRAY.push(this);
},
destroyed() {
ARRAY = ARRAY.filter(item => item !== this);
},
methods: {
updateChildData(childItem, newData, needRefreshList = false) {
childItem.setData(newData);
if (needRefreshList) {
// dropdown-item data 更新,涉及到 title 的展示,触发模板更新
this.setData({ itemListData: this.data.itemListData });
}
},
toggleItem(active) {
this.children.forEach((item, index) => {
const { showPopup } = item.data;
if (index === active) {
this.toggleChildItem(item);
}
else if (showPopup) {
this.toggleChildItem(item, false, { immediate: true });
}
});
},
toggleChildItem(childItem, show, options = {}) {
const { showPopup, duration } = childItem.data;
if (show === undefined)
show = !showPopup;
if (show === showPopup) {
return;
}
const newChildData = { transition: !options.immediate, showPopup: show };
if (!show) {
const time = options.immediate ? 0 : duration;
this.updateChildData(childItem, Object.assign({}, newChildData), true);
setTimeout(() => {
this.updateChildData(childItem, { showWrapper: false }, true);
}, time);
return;
}
this.getChildWrapperStyle().then((wrapperStyle = '') => {
this.updateChildData(childItem, Object.assign(Object.assign({}, newChildData), { wrapperStyle, showWrapper: true }), true);
});
},
close() {
this.children.forEach((item) => {
this.toggleChildItem(item, false, { immediate: true });
});
},
getChildWrapperStyle() {
const { windowHeight } = wx.getSystemInfoSync();
const { zIndex, direction } = this.data;
let offset = 0;
return this.getRect('.van-dropdown-menu').then(rect => {
const { top = 0, bottom = 0 } = rect;
if (direction === 'down') {
offset = bottom;
}
else {
offset = windowHeight - top;
}
let wrapperStyle = `z-index: ${zIndex};`;
if (direction === 'down') {
wrapperStyle += `top: ${addUnit(offset)};`;
}
else {
wrapperStyle += `bottom: ${addUnit(offset)};`;
}
return Promise.resolve(wrapperStyle);
});
},
onTitleTap(event) {
// item ---> dropdown-item
const { item, index } = event.currentTarget.dataset;
if (!item.disabled) {
// menuItem ---> dropdown-menu
ARRAY.forEach(menuItem => {
if (menuItem && menuItem.data.closeOnClickOutside && menuItem !== this) {
menuItem.close();
}
});
this.toggleItem(index);
}
}
}
});

3
dist/dropdown-menu/index.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"component": true
}

23
dist/dropdown-menu/index.wxml vendored Normal file
View File

@ -0,0 +1,23 @@
<wxs src="../wxs/utils.wxs" module="utils" />
<view class="van-dropdown-menu van-dropdown-menu--top-bottom">
<view
wx:for="{{ itemListData }}"
wx:key="index"
data-item="{{ item }}"
data-index="{{ index }}"
class="{{ utils.bem('dropdown-menu__item', { disabled: item.disabled }) }}"
bind:tap="onTitleTap"
>
<view
class="{{ item.titleClass }} {{ utils.bem('dropdown-menu__title', { active: item.showPopup, down: item.showPopup === (direction === 'down') }) }}"
style="{{ item.showPopup ? 'color:' + activeColor : '' }}"
>
<view class="van-ellipsis">
{{item.displayTitle}}
</view>
</view>
</view>
<slot />
</view>

1
dist/dropdown-menu/index.wxss vendored Normal file
View File

@ -0,0 +1 @@
@import '../common/index.wxss';.van-dropdown-menu{display:-webkit-flex;display:flex;height:50px;background-color:#fff;-webkit-user-select:none;user-select:none}.van-dropdown-menu__item{display:-webkit-flex;display:flex;-webkit-flex:1;flex:1;-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center;min-width:0}.van-dropdown-menu__item:active{opacity:.7}.van-dropdown-menu__item--disabled:active{opacity:1}.van-dropdown-menu__item--disabled .van-dropdown-menu__title{color:#999}.van-dropdown-menu__title{position:relative;box-sizing:border-box;max-width:100%;padding:0 8px;color:#333;font-size:15px;line-height:18px}.van-dropdown-menu__title:after{position:absolute;top:50%;right:-4px;margin-top:-5px;border-color:transparent transparent currentcolor currentcolor;border-style:solid;border-width:3px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);opacity:.8;content:""}.van-dropdown-menu__title--active{color:#1989fa}.van-dropdown-menu__title--down:after{margin-top:-1px;-webkit-transform:rotate(135deg);transform:rotate(135deg)}

1
dist/image/index.d.ts vendored Normal file
View File

@ -0,0 +1 @@
export {};

91
dist/image/index.js vendored Normal file
View File

@ -0,0 +1,91 @@
import { addUnit, isDef } from '../common/utils';
import { VantComponent } from '../common/component';
import { button } from '../mixins/button';
import { openType } from '../mixins/open-type';
VantComponent({
mixins: [button, openType],
classes: ['custom-class', 'loading-class', 'error-class', 'image-class'],
props: {
src: String,
width: String,
height: String,
fit: {
type: String,
value: 'fill'
},
round: Boolean,
lazyLoad: Boolean,
showError: {
type: Boolean,
value: true
},
showLoading: {
type: Boolean,
value: true
},
showMenuByLongpress: Boolean,
// 受小程序slot限制所需要的属性
useLoadingSlot: Boolean,
useErrorSlot: Boolean,
},
data: {
fitWeapp: 'aspectFit',
FIT_MODE_MAP: {
contain: 'aspectFit',
cover: 'aspectFill',
fill: 'scaleToFill',
none: 'center',
// TODO: 这个没有原生的属性需要后面实现暂时先用contain;
'scale-down': 'aspectFit'
},
loading: true,
error: false
},
watch: {
src() {
this.setData({
loading: true,
error: false
});
}
},
mounted() {
this.init();
},
methods: {
init() {
const { FIT_MODE_MAP, fit } = this.data;
this.setData({
mode: FIT_MODE_MAP[fit],
style: this.getStyle(),
});
},
getStyle() {
const { width, height } = this.data;
let style = '';
if (isDef(width)) {
style += `width: ${addUnit(width)};`;
}
if (isDef(height)) {
style += `height: ${addUnit(height)};`;
}
return style;
},
onLoad(event) {
this.setData({
loading: false
});
this.$emit('load', event.detail);
},
onError(event) {
this.setData({
loading: false,
error: true,
});
this.$emit('error', event.detail);
},
onClick(event) {
this.$emit('click', event.detail);
},
}
});

7
dist/image/index.json vendored Normal file
View File

@ -0,0 +1,7 @@
{
"component": true,
"usingComponents": {
"van-icon": "../icon/index",
"van-loading": "../loading/index"
}
}

47
dist/image/index.wxml vendored Normal file
View File

@ -0,0 +1,47 @@
<wxs src="../wxs/utils.wxs" module="utils" />
<view
class="custom-class {{ utils.bem('image', { round })}}"
style="{{ style }}"
bind:tap="onClick"
>
<image
wx:if="{{ !error }}"
class="image-class van-image__img"
mode="{{ mode }}"
src="{{ src }}"
lazy-load="{{ lazyLoad }}"
show-menu-by-longpress="{{ showMenuByLongpress }}"
bind:load="onLoad"
bind:error="onError"
/>
<div
wx:if="{{ loading && showLoading }}"
class="loading-class van-image__loading"
>
<slot
wx:if="{{ useLoadingSlot }}"
name="loading"
/>
<van-icon
wx:else
name="photo-o"
size="22"
/>
</div>
<div
wx:if="{{ error && showError }}"
class="error-class van-image__error"
>
<slot
wx:if="{{ useErrorSlot }}"
name="error"
/>
<van-icon
wx:else
name="warning-o"
size="22"
/>
</div>
</view>

1
dist/image/index.wxss vendored Normal file
View File

@ -0,0 +1 @@
@import '../common/index.wxss';.van-image{position:relative;display:inline-block}.van-image--round{overflow:hidden;border-radius:50%}.van-image--round .van-image__img{border-radius:inherit}.van-image__error,.van-image__img,.van-image__loading{display:block;width:100%;height:100%}.van-image__error,.van-image__loading{position:absolute;top:0;left:0;display:-webkit-flex;display:flex;-webkit-flex-direction:column;flex-direction:column;-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center;color:#999;font-size:14px;background-color:#f8f8f8}

View File

@ -7,6 +7,7 @@ VantComponent({
percentage: Number, percentage: Number,
pivotText: String, pivotText: String,
pivotColor: String, pivotColor: String,
trackColor: String,
showPivot: { showPivot: {
type: Boolean, type: Boolean,
value: true value: true
@ -15,10 +16,6 @@ VantComponent({
type: String, type: String,
value: BLUE value: BLUE
}, },
trackColor: {
type: String,
value: "#e5e5e5",
},
textColor: { textColor: {
type: String, type: String,
value: '#fff' value: '#fff'

View File

@ -1,6 +1,9 @@
<wxs src="./index.wxs" module="getters" /> <wxs src="./index.wxs" module="getters" />
<view class="van-progress custom-class" style="height: {{ strokeWidthUnit }}; background: {{trackColor}};"> <view
class="van-progress custom-class"
style="height: {{ strokeWidthUnit }}; {{ trackColor ? 'background: ' + trackColor : '' }}"
>
<view <view
class="van-progress__portion" class="van-progress__portion"
style="width: {{ percentage }}%; background: {{ inactive ? '#cacaca' : color }}" style="width: {{ percentage }}%; background: {{ inactive ? '#cacaca' : color }}"

View File

@ -1,37 +1,38 @@
<wxs src="../wxs/utils.wxs" module="utils" /> <wxs src="../wxs/utils.wxs" module="utils" />
<view class="van-stepper custom-class"> <view class="van-stepper custom-class">
<view <view
wx:if="{{ showMinus }}" wx:if="{{ showMinus }}"
data-type="minus" data-type="minus"
style="{{ buttonStyle }}" style="{{ buttonStyle }}"
class="minus-class {{ utils.bem('stepper__minus', { disabled: disabled || value <= min }) }}" class="minus-class {{ utils.bem('stepper__minus', { disabled: disabled || value <= min }) }}"
hover-class="van-stepper__minus--hover" hover-class="van-stepper__minus--hover"
hover-stay-time="70" hover-stay-time="70"
bind:tap="onTap" bind:tap="onTap"
bind:touchstart="onTouchStart" bind:touchstart="onTouchStart"
bind:touchend="onTouchEnd" bind:touchend="onTouchEnd"
/> />
<input <input
type="{{ integer ? 'number' : 'digit' }}" type="{{ integer ? 'number' : 'digit' }}"
class="input-class {{ utils.bem('stepper__input', { disabled: disabled || disableInput }) }}" class="input-class {{ utils.bem('stepper__input', { disabled: disabled || disableInput }) }}"
style="{{ inputStyle }}" style="{{ inputStyle }}"
value="{{ value }}" value="{{ value }}"
focus="{{ focus }}" focus="{{ focus }}"
disabled="{{ disabled || disableInput }}" disabled="{{ disabled || disableInput }}"
bindinput="onInput" bindinput="onInput"
bind:focus="onFocus" bind:focus="onFocus"
bind:blur="onBlur" bind:blur="onBlur"
/> />
<view <view
wx:if="{{ showPlus }}" wx:if="{{ showPlus }}"
data-type="plus" data-type="plus"
style="{{ buttonStyle }}" style="{{ buttonStyle }}"
class="plus-class {{ utils.bem('stepper__plus', { disabled: disabled || value >= max }) }}" class="plus-class {{ utils.bem('stepper__plus', { disabled: disabled || value >= max }) }}"
hover-class="van-stepper__plus--hover" hover-class="van-stepper__plus--hover"
hover-stay-time="70" hover-stay-time="70"
bind:tap="onTap" bind:tap="onTap"
bind:touchstart="onTouchStart" bind:touchstart="onTouchStart"
bind:touchend="onTouchEnd" bind:touchend="onTouchEnd"
/> />
</view> </view>

20
dist/steps/index.wxml vendored
View File

@ -13,13 +13,25 @@
</view> </view>
<view class="van-step__circle-container"> <view class="van-step__circle-container">
<block wx:if="{{ index !== active }}"> <block wx:if="{{ index !== active }}">
<van-icon wx:if="{{ inactiveIcon }}" name="{{ inactiveIcon }}" color="#969799" size="12px" /> <van-icon
<view wx:else class="van-step__circle" style="{{ index < active ? 'background-color: ' + activeColor : '' }}" /> wx:if="{{ inactiveIcon }}"
color="#969799"
name="{{ inactiveIcon }}"
custom-class="van-step__icon"
/>
<view
wx:else
class="van-step__circle"
style="{{ index < active ? 'background-color: ' + activeColor : '' }}"
/>
</block> </block>
<van-icon wx:else name="{{ activeIcon }}" color="{{ activeColor }}" custom-class="van-step__active" /> <van-icon wx:else name="{{ activeIcon }}" color="{{ activeColor }}" custom-class="van-step__icon" />
</view> </view>
<view wx:if="{{ index !== steps.length - 1 }}" class="van-step__line" style="{{ index < active ? 'background-color: ' + activeColor : '' }}" /> <view
wx:if="{{ index !== steps.length - 1 }}"
class="van-step__line" style="{{ index < active ? 'background-color: ' + activeColor : '' }}"
/>
</view> </view>
</view> </view>
</view> </view>

View File

@ -1 +1 @@
@import '../common/index.wxss';.van-steps{overflow:hidden;background-color:#fff;background-color:var(--white,#fff)}.van-steps--horizontal{padding:10px}.van-steps--horizontal .van-step__wrapper{position:relative;display:-webkit-flex;display:flex;overflow:hidden}.van-steps--vertical{padding-left:10px}.van-steps--vertical .van-step__wrapper{padding:0 0 0 20px}.van-step{position:relative;-webkit-flex:1;flex:1;font-size:14px;color:#999;color:var(--gray-dark,#999)}.van-step--finish{color:#333;color:var(--text-color,#333)}.van-step__circle{width:5px;height:5px;border-radius:50%;background-color:#999;background-color:var(--gray-dark,#999)}.van-step--horizontal{padding-bottom:14px}.van-step--horizontal:first-child .van-step__title{-webkit-transform:none;transform:none}.van-step--horizontal:first-child .van-step__circle-container{padding:0 8px 0 0;-webkit-transform:translate3d(0,50%,0);transform:translate3d(0,50%,0)}.van-step--horizontal:last-child{position:absolute;right:0;width:auto}.van-step--horizontal:last-child .van-step__title{text-align:right;-webkit-transform:none;transform:none}.van-step--horizontal:last-child .van-step__circle-container{right:0;padding:0 0 0 8px;-webkit-transform:translate3d(0,50%,0);transform:translate3d(0,50%,0)}.van-step--horizontal .van-step__circle-container{position:absolute;bottom:6px;z-index:1;padding:0 8px;-webkit-transform:translate3d(-50%,50%,0);transform:translate3d(-50%,50%,0);background-color:#fff;background-color:var(--white,#fff)}.van-step--horizontal .van-step__title{display:inline-block;font-size:12px;-webkit-transform:translate3d(-50%,0,0);transform:translate3d(-50%,0,0)}.van-step--horizontal .van-step__line{position:absolute;right:0;bottom:6px;left:0;height:1px;-webkit-transform:translate3d(0,50%,0);transform:translate3d(0,50%,0);background-color:#eee;background-color:var(--border-color,#eee)}.van-step--horizontal.van-step--process{color:#333;color:var(--text-color,#333)}.van-step--horizontal.van-step--process .van-step__active{display:block;font-size:12px;line-height:1}.van-step--vertical{padding:10px 10px 10px 0;font-size:14px;line-height:18px}.van-step--vertical:after{border-bottom-width:1px}.van-step--vertical:last-child:after{border-bottom-width:none}.van-step--vertical:first-child:before{position:absolute;top:0;left:-15px;z-index:1;width:1px;height:20px;content:"";background-color:#fff;background-color:var(--white,#fff)}.van-step--vertical .van-step__active,.van-step--vertical .van-step__circle,.van-step--vertical .van-step__line{position:absolute;top:19px;left:-14px;z-index:2;-webkit-transform:translate3d(-50%,-50%,0);transform:translate3d(-50%,-50%,0)}.van-step--vertical .van-step__active{font-size:12px;line-height:1}.van-step--vertical .van-step__line{z-index:1;width:1px;height:100%;-webkit-transform:translate3d(-50%,0,0);transform:translate3d(-50%,0,0);background-color:#eee;background-color:var(--border-color,#eee)} @import '../common/index.wxss';.van-steps{overflow:hidden;background-color:#fff;background-color:var(--white,#fff)}.van-steps--horizontal{padding:10px}.van-steps--horizontal .van-step__wrapper{position:relative;display:-webkit-flex;display:flex;overflow:hidden}.van-steps--vertical{padding-left:10px}.van-steps--vertical .van-step__wrapper{padding:0 0 0 20px}.van-step{position:relative;-webkit-flex:1;flex:1;font-size:14px;color:#999;color:var(--gray-dark,#999)}.van-step--finish{color:#333;color:var(--text-color,#333)}.van-step__circle{width:5px;height:5px;border-radius:50%;background-color:#999;background-color:var(--gray-dark,#999)}.van-step--horizontal{padding-bottom:14px}.van-step--horizontal:first-child .van-step__title{-webkit-transform:none;transform:none}.van-step--horizontal:first-child .van-step__circle-container{padding:0 8px 0 0;-webkit-transform:translate3d(0,50%,0);transform:translate3d(0,50%,0)}.van-step--horizontal:last-child{position:absolute;right:0;width:auto}.van-step--horizontal:last-child .van-step__title{text-align:right;-webkit-transform:none;transform:none}.van-step--horizontal:last-child .van-step__circle-container{right:0;padding:0 0 0 8px;-webkit-transform:translate3d(0,50%,0);transform:translate3d(0,50%,0)}.van-step--horizontal .van-step__circle-container{position:absolute;bottom:6px;z-index:1;padding:0 8px;-webkit-transform:translate3d(-50%,50%,0);transform:translate3d(-50%,50%,0);background-color:#fff;background-color:var(--white,#fff)}.van-step--horizontal .van-step__title{display:inline-block;font-size:12px;-webkit-transform:translate3d(-50%,0,0);transform:translate3d(-50%,0,0)}.van-step--horizontal .van-step__line{position:absolute;right:0;bottom:6px;left:0;height:1px;-webkit-transform:translate3d(0,50%,0);transform:translate3d(0,50%,0);background-color:#eee;background-color:var(--border-color,#eee)}.van-step--horizontal.van-step--process{color:#333;color:var(--text-color,#333)}.van-step--horizontal.van-step--process .van-step__icon{display:block;font-size:12px;line-height:1}.van-step--vertical{padding:10px 10px 10px 0;font-size:14px;line-height:18px}.van-step--vertical:after{border-bottom-width:1px}.van-step--vertical:last-child:after{border-bottom-width:none}.van-step--vertical:first-child:before{position:absolute;top:0;left:-15px;z-index:1;width:1px;height:20px;content:"";background-color:#fff;background-color:var(--white,#fff)}.van-step--vertical .van-step__circle,.van-step--vertical .van-step__icon,.van-step--vertical .van-step__line{position:absolute;top:19px;left:-14px;z-index:2;-webkit-transform:translate3d(-50%,-50%,0);transform:translate3d(-50%,-50%,0)}.van-step--vertical .van-step__icon{font-size:12px;line-height:1}.van-step--vertical .van-step__line{z-index:1;width:1px;height:100%;-webkit-transform:translate3d(-50%,0,0);transform:translate3d(-50%,0,0);background-color:#eee;background-color:var(--border-color,#eee)}

View File

@ -1 +1 @@
@import '../common/index.wxss';.van-switch{position:relative;display:inline-block;box-sizing:initial;width:2em;width:var(--switch-width,2em);height:1em;height:var(--switch-height,1em);background-color:#fff;background-color:var(--switch-background-color,#fff);border:1px solid rgba(0,0,0,.1);border:var(--switch-border,1px solid rgba(0,0,0,.1));border-radius:1em;border-radius:var(--switch-node-size,1em);transition:background-color .3s;transition:background-color var(--switch-transition-duration,.3s)}.van-switch__node{position:absolute;top:0;left:0;border-radius:100%;z-index:1;z-index:var(--switch-node-z-index,1);width:1em;width:var(--switch-node-size,1em);height:1em;height:var(--switch-node-size,1em);background-color:#fff;background-color:var(--switch-node-background-color,#fff);box-shadow:0 3px 1px 0 rgba(0,0,0,.05),0 2px 2px 0 rgba(0,0,0,.1),0 3px 3px 0 rgba(0,0,0,.05);box-shadow:var(--switch-node-box-shadow,0 3px 1px 0 rgba(0,0,0,.05),0 2px 2px 0 rgba(0,0,0,.1),0 3px 3px 0 rgba(0,0,0,.05));transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;transition:-webkit-transform var(--switch-transition-duration,.3s);transition:transform var(--switch-transition-duration,.3s);transition:transform var(--switch-transition-duration,.3s),-webkit-transform var(--switch-transition-duration,.3s)}.van-switch__loading{position:absolute!important;top:25%;left:25%}.van-switch--on{background-color:#1989fa;background-color:var(--switch-on-background-color,#1989fa)}.van-switch--on .van-switch__node{-webkit-transform:translateX(1em);transform:translateX(1em);-webkit-transform:translateX(calc(var(--switch-width, 2em) - var(--switch-node-size, 1em)));transform:translateX(calc(var(--switch-width, 2em) - var(--switch-node-size, 1em)))}.van-switch--disabled{opacity:.4;opacity:var(--switch-disabled-opacity,.4)} @import '../common/index.wxss';.van-switch{position:relative;display:inline-block;box-sizing:initial;width:2em;width:var(--switch-width,2em);height:1em;height:var(--switch-height,1em);background-color:#fff;background-color:var(--switch-background-color,#fff);border:1px solid rgba(0,0,0,.1);border:var(--switch-border,1px solid rgba(0,0,0,.1));border-radius:1em;border-radius:var(--switch-node-size,1em);transition:background-color .3s;transition:background-color var(--switch-transition-duration,.3s)}.van-switch__node{position:absolute;top:0;left:0;border-radius:100%;z-index:1;z-index:var(--switch-node-z-index,1);width:1em;width:var(--switch-node-size,1em);height:1em;height:var(--switch-node-size,1em);background-color:#fff;background-color:var(--switch-node-background-color,#fff);box-shadow:0 3px 1px 0 rgba(0,0,0,.05),0 2px 2px 0 rgba(0,0,0,.1),0 3px 3px 0 rgba(0,0,0,.05);box-shadow:var(--switch-node-box-shadow,0 3px 1px 0 rgba(0,0,0,.05),0 2px 2px 0 rgba(0,0,0,.1),0 3px 3px 0 rgba(0,0,0,.05));transition:-webkit-transform .3s cubic-bezier(.3,1.05,.4,1.05);transition:transform .3s cubic-bezier(.3,1.05,.4,1.05);transition:transform .3s cubic-bezier(.3,1.05,.4,1.05),-webkit-transform .3s cubic-bezier(.3,1.05,.4,1.05);transition:-webkit-transform var(--switch-transition-duration,.3s) cubic-bezier(.3,1.05,.4,1.05);transition:transform var(--switch-transition-duration,.3s) cubic-bezier(.3,1.05,.4,1.05);transition:transform var(--switch-transition-duration,.3s) cubic-bezier(.3,1.05,.4,1.05),-webkit-transform var(--switch-transition-duration,.3s) cubic-bezier(.3,1.05,.4,1.05)}.van-switch__loading{position:absolute!important;top:25%;left:25%}.van-switch--on{background-color:#1989fa;background-color:var(--switch-on-background-color,#1989fa)}.van-switch--on .van-switch__node{-webkit-transform:translateX(1em);transform:translateX(1em);-webkit-transform:translateX(calc(var(--switch-width, 2em) - var(--switch-node-size, 1em)));transform:translateX(calc(var(--switch-width, 2em) - var(--switch-node-size, 1em)))}.van-switch--disabled{opacity:.4;opacity:var(--switch-disabled-opacity,.4)}

View File

@ -43,7 +43,8 @@
"pages/picker/index", "pages/picker/index",
"pages/overlay/index", "pages/overlay/index",
"pages/circle/index", "pages/circle/index",
"pages/grid/index" "pages/grid/index",
"pages/dropdown-menu/index"
], ],
"window": { "window": {
"navigationBarBackgroundColor": "#f8f8f8", "navigationBarBackgroundColor": "#f8f8f8",
@ -108,7 +109,9 @@
"van-overlay": "./dist/overlay/index", "van-overlay": "./dist/overlay/index",
"van-circle": "./dist/circle/index", "van-circle": "./dist/circle/index",
"van-grid": "./dist/grid/index", "van-grid": "./dist/grid/index",
"van-grid-item": "./dist/grid-item/index" "van-grid-item": "./dist/grid-item/index",
"van-dropdown-menu": "./dist/dropdown-menu/index",
"van-dropdown-item": "./dist/dropdown-item/index"
}, },
"sitemapLocation": "sitemap.json" "sitemapLocation": "sitemap.json"
} }

View File

@ -91,6 +91,10 @@ export default [
path: '/dialog', path: '/dialog',
title: 'Dialog 弹出框' title: 'Dialog 弹出框'
}, },
{
path: '/dropdown-menu',
title: 'DropdownMenu 下拉菜单'
},
{ {
path: '/loading', path: '/loading',
title: 'Loading 加载' title: 'Loading 加载'

View File

@ -0,0 +1,35 @@
import Page from '../../common/page';
Page({
data: {
switchTitle1: '包邮',
switchTitle2: '团购',
itemTitle: '筛选',
option1: [
{ text: '全部商品', value: 0 },
{ text: '新款商品', value: 1 },
{ text: '活动商品', value: 2 }
],
option2: [
{ text: '默认排序', value: 'a' },
{ text: '好评排序', value: 'b' },
{ text: '销量排序', value: 'c' }
],
switch1: true,
switch2: false,
value1: 0,
value2: 'a'
},
onConfirm () {
this.selectComponent('#item').toggle();
},
onSwitch1Change ({ detail }) {
this.setData({ switch1: detail });
},
onSwitch2Change ({ detail }) {
this.setData({ switch2: detail });
}
});

View File

@ -0,0 +1,3 @@
{
"navigationBarTitleText": "Dropdown Menu"
}

View File

@ -0,0 +1,57 @@
<demo-block custom-class="white" title="基础用法" padding>
<van-dropdown-menu>
<van-dropdown-item value="{{ value1 }}" options="{{ option1 }}" />
<van-dropdown-item value="{{ value2 }}" options="{{ option2 }}" />
</van-dropdown-menu>
</demo-block>
<demo-block custom-class="white" title="自定义菜单内容" padding>
<van-dropdown-menu>
<van-dropdown-item value="{{ value1 }}" options="{{ option1 }}" />
<van-dropdown-item id="item" title="{{ itemTitle }}">
<van-cell title="{{ switchTitle1 }}">
<van-switch
slot="right-icon"
size="24px"
style="height: 26px"
checked="{{ switch1 }}"
bind:change="onSwitch1Change"
/>
</van-cell>
<van-cell title="{{ switchTitle2 }}">
<van-switch
slot="right-icon"
size="24px"
style="height: 26px"
checked="{{ switch2 }}"
bind:change="onSwitch2Change"
/>
</van-cell>
<van-button type="info" block bind:click="onConfirm">
确定
</van-button>
</van-dropdown-item>
</van-dropdown-menu>
</demo-block>
<demo-block custom-class="white" title="自定义选中状态颜色" padding>
<van-dropdown-menu active-color="#ee0a24">
<van-dropdown-item value="{{ value1 }}" options="{{ option1 }}" />
<van-dropdown-item value="{{ value2 }}" options="{{ option2 }}" />
</van-dropdown-menu>
</demo-block>
<demo-block custom-class="white" title="向上展开" padding>
<van-dropdown-menu direction="up">
<van-dropdown-item value="{{ value1 }}" options="{{ option1 }}" />
<van-dropdown-item value="{{ value2 }}" options="{{ option2 }}" />
</van-dropdown-menu>
</demo-block>
<demo-block custom-class="white" title="禁用菜单" padding>
<van-dropdown-menu>
<van-dropdown-item value="{{ value1 }}" disabled options="{{ option1 }}" />
<van-dropdown-item value="{{ value2 }}" disabled options="{{ option2 }}" />
</van-dropdown-menu>
</demo-block>

View File

@ -0,0 +1,3 @@
page {
background-color: white;
}

View File

@ -1 +1 @@
@import '../common/index.wxss';.van-action-sheet{max-height:90%!important;color:#333;color:var(--text-color,#333)}.van-action-sheet__cancel,.van-action-sheet__item{height:50px;font-size:16px;line-height:50px;text-align:center;background-color:#fff;background-color:var(--white,#fff)}.van-action-sheet__cancel--hover,.van-action-sheet__item--hover{background-color:#f2f3f5;background-color:var(--active-color,#f2f3f5)}.van-action-sheet__cancel{height:60px}.van-action-sheet__cancel:before{display:block;height:10px;content:" ";background-color:#f8f8f8;background-color:var(--background-color,#f8f8f8)}.van-action-sheet__item--disabled{color:#c9c9c9;color:var(--gray,#c9c9c9)}.van-action-sheet__item--disabled.van-action-sheet__item--hover{background-color:#fff;background-color:var(--white,#fff)}.van-action-sheet__subname{margin-left:5px;font-size:12px;color:#7d7e80;color:var(--gray-darker,#7d7e80)}.van-action-sheet__header{font-weight:500;font-size:16px;line-height:44px;text-align:center}.van-action-sheet__description{padding:16px;color:#7d7e80;font-size:14px;line-height:20px;text-align:center}.van-action-sheet__close{position:absolute!important;top:0;right:0;padding:0 15px;font-size:18px!important;line-height:inherit!important;color:#999;color:var(--gray-dark,#999)} @import '../common/index.wxss';.van-action-sheet{max-height:90%!important;color:#333;color:var(--action-sheet-item-text-color,#333)}.van-action-sheet__cancel,.van-action-sheet__item{font-size:16px;line-height:50px;text-align:center;background-color:#fff;background-color:var(--action-sheet-item-background,#fff)}.van-action-sheet__cancel--hover,.van-action-sheet__item--hover{background-color:#f2f3f5;background-color:var(--active-color,#f2f3f5)}.van-action-sheet__cancel{height:50px}.van-action-sheet__cancel:before{display:block;height:8px;content:" ";background-color:#f8f8f8;background-color:var(--action-sheet-cancel-padding-color,#f8f8f8)}.van-action-sheet__item--disabled{color:#c9c9c9;color:var(--action-sheet-item-disabled-text-color,#c9c9c9)}.van-action-sheet__item--disabled.van-action-sheet__item--hover{background-color:#fff;background-color:var(--action-sheet-item-background,#fff)}.van-action-sheet__subname{margin-left:4px;font-size:12px;color:#7d7e80;color:var(--action-sheet-subname-color,#7d7e80)}.van-action-sheet__header{font-weight:500;font-size:16px;line-height:44px;text-align:center}.van-action-sheet__description{padding:16px;color:#7d7e80;font-size:14px;line-height:20px;text-align:center}.van-action-sheet__close{position:absolute!important;top:0;right:0;padding:0 12px;font-size:18px!important;line-height:inherit!important;color:#999;color:var(--action-sheet-close-icon-color,#999)}

View File

@ -1 +1 @@
@import '../common/index.wxss';.van-button{position:relative;display:inline-block;box-sizing:border-box;height:44px;padding:0;font-size:16px;line-height:42px;text-align:center;vertical-align:middle;transition:opacity .2s;border-radius:2px;border-radius:var(--button-border-radius,2px);-webkit-appearance:none;-webkit-text-size-adjust:100%}.van-button:before{position:absolute;top:50%;left:50%;width:100%;height:100%;border:inherit;border-radius:inherit;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);opacity:0;content:" ";background-color:#000;background-color:var(--black,#000);border-color:#000;border-color:var(--black,#000)}.van-button:after{border-width:0}.van-button--active:before{opacity:.15}.van-button--unclickable:after{display:none}.van-button--default{color:#333;color:var(--button-default-color,#333);background-color:#fff;background-color:var(--button-default-background-color,#fff);border:1px solid #eee;border:1px solid var(--button-default-border-color,#eee)}.van-button--primary{color:#fff;color:var(--button-primary-color,#fff);background-color:#07c160;background-color:var(--button-primary-background-color,#07c160);border:1px solid #07c160;border:1px solid var(--button-primary-border-color,#07c160)}.van-button--info{color:#fff;color:var(--button-info-color,#fff);background-color:#1989fa;background-color:var(--button-info-background-color,#1989fa);border:1px solid #1989fa;border:1px solid var(--button-info-border-color,#1989fa)}.van-button--danger{color:#fff;color:var(--button-danger-color,#fff);background-color:#ee0a24;background-color:var(--button-danger-background-color,#ee0a24);border:1px solid #ee0a24;border:1px solid var(--button-danger-border-color,#ee0a24)}.van-button--warning{color:#fff;color:var(--button-warning-color,#fff);background-color:#ff976a;background-color:var(--button-warning-background-color,#ff976a);border:1px solid #ff976a;border:1px solid var(--button-warning-border-color,#ff976a)}.van-button--plain{background-color:#fff;background-color:var(--white,#fff)}.van-button--plain.van-button--primary{color:#07c160;color:var(--button-primary-background-color,#07c160)}.van-button--plain.van-button--info{color:#1989fa;color:var(--button-info-background-color,#1989fa)}.van-button--plain.van-button--danger{color:#ee0a24;color:var(--button-danger-background-color,#ee0a24)}.van-button--plain.van-button--warning{color:#ff976a;color:var(--button-warning-background-color,#ff976a)}.van-button--large{width:100%;height:50px;line-height:48px}.van-button--normal{padding:0 15px;font-size:14px}.van-button--small{min-width:60px;height:30px;padding:0 8px;font-size:12px;line-height:28px}.van-button--mini{display:inline-block;width:50px;height:22px;font-size:10px;line-height:20px}.van-button--mini+.van-button--mini{margin-left:5px}.van-button--block{display:block;width:100%}.van-button--round{border-radius:10em;border-radius:var(--button-round-border-radius,10em)}.van-button--square{border-radius:0}.van-button--disabled{opacity:.5}.van-button__text{display:inline}.van-button__loading-text{display:inline-block;margin-left:5px;vertical-align:middle}.van-button__icon{min-width:1em;line-height:inherit!important;vertical-align:top}.van-button__icon+.van-button__text:not(:empty){display:inline-block;margin-left:5px;vertical-align:top}.van-button--hairline{padding-top:1px;border-width:0}.van-button--hairline:after{border-color:inherit;border-width:1px;border-radius:4px;border-radius:calc(var(--button-border-radius, 2px)*2)}.van-button--hairline.van-button--round:after{border-radius:10em;border-radius:var(--button-round-border-radius,10em)}.van-button--hairline.van-button--square:after{border-radius:0} @import '../common/index.wxss';.van-button{position:relative;display:inline-block;box-sizing:border-box;height:44px;padding:0;font-size:16px;line-height:42px;text-align:center;vertical-align:middle;transition:opacity .2s;border-radius:2px;border-radius:var(--button-border-radius,2px);-webkit-appearance:none;-webkit-text-size-adjust:100%}.van-button:before{position:absolute;top:50%;left:50%;width:100%;height:100%;border:inherit;border-radius:inherit;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);opacity:0;content:" ";background-color:#000;background-color:var(--black,#000);border-color:#000;border-color:var(--black,#000)}.van-button:after{border-width:0}.van-button--active:before{opacity:.15}.van-button--unclickable:after{display:none}.van-button--default{color:#333;color:var(--button-default-color,#333);background-color:#fff;background-color:var(--button-default-background-color,#fff);border:1px solid #eee;border:1px solid var(--button-default-border-color,#eee)}.van-button--primary{color:#fff;color:var(--button-primary-color,#fff);background-color:#07c160;background-color:var(--button-primary-background-color,#07c160);border:1px solid #07c160;border:1px solid var(--button-primary-border-color,#07c160)}.van-button--info{color:#fff;color:var(--button-info-color,#fff);background-color:#1989fa;background-color:var(--button-info-background-color,#1989fa);border:1px solid #1989fa;border:1px solid var(--button-info-border-color,#1989fa)}.van-button--danger{color:#fff;color:var(--button-danger-color,#fff);background-color:#ee0a24;background-color:var(--button-danger-background-color,#ee0a24);border:1px solid #ee0a24;border:1px solid var(--button-danger-border-color,#ee0a24)}.van-button--warning{color:#fff;color:var(--button-warning-color,#fff);background-color:#ff976a;background-color:var(--button-warning-background-color,#ff976a);border:1px solid #ff976a;border:1px solid var(--button-warning-border-color,#ff976a)}.van-button--plain{background-color:#fff;background-color:var(--button-plain-background-color,#fff)}.van-button--plain.van-button--primary{color:#07c160;color:var(--button-primary-background-color,#07c160)}.van-button--plain.van-button--info{color:#1989fa;color:var(--button-info-background-color,#1989fa)}.van-button--plain.van-button--danger{color:#ee0a24;color:var(--button-danger-background-color,#ee0a24)}.van-button--plain.van-button--warning{color:#ff976a;color:var(--button-warning-background-color,#ff976a)}.van-button--large{width:100%;height:50px;line-height:48px}.van-button--normal{padding:0 15px;font-size:14px}.van-button--small{min-width:60px;height:30px;padding:0 8px;font-size:12px;line-height:28px}.van-button--mini{display:inline-block;width:50px;height:22px;font-size:10px;line-height:20px}.van-button--mini+.van-button--mini{margin-left:5px}.van-button--block{display:block;width:100%}.van-button--round{border-radius:10em;border-radius:var(--button-round-border-radius,10em)}.van-button--square{border-radius:0}.van-button--disabled{opacity:.5}.van-button__text{display:inline}.van-button__loading-text{display:inline-block;margin-left:5px;vertical-align:middle}.van-button__icon{min-width:1em;line-height:inherit!important;vertical-align:top}.van-button__icon+.van-button__text:not(:empty){display:inline-block;margin-left:5px;vertical-align:top}.van-button--hairline{padding-top:1px;border-width:0}.van-button--hairline:after{border-color:inherit;border-width:1px;border-radius:4px;border-radius:calc(var(--button-border-radius, 2px)*2)}.van-button--hairline.van-button--round:after{border-radius:10em;border-radius:var(--button-round-border-radius,10em)}.van-button--hairline.van-button--square:after{border-radius:0}

View File

@ -1 +1 @@
@import '../common/index.wxss';.van-card{position:relative;box-sizing:border-box;padding:5px 15px;font-size:12px;color:#333;color:var(--text-color,#333);background-color:#fafafa;background-color:var(--background-color-light,#fafafa)}.van-card__header{display:-webkit-flex;display:flex}.van-card__header--center{-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center}.van-card__thumb{position:relative;-webkit-flex:none;flex:none;width:90px;height:90px;margin-right:10px}.van-card__thumb:empty{display:none}.van-card__img{width:100%;height:100%}.van-card__content{position:relative;-webkit-flex:1;flex:1;min-width:0}.van-card__desc,.van-card__title{word-wrap:break-word}.van-card__title{font-weight:700;line-height:16px}.van-card__desc{color:#7d7e80;color:var(--gray-darker,#7d7e80)}.van-card__bottom,.van-card__desc{line-height:20px}.van-card__price{display:inline-block;font-weight:700;color:#ee0a24;color:var(--red,#ee0a24)}.van-card__origin-price{display:inline-block;margin-left:5px;font-size:10px;text-decoration:line-through;color:#7d7e80;color:var(--gray-darker,#7d7e80)}.van-card__num{float:right}.van-card__tag{position:absolute;top:2px;left:0}.van-card__footer{-webkit-flex:none;flex:none;width:100%;text-align:right} @import '../common/index.wxss';.van-card{position:relative;box-sizing:border-box;padding:8px 16px;font-size:12px;color:#333;color:var(--card-text-color,#333);background-color:#fafafa;background-color:var(--card-background-color,#fafafa)}.van-card__header{display:-webkit-flex;display:flex}.van-card__header--center{-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center}.van-card__thumb{position:relative;-webkit-flex:none;flex:none;width:90px;height:90px;margin-right:8px}.van-card__thumb:empty{display:none}.van-card__img{width:100%;height:100%}.van-card__content{position:relative;-webkit-flex:1;flex:1;min-width:0}.van-card__desc,.van-card__title{word-wrap:break-word}.van-card__title{font-weight:700;line-height:16px}.van-card__desc{color:#7d7e80;color:var(--card-desc-color,#7d7e80)}.van-card__bottom,.van-card__desc{line-height:20px}.van-card__price{display:inline-block;font-weight:700;color:#ee0a24;color:var(--card-price-color,#ee0a24)}.van-card__origin-price{display:inline-block;margin-left:5px;font-size:10px;text-decoration:line-through;color:#7d7e80;color:var(--card-origin-price-color,#7d7e80)}.van-card__num{float:right}.van-card__tag{position:absolute;top:2px;left:0}.van-card__footer{-webkit-flex:none;flex:none;width:100%;text-align:right}

View File

@ -1 +1 @@
@import '../common/index.wxss';.van-dialog{top:45%!important;width:320px;overflow:hidden;font-size:16px;border-radius:4px;background-color:#fff;background-color:var(--white,#fff)}@media (max-width:321px){.van-dialog{width:90%}}.van-dialog__header{padding-top:25px;font-weight:500;line-height:24px;text-align:center}.van-dialog__header--isolated{padding:25px 0}.van-dialog__message{max-height:60vh;padding:25px;overflow-y:auto;font-size:14px;line-height:20px;text-align:center;-webkit-overflow-scrolling:touch}.van-dialog__message-text{word-wrap:break-word}.van-dialog__message--has-title{padding-top:12px;color:#7d7e80;color:var(--gray-darker,#7d7e80)}.van-dialog__message--left{text-align:left}.van-dialog__message--right{text-align:right}.van-dialog__footer{display:-webkit-flex;display:flex}.van-dialog__button{-webkit-flex:1;flex:1}.van-dialog__cancel,.van-dialog__confirm{border:0!important}.van-dialog-bounce-enter{-webkit-transform:translate3d(-50%,-50%,0) scale(.7);transform:translate3d(-50%,-50%,0) scale(.7);opacity:0}.van-dialog-bounce-leave-active{-webkit-transform:translate3d(-50%,-50%,0) scale(.9);transform:translate3d(-50%,-50%,0) scale(.9);opacity:0} @import '../common/index.wxss';.van-dialog{top:45%!important;width:320px;overflow:hidden;font-size:16px;border-radius:16px;background-color:#fff;background-color:var(--white,#fff)}@media (max-width:321px){.van-dialog{width:90%}}.van-dialog__header{padding-top:25px;font-weight:500;line-height:24px;text-align:center}.van-dialog__header--isolated{padding:25px 0}.van-dialog__message{max-height:60vh;padding:25px;overflow-y:auto;font-size:14px;line-height:20px;text-align:center;-webkit-overflow-scrolling:touch}.van-dialog__message-text{word-wrap:break-word}.van-dialog__message--has-title{padding-top:12px;color:#7d7e80;color:var(--gray-darker,#7d7e80)}.van-dialog__message--left{text-align:left}.van-dialog__message--right{text-align:right}.van-dialog__footer{display:-webkit-flex;display:flex}.van-dialog__button{-webkit-flex:1;flex:1}.van-dialog__cancel,.van-dialog__confirm{border:0!important}.van-dialog-bounce-enter{-webkit-transform:translate3d(-50%,-50%,0) scale(.7);transform:translate3d(-50%,-50%,0) scale(.7);opacity:0}.van-dialog-bounce-leave-active{-webkit-transform:translate3d(-50%,-50%,0) scale(.9);transform:translate3d(-50%,-50%,0) scale(.9);opacity:0}

View File

@ -0,0 +1,73 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var component_1 = require("../common/component");
component_1.VantComponent({
field: true,
relation: {
name: 'dropdown-menu',
type: 'ancestor',
linked: function (target) {
this.parent = target;
},
unlinked: function () {
this.parent = null;
}
},
props: {
value: null,
title: String,
disabled: Boolean,
titleClass: String,
options: {
type: Array,
value: []
}
},
data: {
transition: true,
showPopup: false,
showWrapper: false,
displayTitle: ''
},
created: function () {
this.setData({ displayTitle: this.computedDisplayTitle(this.data.value) });
},
methods: {
computedDisplayTitle: function (curValue) {
var _a = this.data, title = _a.title, options = _a.options;
if (title) {
return title;
}
var match = options.filter(function (option) { return option.value === curValue; });
var displayTitle = match.length ? match[0].text : '';
return displayTitle;
},
onClickOverlay: function () {
this.toggle();
this.$emit('close');
},
onOptionTap: function (event) {
var _this = this;
var _a = this.data, value = _a.value, displayTitle = _a.displayTitle;
var option = event.currentTarget.dataset.option;
var optionValue = option.value;
if (optionValue !== value) {
value = optionValue;
displayTitle = this.computedDisplayTitle(optionValue);
this.$emit('change', optionValue);
}
this.setData({ showPopup: false, value: value, displayTitle: displayTitle });
var time = this.data.duration || 0;
setTimeout(function () {
_this.setData({ showWrapper: false });
}, time);
// parent 中的 itemListData 是 children 上的数据的集合
// 数据的更新由 children 各自维护,但是模板的更新需要额外触发 parent 的 setData
this.parent.setData({ itemListData: this.parent.data.itemListData });
},
toggle: function () {
var childIndex = this.data.childIndex;
this.parent.toggleItem(childIndex);
}
}
});

View File

@ -0,0 +1,8 @@
{
"component": true,
"usingComponents": {
"van-popup": "../popup/index",
"van-cell": "../cell/index",
"van-icon": "../icon/index"
}
}

View File

@ -0,0 +1,44 @@
<wxs src="../wxs/utils.wxs" module="utils" />
<view
wx:if="{{ showWrapper }}"
class="{{ utils.bem('dropdown-item', direction) }}"
style="{{ wrapperStyle }}"
>
<van-popup
show="{{ showPopup }}"
custom-style="position: absolute;"
overlay-style="position: absolute;"
overlay="{{ overlay }}"
position="{{ direction === 'down' ? 'top' : 'bottom' }}"
duration="{{ transition ? duration : 0 }}"
close-on-click-overlay="{{ closeOnClickOverlay }}"
bind:close="onClickOverlay"
>
<van-cell
wx:for="{{ options }}"
wx:key="{{ item.value }}"
data-option="{{ item }}"
class="{{ utils.bem('dropdown-item__option', { active: item.value === value } ) }}"
clickable
icon="{{ item.icon }}"
bind:tap="onOptionTap"
>
<view
slot="title"
class="van-dropdown-item__title"
style="{{ item.value === value ? 'color:' + activeColor : '' }}"
>
{{ item.text }}
</view>
<van-icon
wx:if="{{ item.value === value }}"
name="success"
class="van-dropdown-item__icon"
color="{{ activeColor }}"
/>
</van-cell>
<slot />
</van-popup>
</view>

View File

@ -0,0 +1 @@
@import '../common/index.wxss';.van-dropdown-item{position:fixed;right:0;left:0;overflow:hidden}.van-dropdown-item__option{text-align:left}.van-dropdown-item__option--active .van-dropdown-item__icon,.van-dropdown-item__option--active .van-dropdown-item__title{color:#1989fa}.van-dropdown-item--up{top:0}.van-dropdown-item--down{bottom:0}.van-dropdown-item__icon{display:block;line-height:inherit}

169
lib/dropdown-menu/index.js Normal file
View File

@ -0,0 +1,169 @@
"use strict";
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
Object.defineProperty(exports, "__esModule", { value: true });
var component_1 = require("../common/component");
var utils_1 = require("../common/utils");
var ARRAY = [];
component_1.VantComponent({
field: true,
relation: {
name: 'dropdown-item',
type: 'descendant',
linked: function (target) {
this.children = this.children || [];
// 透传 props 给 dropdown-item
var _a = this.data, overlay = _a.overlay, duration = _a.duration, activeColor = _a.activeColor, closeOnClickOverlay = _a.closeOnClickOverlay, direction = _a.direction;
this.updateChildData(target, {
overlay: overlay,
duration: duration,
activeColor: activeColor,
closeOnClickOverlay: closeOnClickOverlay,
direction: direction,
childIndex: this.children.length
});
this.children.push(target);
// 收集 dorpdown-item 的 data 挂在 data 上
target &&
this.setData({
itemListData: this.data.itemListData.concat([target.data])
});
},
unlinked: function (target) {
this.children = this.children.filter(function (child) { return child !== target; });
}
},
props: {
activeColor: String,
overlay: {
type: Boolean,
value: true
},
zIndex: {
type: Number,
value: 10
},
duration: {
type: Number,
value: 200
},
direction: {
type: String,
value: 'down'
},
closeOnClickOverlay: {
type: Boolean,
value: true
},
closeOnClickOutside: {
type: Boolean,
value: true
}
},
data: {
itemListData: []
},
created: function () {
ARRAY.push(this);
},
destroyed: function () {
var _this = this;
ARRAY = ARRAY.filter(function (item) { return item !== _this; });
},
methods: {
updateChildData: function (childItem, newData, needRefreshList) {
if (needRefreshList === void 0) { needRefreshList = false; }
childItem.setData(newData);
if (needRefreshList) {
// dropdown-item data 更新,涉及到 title 的展示,触发模板更新
this.setData({ itemListData: this.data.itemListData });
}
},
toggleItem: function (active) {
var _this = this;
this.children.forEach(function (item, index) {
var showPopup = item.data.showPopup;
if (index === active) {
_this.toggleChildItem(item);
}
else if (showPopup) {
_this.toggleChildItem(item, false, { immediate: true });
}
});
},
toggleChildItem: function (childItem, show, options) {
var _this = this;
if (options === void 0) { options = {}; }
var _a = childItem.data, showPopup = _a.showPopup, duration = _a.duration;
if (show === undefined)
show = !showPopup;
if (show === showPopup) {
return;
}
var newChildData = { transition: !options.immediate, showPopup: show };
if (!show) {
var time = options.immediate ? 0 : duration;
this.updateChildData(childItem, __assign({}, newChildData), true);
setTimeout(function () {
_this.updateChildData(childItem, { showWrapper: false }, true);
}, time);
return;
}
this.getChildWrapperStyle().then(function (wrapperStyle) {
if (wrapperStyle === void 0) { wrapperStyle = ''; }
_this.updateChildData(childItem, __assign(__assign({}, newChildData), { wrapperStyle: wrapperStyle, showWrapper: true }), true);
});
},
close: function () {
var _this = this;
this.children.forEach(function (item) {
_this.toggleChildItem(item, false, { immediate: true });
});
},
getChildWrapperStyle: function () {
var windowHeight = wx.getSystemInfoSync().windowHeight;
var _a = this.data, zIndex = _a.zIndex, direction = _a.direction;
var offset = 0;
return this.getRect('.van-dropdown-menu').then(function (rect) {
var _a = rect.top, top = _a === void 0 ? 0 : _a, _b = rect.bottom, bottom = _b === void 0 ? 0 : _b;
if (direction === 'down') {
offset = bottom;
}
else {
offset = windowHeight - top;
}
var wrapperStyle = "z-index: " + zIndex + ";";
if (direction === 'down') {
wrapperStyle += "top: " + utils_1.addUnit(offset) + ";";
}
else {
wrapperStyle += "bottom: " + utils_1.addUnit(offset) + ";";
}
return Promise.resolve(wrapperStyle);
});
},
onTitleTap: function (event) {
var _this = this;
// item ---> dropdown-item
var _a = event.currentTarget.dataset, item = _a.item, index = _a.index;
if (!item.disabled) {
// menuItem ---> dropdown-menu
ARRAY.forEach(function (menuItem) {
if (menuItem && menuItem.data.closeOnClickOutside && menuItem !== _this) {
menuItem.close();
}
});
this.toggleItem(index);
}
}
}
});

View File

@ -0,0 +1,3 @@
{
"component": true
}

View File

@ -0,0 +1,23 @@
<wxs src="../wxs/utils.wxs" module="utils" />
<view class="van-dropdown-menu van-dropdown-menu--top-bottom">
<view
wx:for="{{ itemListData }}"
wx:key="index"
data-item="{{ item }}"
data-index="{{ index }}"
class="{{ utils.bem('dropdown-menu__item', { disabled: item.disabled }) }}"
bind:tap="onTitleTap"
>
<view
class="{{ item.titleClass }} {{ utils.bem('dropdown-menu__title', { active: item.showPopup, down: item.showPopup === (direction === 'down') }) }}"
style="{{ item.showPopup ? 'color:' + activeColor : '' }}"
>
<view class="van-ellipsis">
{{item.displayTitle}}
</view>
</view>
</view>
<slot />
</view>

View File

@ -0,0 +1 @@
@import '../common/index.wxss';.van-dropdown-menu{display:-webkit-flex;display:flex;height:50px;background-color:#fff;-webkit-user-select:none;user-select:none}.van-dropdown-menu__item{display:-webkit-flex;display:flex;-webkit-flex:1;flex:1;-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center;min-width:0}.van-dropdown-menu__item:active{opacity:.7}.van-dropdown-menu__item--disabled:active{opacity:1}.van-dropdown-menu__item--disabled .van-dropdown-menu__title{color:#999}.van-dropdown-menu__title{position:relative;box-sizing:border-box;max-width:100%;padding:0 8px;color:#333;font-size:15px;line-height:18px}.van-dropdown-menu__title:after{position:absolute;top:50%;right:-4px;margin-top:-5px;border-color:transparent transparent currentcolor currentcolor;border-style:solid;border-width:3px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);opacity:.8;content:""}.van-dropdown-menu__title--active{color:#1989fa}.van-dropdown-menu__title--down:after{margin-top:-1px;-webkit-transform:rotate(135deg);transform:rotate(135deg)}

93
lib/image/index.js Normal file
View File

@ -0,0 +1,93 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var utils_1 = require("../common/utils");
var component_1 = require("../common/component");
var button_1 = require("../mixins/button");
var open_type_1 = require("../mixins/open-type");
component_1.VantComponent({
mixins: [button_1.button, open_type_1.openType],
classes: ['custom-class', 'loading-class', 'error-class', 'image-class'],
props: {
src: String,
width: String,
height: String,
fit: {
type: String,
value: 'fill'
},
round: Boolean,
lazyLoad: Boolean,
showError: {
type: Boolean,
value: true
},
showLoading: {
type: Boolean,
value: true
},
showMenuByLongpress: Boolean,
// 受小程序slot限制所需要的属性
useLoadingSlot: Boolean,
useErrorSlot: Boolean,
},
data: {
fitWeapp: 'aspectFit',
FIT_MODE_MAP: {
contain: 'aspectFit',
cover: 'aspectFill',
fill: 'scaleToFill',
none: 'center',
// TODO: 这个没有原生的属性需要后面实现暂时先用contain;
'scale-down': 'aspectFit'
},
loading: true,
error: false
},
watch: {
src: function () {
this.setData({
loading: true,
error: false
});
}
},
mounted: function () {
this.init();
},
methods: {
init: function () {
var _a = this.data, FIT_MODE_MAP = _a.FIT_MODE_MAP, fit = _a.fit;
this.setData({
mode: FIT_MODE_MAP[fit],
style: this.getStyle(),
});
},
getStyle: function () {
var _a = this.data, width = _a.width, height = _a.height;
var style = '';
if (utils_1.isDef(width)) {
style += "width: " + utils_1.addUnit(width) + ";";
}
if (utils_1.isDef(height)) {
style += "height: " + utils_1.addUnit(height) + ";";
}
return style;
},
onLoad: function (event) {
this.setData({
loading: false
});
this.$emit('load', event.detail);
},
onError: function (event) {
this.setData({
loading: false,
error: true,
});
this.$emit('error', event.detail);
},
onClick: function (event) {
this.$emit('click', event.detail);
},
}
});

7
lib/image/index.json Normal file
View File

@ -0,0 +1,7 @@
{
"component": true,
"usingComponents": {
"van-icon": "../icon/index",
"van-loading": "../loading/index"
}
}

47
lib/image/index.wxml Normal file
View File

@ -0,0 +1,47 @@
<wxs src="../wxs/utils.wxs" module="utils" />
<view
class="custom-class {{ utils.bem('image', { round })}}"
style="{{ style }}"
bind:tap="onClick"
>
<image
wx:if="{{ !error }}"
class="image-class van-image__img"
mode="{{ mode }}"
src="{{ src }}"
lazy-load="{{ lazyLoad }}"
show-menu-by-longpress="{{ showMenuByLongpress }}"
bind:load="onLoad"
bind:error="onError"
/>
<div
wx:if="{{ loading && showLoading }}"
class="loading-class van-image__loading"
>
<slot
wx:if="{{ useLoadingSlot }}"
name="loading"
/>
<van-icon
wx:else
name="photo-o"
size="22"
/>
</div>
<div
wx:if="{{ error && showError }}"
class="error-class van-image__error"
>
<slot
wx:if="{{ useErrorSlot }}"
name="error"
/>
<van-icon
wx:else
name="warning-o"
size="22"
/>
</div>
</view>

1
lib/image/index.wxss Normal file
View File

@ -0,0 +1 @@
@import '../common/index.wxss';.van-image{position:relative;display:inline-block}.van-image--round{overflow:hidden;border-radius:50%}.van-image--round .van-image__img{border-radius:inherit}.van-image__error,.van-image__img,.van-image__loading{display:block;width:100%;height:100%}.van-image__error,.van-image__loading{position:absolute;top:0;left:0;display:-webkit-flex;display:flex;-webkit-flex-direction:column;flex-direction:column;-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center;color:#999;font-size:14px;background-color:#f8f8f8}

View File

@ -9,6 +9,7 @@ component_1.VantComponent({
percentage: Number, percentage: Number,
pivotText: String, pivotText: String,
pivotColor: String, pivotColor: String,
trackColor: String,
showPivot: { showPivot: {
type: Boolean, type: Boolean,
value: true value: true

View File

@ -1,6 +1,9 @@
<wxs src="./index.wxs" module="getters" /> <wxs src="./index.wxs" module="getters" />
<view class="van-progress custom-class" style="height: {{ strokeWidthUnit }};"> <view
class="van-progress custom-class"
style="height: {{ strokeWidthUnit }}; {{ trackColor ? 'background: ' + trackColor : '' }}"
>
<view <view
class="van-progress__portion" class="van-progress__portion"
style="width: {{ percentage }}%; background: {{ inactive ? '#cacaca' : color }}" style="width: {{ percentage }}%; background: {{ inactive ? '#cacaca' : color }}"

View File

@ -1,37 +1,38 @@
<wxs src="../wxs/utils.wxs" module="utils" /> <wxs src="../wxs/utils.wxs" module="utils" />
<view class="van-stepper custom-class"> <view class="van-stepper custom-class">
<view <view
wx:if="{{ showMinus }}" wx:if="{{ showMinus }}"
data-type="minus" data-type="minus"
style="{{ buttonStyle }}" style="{{ buttonStyle }}"
class="minus-class {{ utils.bem('stepper__minus', { disabled: disabled || value <= min }) }}" class="minus-class {{ utils.bem('stepper__minus', { disabled: disabled || value <= min }) }}"
hover-class="van-stepper__minus--hover" hover-class="van-stepper__minus--hover"
hover-stay-time="70" hover-stay-time="70"
bind:tap="onTap" bind:tap="onTap"
bind:touchstart="onTouchStart" bind:touchstart="onTouchStart"
bind:touchend="onTouchEnd" bind:touchend="onTouchEnd"
/> />
<input <input
type="{{ integer ? 'number' : 'digit' }}" type="{{ integer ? 'number' : 'digit' }}"
class="input-class {{ utils.bem('stepper__input', { disabled: disabled || disableInput }) }}" class="input-class {{ utils.bem('stepper__input', { disabled: disabled || disableInput }) }}"
style="{{ inputStyle }}" style="{{ inputStyle }}"
value="{{ value }}" value="{{ value }}"
focus="{{ focus }}" focus="{{ focus }}"
disabled="{{ disabled || disableInput }}" disabled="{{ disabled || disableInput }}"
bindinput="onInput" bindinput="onInput"
bind:focus="onFocus" bind:focus="onFocus"
bind:blur="onBlur" bind:blur="onBlur"
/> />
<view <view
wx:if="{{ showPlus }}" wx:if="{{ showPlus }}"
data-type="plus" data-type="plus"
style="{{ buttonStyle }}" style="{{ buttonStyle }}"
class="plus-class {{ utils.bem('stepper__plus', { disabled: disabled || value >= max }) }}" class="plus-class {{ utils.bem('stepper__plus', { disabled: disabled || value >= max }) }}"
hover-class="van-stepper__plus--hover" hover-class="van-stepper__plus--hover"
hover-stay-time="70" hover-stay-time="70"
bind:tap="onTap" bind:tap="onTap"
bind:touchstart="onTouchStart" bind:touchstart="onTouchStart"
bind:touchend="onTouchEnd" bind:touchend="onTouchEnd"
/> />
</view> </view>

View File

@ -13,13 +13,25 @@
</view> </view>
<view class="van-step__circle-container"> <view class="van-step__circle-container">
<block wx:if="{{ index !== active }}"> <block wx:if="{{ index !== active }}">
<van-icon wx:if="{{ inactiveIcon }}" name="{{ inactiveIcon }}" color="#969799" size="12px" /> <van-icon
<view wx:else class="van-step__circle" style="{{ index < active ? 'background-color: ' + activeColor : '' }}" /> wx:if="{{ inactiveIcon }}"
color="#969799"
name="{{ inactiveIcon }}"
custom-class="van-step__icon"
/>
<view
wx:else
class="van-step__circle"
style="{{ index < active ? 'background-color: ' + activeColor : '' }}"
/>
</block> </block>
<van-icon wx:else name="{{ activeIcon }}" color="{{ activeColor }}" custom-class="van-step__active" /> <van-icon wx:else name="{{ activeIcon }}" color="{{ activeColor }}" custom-class="van-step__icon" />
</view> </view>
<view wx:if="{{ index !== steps.length - 1 }}" class="van-step__line" style="{{ index < active ? 'background-color: ' + activeColor : '' }}" /> <view
wx:if="{{ index !== steps.length - 1 }}"
class="van-step__line" style="{{ index < active ? 'background-color: ' + activeColor : '' }}"
/>
</view> </view>
</view> </view>
</view> </view>

View File

@ -1 +1 @@
@import '../common/index.wxss';.van-steps{overflow:hidden;background-color:#fff;background-color:var(--white,#fff)}.van-steps--horizontal{padding:10px}.van-steps--horizontal .van-step__wrapper{position:relative;display:-webkit-flex;display:flex;overflow:hidden}.van-steps--vertical{padding-left:10px}.van-steps--vertical .van-step__wrapper{padding:0 0 0 20px}.van-step{position:relative;-webkit-flex:1;flex:1;font-size:14px;color:#999;color:var(--gray-dark,#999)}.van-step--finish{color:#333;color:var(--text-color,#333)}.van-step__circle{width:5px;height:5px;border-radius:50%;background-color:#999;background-color:var(--gray-dark,#999)}.van-step--horizontal{padding-bottom:14px}.van-step--horizontal:first-child .van-step__title{-webkit-transform:none;transform:none}.van-step--horizontal:first-child .van-step__circle-container{padding:0 8px 0 0;-webkit-transform:translate3d(0,50%,0);transform:translate3d(0,50%,0)}.van-step--horizontal:last-child{position:absolute;right:0;width:auto}.van-step--horizontal:last-child .van-step__title{text-align:right;-webkit-transform:none;transform:none}.van-step--horizontal:last-child .van-step__circle-container{right:0;padding:0 0 0 8px;-webkit-transform:translate3d(0,50%,0);transform:translate3d(0,50%,0)}.van-step--horizontal .van-step__circle-container{position:absolute;bottom:6px;z-index:1;padding:0 8px;-webkit-transform:translate3d(-50%,50%,0);transform:translate3d(-50%,50%,0);background-color:#fff;background-color:var(--white,#fff)}.van-step--horizontal .van-step__title{display:inline-block;font-size:12px;-webkit-transform:translate3d(-50%,0,0);transform:translate3d(-50%,0,0)}.van-step--horizontal .van-step__line{position:absolute;right:0;bottom:6px;left:0;height:1px;-webkit-transform:translate3d(0,50%,0);transform:translate3d(0,50%,0);background-color:#eee;background-color:var(--border-color,#eee)}.van-step--horizontal.van-step--process{color:#333;color:var(--text-color,#333)}.van-step--horizontal.van-step--process .van-step__active{display:block;font-size:12px;line-height:1}.van-step--vertical{padding:10px 10px 10px 0;font-size:14px;line-height:18px}.van-step--vertical:after{border-bottom-width:1px}.van-step--vertical:last-child:after{border-bottom-width:none}.van-step--vertical:first-child:before{position:absolute;top:0;left:-15px;z-index:1;width:1px;height:20px;content:"";background-color:#fff;background-color:var(--white,#fff)}.van-step--vertical .van-step__active,.van-step--vertical .van-step__circle,.van-step--vertical .van-step__line{position:absolute;top:19px;left:-14px;z-index:2;-webkit-transform:translate3d(-50%,-50%,0);transform:translate3d(-50%,-50%,0)}.van-step--vertical .van-step__active{font-size:12px;line-height:1}.van-step--vertical .van-step__line{z-index:1;width:1px;height:100%;-webkit-transform:translate3d(-50%,0,0);transform:translate3d(-50%,0,0);background-color:#eee;background-color:var(--border-color,#eee)} @import '../common/index.wxss';.van-steps{overflow:hidden;background-color:#fff;background-color:var(--white,#fff)}.van-steps--horizontal{padding:10px}.van-steps--horizontal .van-step__wrapper{position:relative;display:-webkit-flex;display:flex;overflow:hidden}.van-steps--vertical{padding-left:10px}.van-steps--vertical .van-step__wrapper{padding:0 0 0 20px}.van-step{position:relative;-webkit-flex:1;flex:1;font-size:14px;color:#999;color:var(--gray-dark,#999)}.van-step--finish{color:#333;color:var(--text-color,#333)}.van-step__circle{width:5px;height:5px;border-radius:50%;background-color:#999;background-color:var(--gray-dark,#999)}.van-step--horizontal{padding-bottom:14px}.van-step--horizontal:first-child .van-step__title{-webkit-transform:none;transform:none}.van-step--horizontal:first-child .van-step__circle-container{padding:0 8px 0 0;-webkit-transform:translate3d(0,50%,0);transform:translate3d(0,50%,0)}.van-step--horizontal:last-child{position:absolute;right:0;width:auto}.van-step--horizontal:last-child .van-step__title{text-align:right;-webkit-transform:none;transform:none}.van-step--horizontal:last-child .van-step__circle-container{right:0;padding:0 0 0 8px;-webkit-transform:translate3d(0,50%,0);transform:translate3d(0,50%,0)}.van-step--horizontal .van-step__circle-container{position:absolute;bottom:6px;z-index:1;padding:0 8px;-webkit-transform:translate3d(-50%,50%,0);transform:translate3d(-50%,50%,0);background-color:#fff;background-color:var(--white,#fff)}.van-step--horizontal .van-step__title{display:inline-block;font-size:12px;-webkit-transform:translate3d(-50%,0,0);transform:translate3d(-50%,0,0)}.van-step--horizontal .van-step__line{position:absolute;right:0;bottom:6px;left:0;height:1px;-webkit-transform:translate3d(0,50%,0);transform:translate3d(0,50%,0);background-color:#eee;background-color:var(--border-color,#eee)}.van-step--horizontal.van-step--process{color:#333;color:var(--text-color,#333)}.van-step--horizontal.van-step--process .van-step__icon{display:block;font-size:12px;line-height:1}.van-step--vertical{padding:10px 10px 10px 0;font-size:14px;line-height:18px}.van-step--vertical:after{border-bottom-width:1px}.van-step--vertical:last-child:after{border-bottom-width:none}.van-step--vertical:first-child:before{position:absolute;top:0;left:-15px;z-index:1;width:1px;height:20px;content:"";background-color:#fff;background-color:var(--white,#fff)}.van-step--vertical .van-step__circle,.van-step--vertical .van-step__icon,.van-step--vertical .van-step__line{position:absolute;top:19px;left:-14px;z-index:2;-webkit-transform:translate3d(-50%,-50%,0);transform:translate3d(-50%,-50%,0)}.van-step--vertical .van-step__icon{font-size:12px;line-height:1}.van-step--vertical .van-step__line{z-index:1;width:1px;height:100%;-webkit-transform:translate3d(-50%,0,0);transform:translate3d(-50%,0,0);background-color:#eee;background-color:var(--border-color,#eee)}

View File

@ -1 +1 @@
@import '../common/index.wxss';.van-switch{position:relative;display:inline-block;box-sizing:initial;width:2em;width:var(--switch-width,2em);height:1em;height:var(--switch-height,1em);background-color:#fff;background-color:var(--switch-background-color,#fff);border:1px solid rgba(0,0,0,.1);border:var(--switch-border,1px solid rgba(0,0,0,.1));border-radius:1em;border-radius:var(--switch-node-size,1em);transition:background-color .3s;transition:background-color var(--switch-transition-duration,.3s)}.van-switch__node{position:absolute;top:0;left:0;border-radius:100%;z-index:1;z-index:var(--switch-node-z-index,1);width:1em;width:var(--switch-node-size,1em);height:1em;height:var(--switch-node-size,1em);background-color:#fff;background-color:var(--switch-node-background-color,#fff);box-shadow:0 3px 1px 0 rgba(0,0,0,.05),0 2px 2px 0 rgba(0,0,0,.1),0 3px 3px 0 rgba(0,0,0,.05);box-shadow:var(--switch-node-box-shadow,0 3px 1px 0 rgba(0,0,0,.05),0 2px 2px 0 rgba(0,0,0,.1),0 3px 3px 0 rgba(0,0,0,.05));transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;transition:-webkit-transform var(--switch-transition-duration,.3s);transition:transform var(--switch-transition-duration,.3s);transition:transform var(--switch-transition-duration,.3s),-webkit-transform var(--switch-transition-duration,.3s)}.van-switch__loading{position:absolute!important;top:25%;left:25%}.van-switch--on{background-color:#1989fa;background-color:var(--switch-on-background-color,#1989fa)}.van-switch--on .van-switch__node{-webkit-transform:translateX(1em);transform:translateX(1em);-webkit-transform:translateX(calc(var(--switch-width, 2em) - var(--switch-node-size, 1em)));transform:translateX(calc(var(--switch-width, 2em) - var(--switch-node-size, 1em)))}.van-switch--disabled{opacity:.4;opacity:var(--switch-disabled-opacity,.4)} @import '../common/index.wxss';.van-switch{position:relative;display:inline-block;box-sizing:initial;width:2em;width:var(--switch-width,2em);height:1em;height:var(--switch-height,1em);background-color:#fff;background-color:var(--switch-background-color,#fff);border:1px solid rgba(0,0,0,.1);border:var(--switch-border,1px solid rgba(0,0,0,.1));border-radius:1em;border-radius:var(--switch-node-size,1em);transition:background-color .3s;transition:background-color var(--switch-transition-duration,.3s)}.van-switch__node{position:absolute;top:0;left:0;border-radius:100%;z-index:1;z-index:var(--switch-node-z-index,1);width:1em;width:var(--switch-node-size,1em);height:1em;height:var(--switch-node-size,1em);background-color:#fff;background-color:var(--switch-node-background-color,#fff);box-shadow:0 3px 1px 0 rgba(0,0,0,.05),0 2px 2px 0 rgba(0,0,0,.1),0 3px 3px 0 rgba(0,0,0,.05);box-shadow:var(--switch-node-box-shadow,0 3px 1px 0 rgba(0,0,0,.05),0 2px 2px 0 rgba(0,0,0,.1),0 3px 3px 0 rgba(0,0,0,.05));transition:-webkit-transform .3s cubic-bezier(.3,1.05,.4,1.05);transition:transform .3s cubic-bezier(.3,1.05,.4,1.05);transition:transform .3s cubic-bezier(.3,1.05,.4,1.05),-webkit-transform .3s cubic-bezier(.3,1.05,.4,1.05);transition:-webkit-transform var(--switch-transition-duration,.3s) cubic-bezier(.3,1.05,.4,1.05);transition:transform var(--switch-transition-duration,.3s) cubic-bezier(.3,1.05,.4,1.05);transition:transform var(--switch-transition-duration,.3s) cubic-bezier(.3,1.05,.4,1.05),-webkit-transform var(--switch-transition-duration,.3s) cubic-bezier(.3,1.05,.4,1.05)}.van-switch__loading{position:absolute!important;top:25%;left:25%}.van-switch--on{background-color:#1989fa;background-color:var(--switch-on-background-color,#1989fa)}.van-switch--on .van-switch__node{-webkit-transform:translateX(1em);transform:translateX(1em);-webkit-transform:translateX(calc(var(--switch-width, 2em) - var(--switch-node-size, 1em)));transform:translateX(calc(var(--switch-width, 2em) - var(--switch-node-size, 1em)))}.van-switch--disabled{opacity:.4;opacity:var(--switch-disabled-opacity,.4)}

View File

@ -278,3 +278,14 @@
@divider-content-padding: @padding-md; @divider-content-padding: @padding-md;
@divider-content-left-width: 10%; @divider-content-left-width: 10%;
@divider-content-right-width: 10%; @divider-content-right-width: 10%;
// DropdownMenu
@dropdown-menu-height: 50px;
@dropdown-menu-background-color: @white;
@dropdown-menu-title-font-size: 15px;
@dropdown-menu-title-text-color: @text-color;
@dropdown-menu-title-active-text-color: @blue;
@dropdown-menu-title-disabled-text-color: @gray-dark;
@dropdown-menu-title-padding: 0 @padding-xs;
@dropdown-menu-title-line-height: 18px;
@dropdown-menu-option-active-color: @blue;

View File

@ -0,0 +1,8 @@
{
"component": true,
"usingComponents": {
"van-popup": "../popup/index",
"van-cell": "../cell/index",
"van-icon": "../icon/index"
}
}

View File

@ -0,0 +1,32 @@
@import '../common/style/var.less';
.van-dropdown-item {
position: fixed;
right: 0;
left: 0;
overflow: hidden;
&__option {
text-align: left;
&--active {
.van-dropdown-item__title,
.van-dropdown-item__icon {
color: @dropdown-menu-option-active-color;
}
}
}
&--up {
top: 0;
}
&--down {
bottom: 0;
}
&__icon {
display: block;
line-height: inherit;
}
}

View File

@ -0,0 +1,85 @@
import { VantComponent } from '../common/component';
import { Weapp } from 'definitions/weapp';
VantComponent({
field: true,
relation: {
name: 'dropdown-menu',
type: 'ancestor',
linked(target) {
this.parent = target;
},
unlinked() {
this.parent = null;
}
},
props: {
value: null,
title: String,
disabled: Boolean,
titleClass: String,
options: {
type: Array,
value: []
}
},
data: {
transition: true,
showPopup: false,
showWrapper: false,
displayTitle: ''
},
created() {
this.setData({ displayTitle: this.computedDisplayTitle(this.data.value) });
},
methods: {
computedDisplayTitle(curValue) {
const { title, options } = this.data;
if (title) {
return title;
}
const match = options.filter(option => option.value === curValue);
const displayTitle = match.length ? match[0].text : '';
return displayTitle;
},
onClickOverlay() {
this.toggle();
this.$emit('close');
},
onOptionTap(event: Weapp.Event) {
let { value, displayTitle } = this.data;
const { option } = event.currentTarget.dataset;
const { value: optionValue } = option;
if (optionValue !== value) {
value = optionValue;
displayTitle = this.computedDisplayTitle(optionValue);
this.$emit('change', optionValue);
}
this.setData({ showPopup: false, value, displayTitle });
const time = this.data.duration || 0;
setTimeout(() => {
this.setData({ showWrapper: false });
}, time);
// parent 中的 itemListData 是 children 上的数据的集合
// 数据的更新由 children 各自维护,但是模板的更新需要额外触发 parent 的 setData
this.parent.setData({ itemListData: this.parent.data.itemListData });
},
toggle() {
const { childIndex } = this.data;
this.parent.toggleItem(childIndex);
}
}
});

View File

@ -0,0 +1,44 @@
<wxs src="../wxs/utils.wxs" module="utils" />
<view
wx:if="{{ showWrapper }}"
class="{{ utils.bem('dropdown-item', direction) }}"
style="{{ wrapperStyle }}"
>
<van-popup
show="{{ showPopup }}"
custom-style="position: absolute;"
overlay-style="position: absolute;"
overlay="{{ overlay }}"
position="{{ direction === 'down' ? 'top' : 'bottom' }}"
duration="{{ transition ? duration : 0 }}"
close-on-click-overlay="{{ closeOnClickOverlay }}"
bind:close="onClickOverlay"
>
<van-cell
wx:for="{{ options }}"
wx:key="{{ item.value }}"
data-option="{{ item }}"
class="{{ utils.bem('dropdown-item__option', { active: item.value === value } ) }}"
clickable
icon="{{ item.icon }}"
bind:tap="onOptionTap"
>
<view
slot="title"
class="van-dropdown-item__title"
style="{{ item.value === value ? 'color:' + activeColor : '' }}"
>
{{ item.text }}
</view>
<van-icon
wx:if="{{ item.value === value }}"
name="success"
class="van-dropdown-item__icon"
color="{{ activeColor }}"
/>
</van-cell>
<slot />
</van-popup>
</view>

View File

@ -0,0 +1,179 @@
# DropdownMenu 下拉菜单
### 介绍
下拉菜单
### 引入
`app.json``index.json`中引入组件,默认为`ES6`版本,`ES5`引入方式参见[快速上手](#/quickstart)
```json
"usingComponents": {
"van-dropdown-menu": "path/to/vant-weapp/dist/dropdown-menu/index",
"van-dropdown-item": "path/to/vant-weapp/dist/dropdown-item/index"
}
```
## 代码演示
### 基础用法
```html
<van-dropdown-menu>
<van-dropdown-item value="{{ value1 }}" options="{{ option1 }}" />
<van-dropdown-item value="{{ value2 }}" options="{{ option2 }}" />
</van-dropdown-menu>
```
```js
Page({
data: {
option1: [
{ text: '全部商品', value: 0 },
{ text: '新款商品', value: 1 },
{ text: '活动商品', value: 2 }
],
option2: [
{ text: '默认排序', value: 'a' },
{ text: '好评排序', value: 'b' },
{ text: '销量排序', value: 'c' }
],
value1: 0,
value2: 'a'
}
});
```
### 自定义菜单内容
```html
<van-dropdown-menu>
<van-dropdown-item value="{{ value1 }}" options="{{ option1 }}" />
<van-dropdown-item id="item" title="{{ itemTitle }}">
<van-cell title="{{ switchTitle1 }}">
<van-switch
slot="right-icon"
size="24px"
style="height: 26px"
checked="{{ switch1 }}"
bind:change="onSwitch1Change"
/>
</van-cell>
<van-cell title="{{ switchTitle2 }}">
<van-switch
slot="right-icon"
size="24px"
style="height: 26px"
checked="{{ switch2 }}"
bind:change="onSwitch2Change"
/>
</van-cell>
<van-button type="info" block bind:click="onConfirm">
确定
</van-button>
</van-dropdown-item>
</van-dropdown-menu>
```
```js
Page({
data: {
switchTitle1: '包邮',
switchTitle2: '团购',
itemTitle: '筛选',
option1: [
{ text: '全部商品', value: 0 },
{ text: '新款商品', value: 1 },
{ text: '活动商品', value: 2 }
],
value1: 0,
},
onConfirm () {
this.selectComponent('#item').toggle();
},
onSwitch1Change ({ detail }) {
this.setData({ switch1: detail });
},
onSwitch2Change ({ detail }) {
this.setData({ switch2: detail });
}
});
```
### 自定义选中状态颜色
```html
<van-dropdown-menu active-color="#ee0a24">
<van-dropdown-item value="{{ value1 }}" options="{{ option1 }}" />
<van-dropdown-item value="{{ value2 }}" options="{{ option2 }}" />
</van-dropdown-menu>
```
### 向上展开
```html
<van-dropdown-menu direction="up">
<van-dropdown-item value="{{ value1 }}" options="{{ option1 }}" />
<van-dropdown-item value="{{ value2 }}" options="{{ option2 }}" />
</van-dropdown-menu>
```
### 禁用菜单
```html
<van-dropdown-menu>
<van-dropdown-item value="{{ value1 }}" disabled options="{{ option1 }}" />
<van-dropdown-item value="{{ value2 }}" disabled options="{{ option2 }}" />
</van-dropdown-menu>
```
## API
### DropdownMenu Props
| Attribute | Description | Type | Default | Version |
| ---------------------- | ------------------------------ | --------- | --------- | ------- |
| active-color | 菜单标题和选项的选中态颜色 | *string* | `#1989fa` | - |
| z-index | 菜单栏 z-index 层级 | *number* | `10` | - |
| duration | 动画时长,单位毫秒 | *number* | `200` | - |
| direction | 菜单展开方向可选值为up | *string* | `down` | - |
| overlay | 是否显示遮罩层 | *boolean* | `true` | - |
| close-on-click-overlay | 是否在点击遮罩层后关闭菜单 | *boolean* | `true` | - |
| close-on-click-outside | 是否在点击外部 menu 后关闭菜单 | *boolean* | `true` | - |
### DropdownItem Props
| Attribute | Description | Type | Default | Version |
| ----------- | ---------------------- | ------------------ | ----------------------- | ------- |
| value | 当前选中项对应的 value | *string \| number* | - | - |
| title | 菜单项标题 | *string* | Text of selected option | - |
| options | 选项数组 | *Option[]* | `[]` | - |
| disabled | 是否禁用菜单 | *boolean* | `false` | - |
| title-class | 标题额外类名 | *string* | - | - |
### DropdownItem Events
| Event | Description | Arguments |
| ------ | ----------------------------- | --------- |
| change | 点击选项导致 value 变化时触发 | value |
| close | 关闭菜单栏时触发 | - |
### DropdownItem Methods
通过 selectComponent(id) 可访问
| Name | Attribute | Return value | Description |
| ------ | ------------- | ------------ | ---------------- |
| toggle | show: boolean | - | 切换菜单是否展示 |
### Data Structure of Option
| Key | Description | Type |
| ----- | ------------------------------------------ | ------------------ |
| text | 文字 | *string* |
| value | 标识符 | *string \| number* |
| icon | 左侧图标名称或图片链接,可选值见 Icon 组件 | *string* |

View File

@ -0,0 +1,3 @@
{
"component": true
}

View File

@ -0,0 +1,63 @@
@import '../common/style/var.less';
.van-dropdown-menu {
display: flex;
height: @dropdown-menu-height;
background-color: @dropdown-menu-background-color;
user-select: none;
&__item {
display: flex;
flex: 1;
align-items: center;
justify-content: center;
min-width: 0; // hack for flex ellipsis
&:active {
opacity: .7;
}
&--disabled {
&:active {
opacity: 1;
}
.van-dropdown-menu__title {
color: @dropdown-menu-title-disabled-text-color;
}
}
}
&__title {
position: relative;
box-sizing: border-box;
max-width: 100%;
padding: @dropdown-menu-title-padding;
color: @dropdown-menu-title-text-color;
font-size: @dropdown-menu-title-font-size;
line-height: @dropdown-menu-title-line-height;
&::after {
position: absolute;
top: 50%;
right: -4px;
margin-top: -5px;
border: 3px solid;
border-color: transparent transparent currentColor currentColor;
transform: rotate(-45deg);
opacity: .8;
content: '';
}
&--active {
color: @dropdown-menu-title-active-text-color;
}
&--down {
&::after {
margin-top: -1px;
transform: rotate(135deg);
}
}
}
}

View File

@ -0,0 +1,184 @@
import { VantComponent } from '../common/component';
import { Weapp } from 'definitions/weapp';
import { addUnit } from '../common/utils';
interface ToggleOptions {
immediate?: Boolean;
}
let ARRAY: WechatMiniprogram.Component.TrivialInstance[] = [];
VantComponent({
field: true,
relation: {
name: 'dropdown-item',
type: 'descendant',
linked(target) {
this.children = this.children || [];
// 透传 props 给 dropdown-item
const { overlay, duration, activeColor, closeOnClickOverlay, direction } = this.data;
this.updateChildData(target, {
overlay,
duration,
activeColor,
closeOnClickOverlay,
direction,
childIndex: this.children.length
});
this.children.push(target);
// 收集 dorpdown-item 的 data 挂在 data 上
target &&
this.setData({
itemListData: this.data.itemListData.concat([target.data])
});
},
unlinked(target) {
this.children = this.children.filter((child: WechatMiniprogram.Component.TrivialInstance) => child !== target);
}
},
props: {
activeColor: String,
overlay: {
type: Boolean,
value: true
},
zIndex: {
type: Number,
value: 10
},
duration: {
type: Number,
value: 200
},
direction: {
type: String,
value: 'down'
},
closeOnClickOverlay: {
type: Boolean,
value: true
},
closeOnClickOutside: {
type: Boolean,
value: true
}
},
data: {
itemListData: []
},
created() {
ARRAY.push(this);
},
destroyed() {
ARRAY = ARRAY.filter(item => item !== this);
},
methods: {
updateChildData(childItem: WechatMiniprogram.Component.TrivialInstance, newData, needRefreshList: Boolean = false) {
childItem.setData(newData);
if (needRefreshList) {
// dropdown-item data 更新,涉及到 title 的展示,触发模板更新
this.setData({ itemListData: this.data.itemListData });
}
},
toggleItem(active: Number) {
this.children.forEach((item: WechatMiniprogram.Component.TrivialInstance, index: Number) => {
const { showPopup } = item.data;
if (index === active) {
this.toggleChildItem(item);
} else if (showPopup) {
this.toggleChildItem(item, false, { immediate: true });
}
});
},
toggleChildItem(childItem: WechatMiniprogram.Component.TrivialInstance, show: boolean, options: ToggleOptions = {}) {
const { showPopup, duration } = childItem.data;
if (show === undefined) show = !showPopup;
if (show === showPopup) {
return;
}
const newChildData = { transition: !options.immediate, showPopup: show };
if (!show) {
const time = options.immediate ? 0 : duration;
this.updateChildData(childItem, { ...newChildData }, true);
setTimeout(() => {
this.updateChildData(childItem, { showWrapper: false }, true);
}, time);
return;
}
this.getChildWrapperStyle().then((wrapperStyle: String = '') => {
this.updateChildData(
childItem,
{
...newChildData,
wrapperStyle,
showWrapper: true
},
true
);
});
},
close() {
this.children.forEach((item: WechatMiniprogram.Component.TrivialInstance) => {
this.toggleChildItem(item, false, { immediate: true });
});
},
getChildWrapperStyle() {
const { windowHeight } = wx.getSystemInfoSync();
const { zIndex, direction } = this.data;
let offset = 0;
return this.getRect('.van-dropdown-menu').then(rect => {
const { top = 0, bottom = 0 } = rect;
if (direction === 'down') {
offset = bottom;
} else {
offset = windowHeight - top;
}
let wrapperStyle = `z-index: ${zIndex};`;
if (direction === 'down') {
wrapperStyle += `top: ${addUnit(offset)};`;
} else {
wrapperStyle += `bottom: ${addUnit(offset)};`;
}
return Promise.resolve(wrapperStyle);
});
},
onTitleTap(event: Weapp.Event) {
// item ---> dropdown-item
const { item, index } = event.currentTarget.dataset;
if (!item.disabled) {
// menuItem ---> dropdown-menu
ARRAY.forEach(menuItem => {
if (menuItem && menuItem.data.closeOnClickOutside && menuItem !== this) {
menuItem.close();
}
});
this.toggleItem(index);
}
}
}
});

View File

@ -0,0 +1,23 @@
<wxs src="../wxs/utils.wxs" module="utils" />
<view class="van-dropdown-menu van-dropdown-menu--top-bottom">
<view
wx:for="{{ itemListData }}"
wx:key="index"
data-item="{{ item }}"
data-index="{{ index }}"
class="{{ utils.bem('dropdown-menu__item', { disabled: item.disabled }) }}"
bind:tap="onTitleTap"
>
<view
class="{{ item.titleClass }} {{ utils.bem('dropdown-menu__title', { active: item.showPopup, down: item.showPopup === (direction === 'down') }) }}"
style="{{ item.showPopup ? 'color:' + activeColor : '' }}"
>
<view class="van-ellipsis">
{{item.displayTitle}}
</view>
</view>
</view>
<slot />
</view>