Merge branch 'dev' of https://github.com/youzan/vant into dev

This commit is contained in:
陈嘉涵 2018-06-06 17:23:25 +08:00
commit f5c1b95af1
18 changed files with 253 additions and 80 deletions

View File

@ -1,6 +1,6 @@
<template> <template>
<transition name="van-dialog-bounce"> <transition name="van-dialog-bounce">
<div v-show="value" :class="b()"> <div v-show="value" :class="[b(), className]">
<div v-if="title" v-text="title" :class="b('header')" /> <div v-if="title" v-text="title" :class="b('header')" />
<div :class="b('content')" class="van-hairline"> <div :class="b('content')" class="van-hairline">
<slot> <slot>
@ -49,6 +49,7 @@ export default create({
title: String, title: String,
message: String, message: String,
callback: Function, callback: Function,
className: [String, Object, Array],
beforeClose: Function, beforeClose: Function,
confirmButtonText: String, confirmButtonText: String,
cancelButtonText: String, cancelButtonText: String,

View File

@ -70,6 +70,7 @@ export default {
|-----------|-----------|-----------|-------------| |-----------|-----------|-----------|-------------|
| title | Title | `String` | - | | title | Title | `String` | - |
| message | Message | `String` | - | | message | Message | `String` | - |
| className | Custom className | `String | Array | Object` | - |
| showConfirmButton | Whether to show confirm button | `Boolean` | `true` | | showConfirmButton | Whether to show confirm button | `Boolean` | `true` |
| showCancelButton | Whether to show cancel button | `Boolean` | `false` | | showCancelButton | Whether to show cancel button | `Boolean` | `false` |
| confirmButtonText | Confirm button text | `String` | `Confirm` | | confirmButtonText | Confirm button text | `String` | `Confirm` |

View File

@ -34,6 +34,7 @@ Dialog.defaultOptions = {
title: '', title: '',
message: '', message: '',
overlay: true, overlay: true,
className: '',
lockScroll: true, lockScroll: true,
beforeClose: null, beforeClose: null,
confirmButtonText: '', confirmButtonText: '',

View File

@ -71,6 +71,7 @@ export default {
|-----------|-----------|-----------|-------------| |-----------|-----------|-----------|-------------|
| title | 标题 | `String` | - | | title | 标题 | `String` | - |
| message | 内容 | `String` | - | | message | 内容 | `String` | - |
| className | 自定义类名 | `String | Array | Object` | - |
| showConfirmButton | 是否展示确认按钮 | `Boolean` | `true` | | showConfirmButton | 是否展示确认按钮 | `Boolean` | `true` |
| showCancelButton | 是否展示取消按钮 | `Boolean` | `false` | | showCancelButton | 是否展示取消按钮 | `Boolean` | `false` |
| confirmButtonText | 确认按钮的文案 | `String` | `确认` | | confirmButtonText | 确认按钮的文案 | `String` | `确认` |

View File

@ -114,7 +114,7 @@ Field support all native properties of input tagsuch as `maxlength`、`placeh
| Attribute | Description | Type | Default | | Attribute | Description | Type | Default |
|-----------|-----------|-----------|-------------| |-----------|-----------|-----------|-------------|
| value | Field value | `String` | - | | value | Field value | `String | Number` | - |
| label | Field label | `String` | - | | label | Field label | `String` | - |
| type | Input type | `String` | `text` | | type | Input type | `String` | `text` |
| disabled | Disable field | `Boolean` | `false` | | disabled | Disable field | `Boolean` | `false` |

View File

@ -8,7 +8,7 @@
:class="b({ :class="b({
error, error,
disabled: $attrs.disabled, disabled: $attrs.disabled,
'has-icon': hasIcon, 'has-icon': showIcon,
'min-height': type === 'textarea' && !autosize 'min-height': type === 'textarea' && !autosize
})" })"
> >
@ -35,8 +35,7 @@
:class="b('error-message')" :class="b('error-message')"
/> />
<div <div
v-if="hasIcon" v-if="showIcon"
v-show="$slots.icon || value"
:class="b('icon')" :class="b('icon')"
@touchstart.prevent="onClickIcon" @touchstart.prevent="onClickIcon"
> >
@ -60,7 +59,7 @@ export default create({
inheritAttrs: false, inheritAttrs: false,
props: { props: {
value: null, value: [String, Number],
icon: String, icon: String,
label: String, label: String,
error: Boolean, error: Boolean,
@ -91,8 +90,8 @@ export default create({
}, },
computed: { computed: {
hasIcon() { showIcon() {
return this.$slots.icon || this.icon; return this.$slots.icon || (this.icon && this.value !== '' && this.isDef(this.value));
}, },
listeners() { listeners() {
@ -117,7 +116,7 @@ export default create({
onKeypress(event) { onKeypress(event) {
if (this.type === 'number') { if (this.type === 'number') {
const { keyCode } = event; const { keyCode } = event;
const allowPoint = this.value.indexOf('.') === -1; const allowPoint = String(this.value).indexOf('.') === -1;
const isValidKey = (keyCode >= 48 && keyCode <= 57) || (keyCode === 46 && allowPoint) || keyCode === 45; const isValidKey = (keyCode >= 48 && keyCode <= 57) || (keyCode === 46 && allowPoint) || keyCode === 45;
if (!isValidKey) { if (!isValidKey) {
event.preventDefault(); event.preventDefault();

View File

@ -19,7 +19,7 @@ exports[`renders demo correctly 1`] = `
</div> </div>
<div> <div>
<div class="van-cell-group van-hairline--top-bottom"> <div class="van-cell-group van-hairline--top-bottom">
<div placeholder="请输入用户名" class="van-cell van-cell--required van-hairline van-field van-field--has-icon"> <div placeholder="请输入用户名" class="van-cell van-cell--required van-hairline van-field">
<!----> <!---->
<div class="van-cell__title"><span>用户名</span> <div class="van-cell__title"><span>用户名</span>
<!----> <!---->
@ -27,11 +27,7 @@ exports[`renders demo correctly 1`] = `
<div class="van-cell__value"> <div class="van-cell__value">
<input type="text" placeholder="请输入用户名" value="" class="van-field__control"> <input type="text" placeholder="请输入用户名" value="" class="van-field__control">
<!----> <!---->
<div class="van-field__icon" style="display:none;">
<i class="van-icon van-icon-clear" style="color:undefined;">
<!----> <!---->
</i>
</div>
<!----> <!---->
</div> </div>
<!----> <!---->
@ -119,7 +115,7 @@ exports[`renders demo correctly 1`] = `
</div> </div>
<div> <div>
<div class="van-cell-group van-hairline--top-bottom"> <div class="van-cell-group van-hairline--top-bottom">
<div placeholder="请输入短信验证码" class="van-cell van-cell--center van-hairline van-field van-field--has-icon"> <div placeholder="请输入短信验证码" class="van-cell van-cell--center van-hairline van-field">
<!----> <!---->
<div class="van-cell__title"><span>短信验证码</span> <div class="van-cell__title"><span>短信验证码</span>
<!----> <!---->
@ -127,11 +123,7 @@ exports[`renders demo correctly 1`] = `
<div class="van-cell__value"> <div class="van-cell__value">
<input type="text" placeholder="请输入短信验证码" value="" class="van-field__control"> <input type="text" placeholder="请输入短信验证码" value="" class="van-field__control">
<!----> <!---->
<div class="van-field__icon" style="display:none;">
<i class="van-icon van-icon-clear" style="color:undefined;">
<!----> <!---->
</i>
</div>
</div> </div>
<!----> <!---->
<div class="van-field__button"> <div class="van-field__button">

View File

@ -14,6 +14,7 @@ test('click icon event', () => {
const onIconClick = jest.fn(); const onIconClick = jest.fn();
const wrapper = mount(Field, { const wrapper = mount(Field, {
propsData: { propsData: {
value: 'a',
icon: 'search', icon: 'search',
onIconClick onIconClick
} }

View File

@ -117,7 +117,7 @@ Field 默认支持 Input 标签所有的原生属性,比如 `maxlength`、`pla
| 参数 | 说明 | 类型 | 默认值 | | 参数 | 说明 | 类型 | 默认值 |
|-----------|-----------|-----------|-------------|-------------| |-----------|-----------|-----------|-------------|-------------|
| label | 标签 | `String` | - | | label | 标签 | `String` | - |
| value | 当前输入的值 | `String` | - | | value | 当前输入的值 | `String | Number` | - |
| type | 可设置为任意原生类型, 如 `number` `tel` `textarea` | `String` | `text` | | type | 可设置为任意原生类型, 如 `number` `tel` `textarea` | `String` | `text` |
| disabled | 是否禁用输入框 | `Boolean` | `false` | | disabled | 是否禁用输入框 | `Boolean` | `false` |
| error | 是否将输入内容标红 | `Boolean` | `false` | | error | 是否将输入内容标红 | `Boolean` | `false` |

View File

@ -156,18 +156,19 @@ Picker events will pass different parameters according to the columns are single
| defaultIndex | Default value index | | defaultIndex | Default value index |
| className | ClassName for this column | | className | ClassName for this column |
### Picker instance ### Methods
You can get the picker instance in 'change' event, and
| Method | Description | Use ref to get picker instance and call instance methods
|-----------|-----------|
| getValues() | Get current values of all columns | | Name | Attribute | Return value | Description |
| setValues(values) | Set current values of all columns | |-----------|-----------|-----------|-------------|
| getIndexes() | Get current indexes of all columns | | getValues | - | values | Get current values of all columns |
| setIndexes(indexes) | Set current indexes of all columns | | setValues | values | - | Set current values of all columns |
| getColumnValue(columnIndex) | Get current value of the column | | getIndexes | - | indexes | Get current indexes of all columns |
| setColumnValue(columnIndex, value) | Set current value of the column | | setIndexes | indexes | - | Set current indexes of all columns |
| getColumnIndex(columnIndex) | Get current index of the column | | getColumnValue | columnIndex | value | Get current value of the column |
| setColumnIndex(columnIndex, optionIndex) | Set current index of the column | | setColumnValue | columnIndex, value | - | Set current value of the column |
| getColumnValues(columnIndex) | Get columns data of the column | | getColumnIndex | columnIndex | optionIndex | Get current index of the column |
| setColumnValues(columnIndex, values) | Set columns data of the column | | setColumnIndex | columnIndex, optionIndex | - | Set current index of the column |
| getColumnValues | columnIndex | values | Get columns data of the column |
| setColumnValue | columnIndex, values | - | Set columns data of the column |

View File

@ -159,18 +159,19 @@ Picker 组件的事件会根据 columns 是单列或多列返回不同的参数
| defaultIndex | 初始选中项的索引,默认为 0 | | defaultIndex | 初始选中项的索引,默认为 0 |
| className | 为对应列添加额外的`class` | | className | 为对应列添加额外的`class` |
### Picker 实例 ### 方法
`change`事件中,可以获取到`picker`实例,通过实例方法可以灵活控制 Picker 内容
| 函数 | 说明 | 通过 ref 可以获取到 picker 实例并调用实例方法
|-----------|-----------|
| getValues() | 获取所有列选中的值,返回一个数组 | | 方法名 | 参数 | 返回值 | 介绍 |
| setValues(values) | 设置所有列选中的值 | |-----------|-----------|-----------|-------------|
| getIndexes() | 获取所有列选中值对应的索引,返回一个数组 | | getValues | - | values | 获取所有列选中的值 |
| setIndexes(indexes) | 设置所有列选中值对应的索引 | | setValues | values | - | 设置所有列选中的值 |
| getColumnValue(columnIndex) | 获取对应列选中的值 | | getIndexes | - | indexes | 获取所有列选中值对应的索引 |
| setColumnValue(columnIndex, value) | 设置对应列选中的值 | | setIndexes | indexes | - | 设置所有列选中值对应的索引 |
| getColumnIndex(columnIndex) | 获取对应列选中项的索引 | | getColumnValue | columnIndex | value | 获取对应列选中的值 |
| setColumnIndex(columnIndex, optionIndex) | 设置对应列选中项的索引 | | setColumnValue | columnIndex, value | - | 设置对应列选中的值 |
| getColumnValues(columnIndex) | 获取对应列中所有选项 | | getColumnIndex | columnIndex | optionIndex | 获取对应列选中项的索引 |
| setColumnValues(columnIndex, values) | 设置对应列中所有选项 | | setColumnIndex | columnIndex, optionIndex | - | 设置对应列选中项的索引 |
| getColumnValues | columnIndex | values | 获取对应列中所有选项 |
| setColumnValue | columnIndex, values | - | 设置对应列中所有选项 |

View File

@ -7,17 +7,13 @@ exports[`renders demo correctly 1`] = `
<i class="van-icon van-icon-search" style="color:undefined;"> <i class="van-icon van-icon-search" style="color:undefined;">
<!----> <!---->
</i> </i>
<div placeholder="请输入商品名称" class="van-cell van-field van-field--has-icon"> <div placeholder="请输入商品名称" class="van-cell van-field">
<!----> <!---->
<!----> <!---->
<div class="van-cell__value van-cell__value--alone"> <div class="van-cell__value van-cell__value--alone">
<input type="search" placeholder="请输入商品名称" value="" class="van-field__control"> <input type="search" placeholder="请输入商品名称" value="" class="van-field__control">
<!----> <!---->
<div class="van-field__icon" style="display:none;">
<i class="van-icon van-icon-clear" style="color:undefined;">
<!----> <!---->
</i>
</div>
<!----> <!---->
</div> </div>
<!----> <!---->
@ -31,17 +27,13 @@ exports[`renders demo correctly 1`] = `
<i class="van-icon van-icon-search" style="color:undefined;"> <i class="van-icon van-icon-search" style="color:undefined;">
<!----> <!---->
</i> </i>
<div placeholder="请输入商品名称" class="van-cell van-field van-field--has-icon"> <div placeholder="请输入商品名称" class="van-cell van-field">
<!----> <!---->
<!----> <!---->
<div class="van-cell__value van-cell__value--alone"> <div class="van-cell__value van-cell__value--alone">
<input type="search" placeholder="请输入商品名称" value="" class="van-field__control"> <input type="search" placeholder="请输入商品名称" value="" class="van-field__control">
<!----> <!---->
<div class="van-field__icon" style="display:none;">
<i class="van-icon van-icon-clear" style="color:undefined;">
<!----> <!---->
</i>
</div>
<!----> <!---->
</div> </div>
<!----> <!---->
@ -57,17 +49,13 @@ exports[`renders demo correctly 1`] = `
<i class="van-icon van-icon-search" style="color:undefined;"> <i class="van-icon van-icon-search" style="color:undefined;">
<!----> <!---->
</i> </i>
<div class="van-cell van-field van-field--has-icon"> <div class="van-cell van-field">
<!----> <!---->
<!----> <!---->
<div class="van-cell__value van-cell__value--alone"> <div class="van-cell__value van-cell__value--alone">
<input type="search" value="" class="van-field__control"> <input type="search" value="" class="van-field__control">
<!----> <!---->
<div class="van-field__icon" style="display:none;">
<i class="van-icon van-icon-clear" style="color:undefined;">
<!----> <!---->
</i>
</div>
<!----> <!---->
</div> </div>
<!----> <!---->

View File

@ -111,9 +111,11 @@ Vue.use(Sku);
### Methods ### Methods
| Method | Description | Use ref to get sku instance and call instance methods
|-----------|-----------|
| getSkuData() | Get current sku data | | Name | Attribute | Return value | Description |
|-----------|-----------|-----------|-------------|
| getSkuData | - | skuData | Get current skuData |
### Slot ### Slot

View File

@ -112,11 +112,14 @@ Vue.use(Sku);
### 方法 ### 方法
| 函数 | 说明 | 通过 ref 可以获取到 sku 实例并调用实例方法
|-----------|-----------|
| getSkuData() | 获取当前 skuData | | 方法名 | 参数 | 返回值 | 介绍 |
|-----------|-----------|-----------|-------------|
| getSkuData | - | skuData | 获取当前 skuData |
### Slot ### Slot
Sku 组件默认划分好了若干区块,这些区块都定义成了 slot可以按需进行替换。区块顺序见下表 Sku 组件默认划分好了若干区块,这些区块都定义成了 slot可以按需进行替换。区块顺序见下表
| 名称 | 说明 | | 名称 | 说明 |

View File

@ -94,3 +94,11 @@ export default {
| Event | Description | Arguments | | Event | Description | Arguments |
|-----------|-----------|-----------| |-----------|-----------|-----------|
| change | Triggered when current swipe change | index: index of current swipe | | change | Triggered when current swipe change | index: index of current swipe |
### Methods
Use ref to get swipe instance and call instance methods
| Name | Attribute | Return value | Description |
|-----------|-----------|-----------|-------------|
| swipeTo | index: 目标位置的索引 | void | 滚动到目标位置 |

View File

@ -90,6 +90,8 @@ export default create({
autoplay(autoplay) { autoplay(autoplay) {
if (!autoplay) { if (!autoplay) {
this.clear(); this.clear();
} else {
this.autoPlay();
} }
} }
}, },
@ -206,6 +208,15 @@ export default create({
this.offset = offset - this.active * this.size; this.offset = offset - this.active * this.size;
}, },
swipeTo(index) {
this.swiping = true;
this.correctPosition();
setTimeout(() => {
this.swiping = false;
this.move(index % this.count - this.active);
}, 30);
},
correctPosition() { correctPosition() {
if (this.active <= -1) { if (this.active <= -1) {
this.move(this.count); this.move(this.count);
@ -221,6 +232,7 @@ export default create({
autoPlay() { autoPlay() {
const { autoplay } = this; const { autoplay } = this;
if (autoplay && this.count > 1) { if (autoplay && this.count > 1) {
this.clear(); this.clear();
this.timer = setTimeout(() => { this.timer = setTimeout(() => {

View File

@ -0,0 +1,154 @@
import Swipe from '..';
import SwipeItem from '../../swipe-item';
import { mount } from '@vue/test-utils';
import { triggerDrag } from '../../../test/utils';
const Component = {
template: `
<swipe ref="swipe" v-bind="$props">
<swipe-item :style="style">1</swipe-item>
<swipe-item :style="style">2</swipe-item>
<swipe-item :style="style">3</swipe-item>
</swipe>
`,
components: {
Swipe,
SwipeItem
},
props: {
vertical: Boolean,
loop: {
type: Boolean,
default: true
},
touchable: {
type: Boolean,
default: true
},
autoplay: {
type: Number,
default: 0
},
initialSwipe: {
type: Number,
default: 0
}
},
data() {
return {
style: {
width: '100px',
height: '100px'
}
};
}
};
test('autoplay', done => {
const wrapper = mount(Component, {
propsData: {
autoplay: 20
}
});
const { swipe } = wrapper.vm.$refs;
setTimeout(() => {
expect(swipe.active).toEqual(1);
wrapper.setData({ autoplay: 0 });
setTimeout(() => {
expect(swipe.active).toEqual(1);
wrapper.setData({ autoplay: 20 });
setTimeout(() => {
expect(swipe.active).toEqual(2);
wrapper.destroy();
done();
}, 60);
}, 60);
}, 60);
});
test('swipeTo', done => {
const wrapper = mount(Component);
const { swipe } = wrapper.vm.$refs;
swipe.swipeTo(2);
setTimeout(() => {
expect(swipe.active).toEqual(2);
done();
}, 30);
});
test('initial swipe', () => {
const wrapper = mount(Component);
const { swipe } = wrapper.vm.$refs;
expect(swipe.active).toEqual(0);
wrapper.setProps({ initialSwipe: 2 });
expect(swipe.active).toEqual(2);
});
test('vertical swipe', () => {
const wrapper = mount(Component, {
propsData: {
vertical: true
}
});
const { swipe } = wrapper.vm.$refs;
const track = wrapper.find('.van-swipe__track');
triggerDrag(track, 0, -100);
expect(swipe.active).toEqual(1);
});
test('untouchable', () => {
const wrapper = mount(Component, {
propsData: {
touchable: false
}
});
const { swipe } = wrapper.vm.$refs;
const track = wrapper.find('.van-swipe__track');
triggerDrag(track, 100, 0);
expect(swipe.active).toEqual(0);
});
test('loop', () => {
const wrapper = mount(Component);
const { swipe } = wrapper.vm.$refs;
const track = wrapper.find('.van-swipe__track');
triggerDrag(track, -100, 0);
expect(swipe.active).toEqual(1);
triggerDrag(track, -100, 0);
expect(swipe.active).toEqual(2);
triggerDrag(track, -100, 0);
expect(swipe.active).toEqual(3);
triggerDrag(track, -100, 0);
expect(swipe.active).toEqual(1);
triggerDrag(track, 100, 0);
expect(swipe.active).toEqual(0);
triggerDrag(track, 100, 0);
expect(swipe.active).toEqual(-1);
triggerDrag(track, 100, 0);
expect(swipe.active).toEqual(1);
});
test('not loop', () => {
const wrapper = mount(Component, {
propsData: {
loop: false
}
});
const { swipe } = wrapper.vm.$refs;
const track = wrapper.find('.van-swipe__track');
triggerDrag(track, -100, 0);
expect(swipe.active).toEqual(1);
triggerDrag(track, -100, 0);
expect(swipe.active).toEqual(2);
triggerDrag(track, -100, 0);
expect(swipe.active).toEqual(2);
});

View File

@ -94,3 +94,11 @@ export default {
| 事件名 | 说明 | 参数 | | 事件名 | 说明 | 参数 |
|-----------|-----------|-----------| |-----------|-----------|-----------|
| change | 每一页轮播结束后触发 | index, 当前页的索引 | | change | 每一页轮播结束后触发 | index, 当前页的索引 |
### 方法
通过 ref 可以获取到 swipe 实例并调用实例方法
| 方法名 | 参数 | 返回值 | 介绍 |
|-----------|-----------|-----------|-------------|
| swipeTo | index: 目标位置的索引 | void | 滚动到目标位置 |