diff --git a/docs/demos/common.js b/docs/demos/common.js
index 21757d521..b2f7f208b 100644
--- a/docs/demos/common.js
+++ b/docs/demos/common.js
@@ -31,6 +31,8 @@ Vue.component('demo-section', DemoSection);
Locale.add({
'zh-CN': {
+ add: '增加',
+ decrease: '减少',
red: '红色',
orange: '橙色',
yellow: '黄色',
@@ -56,6 +58,8 @@ Locale.add({
passwordPlaceholder: '请输入密码'
},
'en-US': {
+ add: 'Add',
+ decrease: 'Decrease',
red: 'Red',
orange: 'Orange',
yellow: 'Yellow',
diff --git a/docs/demos/index.js b/docs/demos/index.js
index 7a6113cf3..a3c210b92 100644
--- a/docs/demos/index.js
+++ b/docs/demos/index.js
@@ -31,6 +31,7 @@ export default {
'cell-swipe': asyncWrapper(r => require.ensure([], () => r(componentWrapper(require('./views/cell-swipe'), 'cell-swipe')), 'cell-swipe')),
'cell': asyncWrapper(r => require.ensure([], () => r(componentWrapper(require('./views/cell'), 'cell')), 'cell')),
'checkbox': asyncWrapper(r => require.ensure([], () => r(componentWrapper(require('./views/checkbox'), 'checkbox')), 'checkbox')),
+ 'circle': asyncWrapper(r => require.ensure([], () => r(componentWrapper(require('./views/circle'), 'circle')), 'circle')),
'contact': asyncWrapper(r => require.ensure([], () => r(componentWrapper(require('./views/contact'), 'contact')), 'contact')),
'coupon': asyncWrapper(r => require.ensure([], () => r(componentWrapper(require('./views/coupon'), 'coupon')), 'coupon')),
'datetime-picker': asyncWrapper(r => require.ensure([], () => r(componentWrapper(require('./views/datetime-picker'), 'datetime-picker')), 'datetime-picker')),
diff --git a/docs/demos/views/circle.vue b/docs/demos/views/circle.vue
new file mode 100644
index 000000000..276724745
--- /dev/null
+++ b/docs/demos/views/circle.vue
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/demos/views/sku.vue b/docs/demos/views/sku.vue
index 6a956a76c..b09bb9ae8 100644
--- a/docs/demos/views/sku.vue
+++ b/docs/demos/views/sku.vue
@@ -13,6 +13,7 @@
:reset-stepper-on-hide="true"
:reset-selected-sku-on-hide="true"
:disable-stepper-input="true"
+ :message-config="messageConfig"
@buy-clicked="onBuyClicked"
@add-cart="onAddCartClicked"
/>
@@ -23,7 +24,7 @@
- {{ $t('title2') }}
+ {{ $t('title2') }}
@@ -94,6 +95,7 @@ export default {
return {
showBase: false,
showCustom: false,
+ showStepper: false,
initialSku: {
s1: '30349',
s2: '1193'
@@ -113,6 +115,14 @@ export default {
}
}
}
+ },
+ messageConfig: {
+ uploadImg: () => {
+ return new Promise((resolve) => {
+ setTimeout(() => resolve('https://img.yzcdn.cn/upload_files/2017/02/21/FjKTOxjVgnUuPmHJRdunvYky9OHP.jpg!100x100.jpg'), 1000);
+ });
+ },
+ uploadMaxSize: 3
}
};
},
diff --git a/docs/markdown/en-US/actionsheet.md b/docs/markdown/en-US/actionsheet.md
index 4bc0502c5..6a58204ed 100644
--- a/docs/markdown/en-US/actionsheet.md
+++ b/docs/markdown/en-US/actionsheet.md
@@ -61,6 +61,7 @@ Actionsheet will get another style if there is a `title` prop.
| cancel-text | Text of cancel button | `String` | - | - |
| overlay | Whether to show overlay | `Boolean` | - | - |
| close-on-click-overlay | Whether to close when click overlay | `Boolean` | - | - |
+| get-container | Return the mount node for actionsheet | `Function` | - | `() => HTMLElement` |
### Data struct of actions
diff --git a/docs/markdown/en-US/circle.md b/docs/markdown/en-US/circle.md
new file mode 100644
index 000000000..5e1bb8cda
--- /dev/null
+++ b/docs/markdown/en-US/circle.md
@@ -0,0 +1,69 @@
+## Circle
+
+### Install
+``` javascript
+import { Circle } from 'vant';
+
+Vue.use(Circle);
+```
+
+### Usage
+
+#### Basic Usage
+
+```html
+
+```
+
+``` javascript
+export default {
+ data() {
+ return {
+ currentRate: 0
+ };
+ },
+ computed: {
+ text() {
+ return this.currentRate.toFixed(0) + '%'
+ }
+ }
+};
+```
+
+#### Custom style
+
+```html
+
+```
+
+
+### API
+
+| Attribute | Description | Type | Default | Accepted Values |
+|-----------|-----------|-----------|-------------|-------------|
+| v-model | Current rate | `Number` | - | - |
+| rate | Target rate | `Number` | `100` | - |
+| size | Circle size | `String` | `100px` | - |
+| color | Progress bar color | `String` | `#38f` | - |
+| layer-color | Layer color | `String` | `#fff` | - |
+| fill | Fill color | `String` | `none` | - |
+| speed | Animate speed(rate/s)| `Number` | - | - |
+| text | Text | `String` | - | - |
+| stroke-width | Stroke width | `Number` | `40` | - |
+| clockwise | Is clockwise | `Boolean` | `true` | - |
diff --git a/docs/markdown/en-US/popup.md b/docs/markdown/en-US/popup.md
index a87291505..4c7474c94 100644
--- a/docs/markdown/en-US/popup.md
+++ b/docs/markdown/en-US/popup.md
@@ -48,3 +48,4 @@ Use `position` prop to set popup display position
| close-on-click-overlay | Close popup when click overlay | `Boolean` | `true` | - |
| transition | Transition | `String` | `popup-slide` | - |
| prevent-scroll | Prevent background scroll | `Boolean` | `false` | - |
+| get-container | Return the mount node for Popup | `Function` | - | `() => HTMLElement` |
diff --git a/docs/markdown/en-US/sku.md b/docs/markdown/en-US/sku.md
index 3c35d5bf3..e0706870c 100644
--- a/docs/markdown/en-US/sku.md
+++ b/docs/markdown/en-US/sku.md
@@ -22,6 +22,7 @@ Vue.use(Sku);
:reset-stepper-on-hide="resetStepperOnHide"
:reset-selected-sku-on-hide="resetSelectedSkuOnHide"
:disable-stepper-input="disableStepperInput"
+ :message-config="messageConfig"
@buy-clicked="onBuyClicked"
@add-cart="onAddCartClicked"
/>
@@ -90,6 +91,8 @@ Vue.use(Sku);
| disable-stepper-input | Whether to disable stepper input | `Boolean` | `false` | - |
| stepper-title | Quantity title | `String` | `Quantity` | - |
| custom-stepper-config | Custom stepper related config | `Object` | `{}` | - |
+| message-config | Message related config | `Object` | `{}` | - |
+| get-container | Return the mount node for sku | `Function` | - | `() => HTMLElement` |
### Event
@@ -200,6 +203,26 @@ customStepperConfig: {
}
```
+#### messageConfig Data Structure
+```javascript
+messageConfig: {
+ // the upload image callback
+ uploadImg: () => {
+ return new Promise((resolve) => {
+ setTimeout(() => resolve('https://img.yzcdn.cn/upload_files/2017/02/21/FjKTOxjVgnUuPmHJRdunvYky9OHP.jpg!100x100.jpg'), 1000);
+ });
+ },
+ // max file size (MB)
+ uploadMaxSize: 3,
+ // placehold config
+ placeholderMap: {
+ text: 'xxx',
+ tel: 'xxx',
+ ...
+ }
+}
+```
+
#### Event Params Data Structure
```javascript
diff --git a/docs/markdown/index.js b/docs/markdown/index.js
index 124f4cefe..e5108c2a8 100644
--- a/docs/markdown/index.js
+++ b/docs/markdown/index.js
@@ -25,6 +25,7 @@ export default {
'zh-CN/changelog-generated': wrapper(r => require.ensure([], () => r(require('./zh-CN/changelog-generated.md')), 'zh-CN/changelog-generated')),
'zh-CN/changelog': wrapper(r => require.ensure([], () => r(require('./zh-CN/changelog.md')), 'zh-CN/changelog')),
'zh-CN/checkbox': wrapper(r => require.ensure([], () => r(require('./zh-CN/checkbox.md')), 'zh-CN/checkbox')),
+ 'zh-CN/circle': wrapper(r => require.ensure([], () => r(require('./zh-CN/circle.md')), 'zh-CN/circle')),
'zh-CN/contact': wrapper(r => require.ensure([], () => r(require('./zh-CN/contact.md')), 'zh-CN/contact')),
'zh-CN/coupon': wrapper(r => require.ensure([], () => r(require('./zh-CN/coupon.md')), 'zh-CN/coupon')),
'zh-CN/datetime-picker': wrapper(r => require.ensure([], () => r(require('./zh-CN/datetime-picker.md')), 'zh-CN/datetime-picker')),
@@ -77,6 +78,7 @@ export default {
'en-US/cell': wrapper(r => require.ensure([], () => r(require('./en-US/cell.md')), 'en-US/cell')),
'en-US/changelog': wrapper(r => require.ensure([], () => r(require('./en-US/changelog.md')), 'en-US/changelog')),
'en-US/checkbox': wrapper(r => require.ensure([], () => r(require('./en-US/checkbox.md')), 'en-US/checkbox')),
+ 'en-US/circle': wrapper(r => require.ensure([], () => r(require('./en-US/circle.md')), 'en-US/circle')),
'en-US/contact': wrapper(r => require.ensure([], () => r(require('./en-US/contact.md')), 'en-US/contact')),
'en-US/coupon': wrapper(r => require.ensure([], () => r(require('./en-US/coupon.md')), 'en-US/coupon')),
'en-US/datetime-picker': wrapper(r => require.ensure([], () => r(require('./en-US/datetime-picker.md')), 'en-US/datetime-picker')),
diff --git a/docs/markdown/zh-CN/actionsheet.md b/docs/markdown/zh-CN/actionsheet.md
index 310808041..a91d53b94 100644
--- a/docs/markdown/zh-CN/actionsheet.md
+++ b/docs/markdown/zh-CN/actionsheet.md
@@ -72,6 +72,7 @@ export default {
| cancel-text | 取消按钮文案 | `String` | - | - |
| overlay | 是否显示遮罩 | `Boolean` | - | - |
| close-on-click-overlay | 点击遮罩是否关闭`Actionsheet` | `Boolean` | - | - |
+| get-container | 指定挂载的 HTML 节点 | `Function` | - | `() => HTMLElement` |
### actions
diff --git a/docs/markdown/zh-CN/circle.md b/docs/markdown/zh-CN/circle.md
new file mode 100644
index 000000000..e0c2fee3e
--- /dev/null
+++ b/docs/markdown/zh-CN/circle.md
@@ -0,0 +1,70 @@
+## Circle 环形进度条
+
+### 使用指南
+``` javascript
+import { Circle } from 'vant';
+
+Vue.use(Circle);
+```
+
+### 代码演示
+
+#### 基础用法
+通过 `rate` 指定目标进度,`v-model` 代表当前进度,`speed` 控制动画速度
+
+```html
+
+```
+
+``` javascript
+export default {
+ data() {
+ return {
+ currentRate: 0
+ };
+ },
+ computed: {
+ text() {
+ return this.currentRate.toFixed(0) + '%'
+ }
+ }
+};
+```
+
+#### 样式定制
+
+```html
+
+```
+
+
+### API
+
+| 参数 | 说明 | 类型 | 默认值 | 可选值 |
+|-----------|-----------|-----------|-------------|-------------|
+| v-model | 当前进度 | `Number` | - | - |
+| rate | 目标进度 | `Number` | `100` | - |
+| size | 圆环直径 | `String` | `100px` | - |
+| color | 进度条颜色 | `String` | `#38f` | - |
+| layer-color | 轨道颜色 | `String` | `#fff` | - |
+| fill | 填充颜色 | `String` | `none` | - |
+| speed | 动画速度(单位为 rate/s)| `Number` | - | - |
+| text | 文字 | `String` | - | - |
+| stroke-width | 进度条宽度 | `Number` | `40` | - |
+| clockwise | 是否顺时针增加 | `Boolean` | `true` | - |
diff --git a/docs/markdown/zh-CN/popup.md b/docs/markdown/zh-CN/popup.md
index e0ed9e492..47b33a47b 100644
--- a/docs/markdown/zh-CN/popup.md
+++ b/docs/markdown/zh-CN/popup.md
@@ -48,3 +48,4 @@ export default {
| close-on-click-overlay | 点击蒙层是否关闭 Popup | `Boolean` | `true` | - |
| transition | transition 名称 | `String` | `popup-slide` | - |
| prevent-scroll | 是否防止滚动穿透 | `Boolean` | `false` | - |
+| get-container | 指定弹出层挂载的 HTML 节点 | `Function` | - | `() => HTMLElement` |
diff --git a/docs/markdown/zh-CN/sku.md b/docs/markdown/zh-CN/sku.md
index 21b4f3a19..d5fec3c72 100644
--- a/docs/markdown/zh-CN/sku.md
+++ b/docs/markdown/zh-CN/sku.md
@@ -22,6 +22,7 @@ Vue.use(Sku);
:reset-stepper-on-hide="resetStepperOnHide"
:reset-selected-sku-on-hide="resetSelectedSkuOnHide"
:disable-stepper-input="disableStepperInput"
+ :message-config="messageConfig"
@buy-clicked="onBuyClicked"
@add-cart="onAddCartClicked"
/>
@@ -91,6 +92,8 @@ Vue.use(Sku);
| disable-stepper-input | 是否禁用sku中stepper的input框 | `Boolean` | `false` | - |
| stepper-title | 数量选择组件左侧文案 | `String` | `购买数量` | - |
| custom-stepper-config | 步进器相关自定义配置 | `Object` | `{}` | - |
+| message-config | 留言相关配置 | `Object` | `{}` | - |
+| get-container | 指定挂载的 HTML 节点 | `Function` | - | `() => HTMLElement` |
### Event
@@ -206,6 +209,26 @@ customStepperConfig: {
}
```
+#### messageConfig Data Structure
+```javascript
+messageConfig: {
+ // 图片上传回调,需要返回一个promise,promise正确执行的结果需要是一个图片url
+ uploadImg: () => {
+ return new Promise((resolve) => {
+ setTimeout(() => resolve('https://img.yzcdn.cn/upload_files/2017/02/21/FjKTOxjVgnUuPmHJRdunvYky9OHP.jpg!100x100.jpg'), 1000);
+ });
+ },
+ // 最大上传体积 (MB)
+ uploadMaxSize: 3,
+ // placehold配置
+ placeholderMap: {
+ text: 'xxx',
+ tel: 'xxx',
+ ...
+ }
+}
+```
+
#### 添加购物车和点击购买回调函数接收的 skuData 对象结构
```javascript
skuData: {
diff --git a/docs/src/doc.config.js b/docs/src/doc.config.js
index 6a4a29ffd..77189b041 100644
--- a/docs/src/doc.config.js
+++ b/docs/src/doc.config.js
@@ -80,6 +80,10 @@ module.exports = {
path: '/cell',
title: 'Cell - 单元格'
},
+ {
+ path: '/circle',
+ title: 'Circle - 环形进度条'
+ },
{
path: '/icon',
title: 'Icon - 图标'
@@ -358,6 +362,10 @@ module.exports = {
path: '/cell',
title: 'Cell'
},
+ {
+ path: '/circle',
+ title: 'Circle'
+ },
{
path: '/icon',
title: 'Icon'
diff --git a/packages/actionsheet/index.vue b/packages/actionsheet/index.vue
index ec1333ffa..0cc15f580 100644
--- a/packages/actionsheet/index.vue
+++ b/packages/actionsheet/index.vue
@@ -60,10 +60,6 @@ export default create({
}
},
- mounted() {
- this.value && this.open();
- },
-
methods: {
onClickItem(item) {
if (typeof item.callback === 'function') {
diff --git a/packages/circle/index.vue b/packages/circle/index.vue
new file mode 100644
index 000000000..1040124da
--- /dev/null
+++ b/packages/circle/index.vue
@@ -0,0 +1,126 @@
+
+
+
+
+ {{ text }}
+
+
+
+
+
diff --git a/packages/coupon-list/index.vue b/packages/coupon-list/index.vue
index b3dddeda5..a2e40cc17 100644
--- a/packages/coupon-list/index.vue
+++ b/packages/coupon-list/index.vue
@@ -53,7 +53,6 @@ import Cell from '../cell';
import CellGroup from '../cell-group';
import CouponItem from './Item';
import Field from '../field';
-import Popup from '../popup';
import VanButton from '../button';
export default create({
@@ -64,7 +63,6 @@ export default create({
Cell,
CellGroup,
Field,
- Popup,
CouponItem
},
diff --git a/packages/index.js b/packages/index.js
index cbd7e654f..f0c6cd13c 100644
--- a/packages/index.js
+++ b/packages/index.js
@@ -12,6 +12,7 @@ import CellGroup from './cell-group';
import CellSwipe from './cell-swipe';
import Checkbox from './checkbox';
import CheckboxGroup from './checkbox-group';
+import Circle from './circle';
import Col from './col';
import ContactCard from './contact-card';
import ContactEdit from './contact-edit';
@@ -77,6 +78,7 @@ const components = [
CellSwipe,
Checkbox,
CheckboxGroup,
+ Circle,
Col,
ContactCard,
ContactEdit,
@@ -149,6 +151,7 @@ export {
CellSwipe,
Checkbox,
CheckboxGroup,
+ Circle,
Col,
ContactCard,
ContactEdit,
diff --git a/packages/locale/lang/en-US.js b/packages/locale/lang/en-US.js
index 1523d74cd..d3fe13f4c 100644
--- a/packages/locale/lang/en-US.js
+++ b/packages/locale/lang/en-US.js
@@ -113,10 +113,12 @@ export default {
},
vanSkuMessages: {
fill: 'Please fill',
+ upload: 'Please upload',
number: 'Please fill in the correct number format message',
email: 'Please fill in the correct email message',
idcard: 'Please fill in the correct ID number message',
overlimit: 'not more than 200 words',
+ onePic: 'only one picture',
placeholder: {
'id_no': 'Idcard Number',
text: 'Text',
@@ -127,6 +129,15 @@ export default {
textarea: 'Text'
}
},
+ vanSkuImgUploader: {
+ or: 'Or',
+ uploading: 'Uploading...',
+ rephoto: 'Take Again',
+ photo: 'Take',
+ reselect: 'Reselect',
+ select: 'Select Photo',
+ maxSize: maxSize => `The upload limit is up to ${maxSize}MB,please try to compress the photo`
+ },
vanSkuStepper: {
title: 'Quantity',
remain: count => `Remain ${count} items`,
diff --git a/packages/locale/lang/zh-CN.js b/packages/locale/lang/zh-CN.js
index 074fa1f3c..582b3c79a 100644
--- a/packages/locale/lang/zh-CN.js
+++ b/packages/locale/lang/zh-CN.js
@@ -117,10 +117,12 @@ export default {
},
vanSkuMessages: {
fill: '请填写',
+ upload: '请上传',
number: '请填写正确的数字格式留言',
email: '请填写正确的邮箱',
'id_no': '请填写正确的身份证号码',
overlimit: '写的太多了,不要超过200字',
+ onePic: '仅限一张',
placeholder: {
'id_no': '输入18位身份证号码',
text: '输入文本',
@@ -131,6 +133,15 @@ export default {
textarea: '点击填写段落文本'
}
},
+ vanSkuImgUploader: {
+ or: '或',
+ uploading: '正在上传...',
+ rephoto: '重拍',
+ photo: '拍照',
+ reselect: '重新选择照片',
+ select: '选择照片',
+ maxSize: maxSize => `最大可上传图片为${maxSize}MB,请尝试压缩图片尺寸`
+ },
vanSkuStepper: {
title: '购买数量',
remain: count => `剩余${count}件`,
diff --git a/packages/mixins/popup/index.js b/packages/mixins/popup/index.js
index 7b51213ea..399f38edf 100644
--- a/packages/mixins/popup/index.js
+++ b/packages/mixins/popup/index.js
@@ -19,6 +19,8 @@ export default {
zIndex: [String, Number],
// prevent touchmove scroll
preventScroll: Boolean,
+ // return the mount node for popup
+ getContainer: Function,
// prevent body scroll
lockOnScroll: {
type: Boolean,
@@ -26,17 +28,8 @@ export default {
}
},
- watch: {
- value(val) {
- this[val ? 'open' : 'close']();
- }
- },
-
- beforeMount() {
- this._popupId = 'popup-' + context.plusKey('idSeed');
- },
-
data() {
+ this._popupId = 'popup-' + context.plusKey('idSeed');
return {
opened: false,
pos: {
@@ -46,6 +39,29 @@ export default {
};
},
+ watch: {
+ value(val) {
+ this[val ? 'open' : 'close']();
+ },
+
+ getContainer() {
+ this.move();
+ }
+ },
+
+ mounted() {
+ if (this.getContainer) {
+ this.move();
+ }
+ if (this.value) {
+ this.open();
+ }
+ },
+
+ beforeDestroy() {
+ this.doAfterClose();
+ },
+
methods: {
recordPosition(e) {
this.pos = {
@@ -65,12 +81,14 @@ export default {
let status = '11';
+ /* istanbul ignore next */
if (scrollTop === 0) {
status = offsetHeight >= scrollHeight ? '00' : '01';
} else if (scrollTop + offsetHeight >= scrollHeight) {
status = '10';
}
+ /* istanbul ignore next */
if (
status !== '11' &&
isVertical &&
@@ -82,6 +100,7 @@ export default {
},
open() {
+ /* istanbul ignore next */
if (this.opened || this.$isServer) {
return;
}
@@ -137,10 +156,14 @@ export default {
off(document, 'touchstart', this.recordPosition);
off(document, 'touchmove', this.watchTouchMove);
}
- }
- },
+ },
- beforeDestroy() {
- this.doAfterClose();
+ move() {
+ if (this.getContainer) {
+ this.getContainer().appendChild(this.$el);
+ } else if (this.$parent) {
+ this.$parent.$el.appendChild(this.$el);
+ }
+ }
}
};
diff --git a/packages/mixins/popup/manager.js b/packages/mixins/popup/manager.js
index 319c8da89..bf2e1c104 100644
--- a/packages/mixins/popup/manager.js
+++ b/packages/mixins/popup/manager.js
@@ -41,6 +41,7 @@ const manager = {
const { id, dom } = config;
const exist = context.stack.some(item => item.id === id);
+ /* istanbul ignore next */
if (!exist) {
const targetNode = dom && dom.parentNode && dom.parentNode.nodeType !== 11 ? dom.parentNode : document.body;
context.stack.push({ instance, id, config, targetNode });
diff --git a/packages/picker/PickerColumn.vue b/packages/picker/PickerColumn.vue
index 365973601..97e6da7e1 100644
--- a/packages/picker/PickerColumn.vue
+++ b/packages/picker/PickerColumn.vue
@@ -13,6 +13,7 @@
{{ cancelButtonText || $t('cancel') }}
+
{{ confirmButtonText || $t('confirm') }}
-
diff --git a/packages/popup/index.vue b/packages/popup/index.vue
index 9700ce2ce..a6291cfa5 100644
--- a/packages/popup/index.vue
+++ b/packages/popup/index.vue
@@ -41,12 +41,6 @@ export default create({
currentValue: false,
currentTransition: transition
};
- },
-
- mounted() {
- if (this.value) {
- this.open();
- }
}
});
diff --git a/packages/sku/Sku.vue b/packages/sku/Sku.vue
index 7d503a2ab..807ebfe77 100644
--- a/packages/sku/Sku.vue
+++ b/packages/sku/Sku.vue
@@ -1,5 +1,12 @@
-
+
@@ -74,7 +81,7 @@
@@ -134,6 +141,7 @@ export default create({
goodsId: [Number, String],
stepperTitle: String,
hideStock: Boolean,
+ getContainer: Function,
resetStepperOnHide: Boolean,
resetSelectedSkuOnHide: Boolean,
disableStepperInput: Boolean,
@@ -157,9 +165,13 @@ export default create({
type: Number,
default: 200
},
- messagePlaceholderMap: {
+ messageConfig: {
type: Object,
- default: () => ({})
+ default: () => ({
+ placeholderMap: {},
+ uploadImg: () => Promise.resolve(),
+ uploadMaxSize: 5
+ })
},
customStepperConfig: {
type: Object,
diff --git a/packages/sku/components/SkuHeader.vue b/packages/sku/components/SkuHeader.vue
index b8469abd9..0303121d5 100644
--- a/packages/sku/components/SkuHeader.vue
+++ b/packages/sku/components/SkuHeader.vue
@@ -4,7 +4,7 @@
diff --git a/packages/sku/components/SkuImgUploader.vue b/packages/sku/components/SkuImgUploader.vue
new file mode 100644
index 000000000..e2bc4d06b
--- /dev/null
+++ b/packages/sku/components/SkuImgUploader.vue
@@ -0,0 +1,122 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
![]()
+
+
+
+
![]()
+
+
+
+
+
+
+
diff --git a/packages/sku/components/SkuMessages.vue b/packages/sku/components/SkuMessages.vue
index a1839030c..ecf606467 100644
--- a/packages/sku/components/SkuMessages.vue
+++ b/packages/sku/components/SkuMessages.vue
@@ -1,14 +1,29 @@
-
+
+
+
+ |
+
+
@@ -16,30 +31,36 @@
import { create } from '../../utils';
import Field from '../../field';
import CellGroup from '../../cell-group';
+import Cell from '../../cell';
import validateEmail from '../../utils/validate/email';
import validateNumber from '../../utils/validate/number';
+import SkuImgUploader from './SkuImgUploader';
export default create({
name: 'van-sku-messages',
components: {
+ SkuImgUploader,
Field,
+ Cell,
CellGroup
},
props: {
messages: Array,
- messagePlaceholderMap: Object,
+ messageConfig: Object,
goodsId: [Number, String]
},
- computed: {
- internalMessages() {
- return Array.isArray(this.messages) ? this.messages.filter(message => message.type !== 'image') : [];
- },
+ data() {
+ return {
+ messageValues: this.messages.map(() => ({ value: '' }))
+ };
+ },
- messageValues() {
- return this.internalMessages.map(() => '');
+ computed: {
+ messagePlaceholderMap() {
+ return this.messageConfig.placeholderMap || {};
}
},
@@ -57,8 +78,9 @@ export default create({
getMessages() {
const messages = {};
- this.messageValues.forEach((value, index) => {
- if (this.internalMessages[index].datetime > 0) {
+ this.messageValues.forEach((item, index) => {
+ let value = item.value;
+ if (this.messages[index].datetime > 0) {
value = value.replace(/T/g, ' ');
}
messages[`message_${index}`] = value;
@@ -70,8 +92,9 @@ export default create({
getCartMessages() {
const messages = {};
- this.messageValues.forEach((value, index) => {
- const message = this.internalMessages[index];
+ this.messageValues.forEach((item, index) => {
+ let value = item.value;
+ const message = this.messages[index];
if (message.datetime > 0) {
value = value.replace(/T/g, ' ');
}
@@ -90,17 +113,16 @@ export default create({
const values = this.messageValues;
for (let i = 0; i < values.length; i++) {
- const value = values[i];
- const message = this.internalMessages[i];
+ const value = values[i].value;
+ const message = this.messages[i];
if (value === '') {
// 必填字段的校验
if (message.required == '1') { // eslint-disable-line
- if (message.type === 'image') {
- continue;
- } else {
- return this.$t('fill') + message.name;
- }
+ const textType = message.type === 'image'
+ ? 'upload'
+ : 'fill';
+ return this.$t(textType) + message.name;
}
} else {
if (message.type === 'tel' && !validateNumber(value)) {
diff --git a/packages/sku/components/SkuStepper.vue b/packages/sku/components/SkuStepper.vue
index 4c705a41d..d1f496706 100644
--- a/packages/sku/components/SkuStepper.vue
+++ b/packages/sku/components/SkuStepper.vue
@@ -9,6 +9,7 @@
:max="stepperLimit"
:disable-input="disableStepperInput"
@overlimit="onOverLimit"
+ @change="onChange"
/>
{{ $t('remain', stock) }}
@@ -104,7 +105,6 @@ export default create({
setCurrentNum(num) {
this.currentNum = num;
},
-
onOverLimit(action) {
this.skuEventBus.$emit('sku:overLimit', {
action,
@@ -112,6 +112,10 @@ export default create({
quota: this.quota,
quotaUsed: this.quotaUsed
});
+ },
+ onChange(currentValue) {
+ const { handleStepperChange } = this.customStepperConfig;
+ handleStepperChange && handleStepperChange(currentValue);
}
}
});
diff --git a/packages/steps/index.vue b/packages/steps/index.vue
index 6bf478b8e..2e3a5aae2 100644
--- a/packages/steps/index.vue
+++ b/packages/steps/index.vue
@@ -8,7 +8,7 @@
diff --git a/packages/tabs/index.vue b/packages/tabs/index.vue
index 11eb46034..e55607139 100644
--- a/packages/tabs/index.vue
+++ b/packages/tabs/index.vue
@@ -22,7 +22,7 @@
@click="onClick(index)"
>
- {{ tab.title }}
+ {{ tab.title }}
diff --git a/packages/tree-select/index.vue b/packages/tree-select/index.vue
index 774d8f8c7..bdb8bb8eb 100644
--- a/packages/tree-select/index.vue
+++ b/packages/tree-select/index.vue
@@ -3,7 +3,7 @@
{{ item.text }}
@@ -13,7 +13,7 @@
{{ item.text }}
diff --git a/packages/vant-css/src/base.css b/packages/vant-css/src/base.css
index 940055af6..a5086616b 100644
--- a/packages/vant-css/src/base.css
+++ b/packages/vant-css/src/base.css
@@ -4,5 +4,6 @@
@import "./common/var.css";
@import "./common/normalize.css";
+@import "./common/ellipsis.css";
@import "./common/hairline.css";
@import "./common/animation.css";
diff --git a/packages/vant-css/src/circle.css b/packages/vant-css/src/circle.css
new file mode 100644
index 000000000..49eb936db
--- /dev/null
+++ b/packages/vant-css/src/circle.css
@@ -0,0 +1,32 @@
+@import './common/var.css';
+
+.van-circle {
+ position: relative;
+ text-align: center;
+ display: inline-block;
+
+ svg {
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ }
+
+ &__layer {
+ fill: none;
+ stroke-dasharray: 3140px;
+ stroke-dashoffset: 3140px;
+ transform: rotate(90deg);
+ transform-origin: 530px 530px;
+ }
+
+ &__text {
+ top: 50%;
+ left: 0;
+ width: 100%;
+ color: $text-color;
+ position: absolute;
+ transform: translateY(-50%);
+ }
+}
diff --git a/packages/vant-css/src/common/ellipsis.css b/packages/vant-css/src/common/ellipsis.css
new file mode 100644
index 000000000..b7e70beee
--- /dev/null
+++ b/packages/vant-css/src/common/ellipsis.css
@@ -0,0 +1,5 @@
+@import '../mixins/ellipsis.css';
+
+.van-ellipsis {
+ @mixin ellipsis;
+}
diff --git a/packages/vant-css/src/index.css b/packages/vant-css/src/index.css
index a0ec70bd4..e2f140575 100644
--- a/packages/vant-css/src/index.css
+++ b/packages/vant-css/src/index.css
@@ -12,7 +12,7 @@
@import './badge.css';
@import './button.css';
@import './cell.css';
-@import './card.css';
+@import './circle.css';
@import './loading.css';
@import './nav-bar.css';
@import './notice-bar.css';
@@ -53,6 +53,7 @@
/* business components */
@import './address-edit.css';
@import './address-list.css';
+@import './card.css';
@import './contact-card.css';
@import './contact-list.css';
@import './contact-edit.css';
diff --git a/packages/vant-css/src/picker.css b/packages/vant-css/src/picker.css
index c24923b30..ff7642d2c 100644
--- a/packages/vant-css/src/picker.css
+++ b/packages/vant-css/src/picker.css
@@ -1,5 +1,4 @@
@import './common/var.css';
-@import './mixins/ellipsis.css';
.van-picker {
overflow: hidden;
@@ -7,8 +6,10 @@
background-color: $white;
&__toolbar {
+ display: flex;
height: 40px;
line-height: 40px;
+ justify-content: space-between;
}
&__cancel,
@@ -21,17 +22,9 @@
}
}
- &__cancel {
- float: left;
- }
-
- &__confirm {
- float: right;
- }
-
&__title {
+ max-width: 50%;
text-align: center;
- @mixin ellipsis;
}
&__columns {
@@ -52,13 +45,12 @@
&-column {
flex: 1;
overflow: hidden;
- font-size: 18px;
+ font-size: 17px;
text-align: center;
li {
- padding: 0 10px;
+ padding: 0 5px;
color: $gray-darker;
- @mixin ellipsis;
}
li&--selected {
diff --git a/packages/vant-css/src/sku.css b/packages/vant-css/src/sku.css
index 392f40626..f1d70af18 100644
--- a/packages/vant-css/src/sku.css
+++ b/packages/vant-css/src/sku.css
@@ -1,4 +1,5 @@
@import './common/var.css';
+@import './mixins/clearfix.css';
.van-sku {
&-container {
@@ -67,9 +68,6 @@
&__goods-name {
font-size: 12px;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
}
&__price-symbol {
@@ -147,7 +145,7 @@
margin-right: 20px;
}
}
-
+
&__stepper {
top: 7px;
left: 4px;
@@ -166,13 +164,85 @@
color: $gray-dark;
font-size: 12px;
}
-
+
&__quota {
display: inline-block;
color: $red;
font-size: 12px;
}
+ &-messages {
+ &__image-cell {
+ .van-cell__title {
+ width: 90px;
+ }
+ .van-cell__value {
+ text-align: left;
+ }
+ }
+ }
+
+ &-img-uploader {
+ display: inline-block;
+
+ &__header {
+ padding: 0 10px;
+ border: 1px solid #e5e5e5;
+ line-height: 24px;
+ border-radius: 3px;
+ font-size: 12px;
+
+ .van-icon {
+ top: 3px;
+ margin-right: 5px;
+ font-size: 14px;
+ }
+ }
+
+ &__imglist {
+ @mixin clearfix;
+ }
+
+ &__img-container {
+ height: 60px;
+ width: 60px;
+ margin-top: 10px;
+ margin-right: 10px;
+ float: left;
+ position: relative;
+ border: #e5e5e5 1px solid;
+
+ img {
+ max-width: 100%;
+ max-height: 100%;
+ top: 50%;
+ position: relative;
+ transform: translateY(-50%);
+ }
+ }
+
+ &__delete-picture {
+ position: absolute;
+ color: $red;
+ top: -10px;
+ right: -17px;
+ z-index: 1;
+ width: 22px;
+ height: 22px;
+ }
+
+ &__uploading {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ margin: auto;
+ width: 20px;
+ height: 20px;
+ }
+ }
+
/* sku actions */
&-actions {
display: flex;
diff --git a/packages/vant-css/src/steps.css b/packages/vant-css/src/steps.css
index 15250a472..8431a2ee1 100644
--- a/packages/vant-css/src/steps.css
+++ b/packages/vant-css/src/steps.css
@@ -1,5 +1,4 @@
@import './common/var.css';
-@import './mixins/ellipsis.css';
.van-steps {
overflow: hidden;
@@ -49,7 +48,6 @@
font-size: 12px;
line-height: 1.5;
color: $gray-dark;
- @mixin ellipsis;
}
}
diff --git a/packages/vant-css/src/tab.css b/packages/vant-css/src/tab.css
index 0e56df079..413ca3706 100644
--- a/packages/vant-css/src/tab.css
+++ b/packages/vant-css/src/tab.css
@@ -1,5 +1,4 @@
@import './common/var.css';
-@import './mixins/ellipsis.css';
$van-tabs-line-height: 44px;
$van-tabs-card-height: 30px;
@@ -118,7 +117,6 @@ $van-tabs-card-height: 30px;
span {
display: block;
- @mixin ellipsis;
}
&:active {
diff --git a/packages/vant-css/src/tree-select.css b/packages/vant-css/src/tree-select.css
index e47b6db13..d08e0200d 100644
--- a/packages/vant-css/src/tree-select.css
+++ b/packages/vant-css/src/tree-select.css
@@ -22,7 +22,6 @@
line-height: 44px;
padding: 0 15px;
background-color: $white;
- @mixin ellipsis;
&--active {
background-color: $background-color;
@@ -41,7 +40,6 @@
line-height: 44px;
padding-left: 5px;
padding-right: 18px;
- @mixin ellipsis;
&--active {
color: $button-danger-background-color;
@@ -54,5 +52,6 @@
right: 0;
top: 0;
bottom: 0;
+ line-height: inherit;
}
}
diff --git a/test/unit/specs/circle.spec.js b/test/unit/specs/circle.spec.js
new file mode 100644
index 000000000..7fff94e7c
--- /dev/null
+++ b/test/unit/specs/circle.spec.js
@@ -0,0 +1,65 @@
+import { mount } from 'avoriaz';
+import Circle from 'packages/circle';
+
+describe('Circle', () => {
+ let wrapper;
+ afterEach(() => {
+ wrapper && wrapper.destroy();
+ });
+
+ it('create a circle', () => {
+ wrapper = mount(Circle, {
+ propsData: {
+ text: 'test'
+ }
+ });
+
+ expect(wrapper.hasClass('van-circle')).to.be.true;
+ expect(wrapper.find('.van-circle__text')[0].text()).to.equal('test');
+ });
+
+ it('circle rate', done => {
+ let currentRate = 0;
+ wrapper = mount(Circle, {
+ propsData: {
+ rate: 0,
+ value: 0,
+ clockwise: false
+ }
+ });
+ wrapper.vm.$on('input', rate => {
+ currentRate = rate;
+ });
+ wrapper.vm.rate = 50;
+
+ setTimeout(() => {
+ expect(currentRate).to.equal(50);
+ done();
+ }, 100);
+ });
+
+ it('circle animation', done => {
+ let currentRate = 0;
+ wrapper = mount(Circle, {
+ propsData: {
+ rate: 0,
+ value: 0,
+ speed: 500,
+ clockwise: false
+ }
+ });
+ wrapper.vm.$on('input', rate => {
+ currentRate = rate;
+ });
+ wrapper.vm.rate = 50;
+
+ setTimeout(() => {
+ expect(currentRate === 50).to.be.false;
+ setTimeout(() => {
+ expect(currentRate === 50).to.be.true;
+ done();
+ }, 200);
+ }, 50);
+ });
+});
+
diff --git a/test/unit/specs/popup.spec.js b/test/unit/specs/popup.spec.js
index 991baf866..7f13782c6 100644
--- a/test/unit/specs/popup.spec.js
+++ b/test/unit/specs/popup.spec.js
@@ -22,7 +22,10 @@ describe('Popup', () => {
it('create a show popup', (done) => {
wrapper = mount(Popup, {
propsData: {
- value: false
+ value: false,
+ zIndex: 100,
+ overlay: false,
+ lockOnScroll: true
}
});
@@ -125,4 +128,23 @@ describe('Popup', () => {
expect(wrapper.vm.lockOnScroll).to.be.true;
});
+
+ it('get container prop', done => {
+ const testNode = document.createElement('div');
+ document.body.appendChild(testNode);
+
+ wrapper = mount(Popup, {
+ propsData: {
+ getContainer: () => testNode
+ }
+ });
+
+ expect(wrapper.vm.$el.parentNode === testNode).to.be.true;
+ wrapper.vm.getContainer = () => document.body;
+
+ setTimeout(() => {
+ expect(wrapper.vm.$el.parentNode === document.body).to.be.true;
+ done();
+ }, 100);
+ });
});
diff --git a/test/unit/specs/sku.spec.js b/test/unit/specs/sku.spec.js
index 499939444..6d2947dee 100644
--- a/test/unit/specs/sku.spec.js
+++ b/test/unit/specs/sku.spec.js
@@ -1,4 +1,5 @@
import Sku from 'packages/sku';
+import Uploader from 'packages/uploader';
import Toast from 'packages/toast';
import { mount } from 'avoriaz';
import { DOMChecker } from '../utils';
@@ -13,6 +14,13 @@ const initialSku = {
};
goods.picture = goods.picture[0];
+const File = function() {
+ this.name = 'test';
+ this.size = 10000;
+};
+
+const mockFile = new File([], '/Users');
+
describe('Sku', (done) => {
let wrapper;
afterEach(() => {
@@ -239,7 +247,15 @@ describe('Sku', (done) => {
value: true,
sku: data.sku,
goodsId: data.goods_id,
- goods: goods
+ goods: goods,
+ messageConfig: {
+ uploadImg: () => {
+ return new Promise((resolve) => {
+ setTimeout(() => resolve('https://img.yzcdn.cn/upload_files/2017/02/21/FjKTOxjVgnUuPmHJRdunvYky9OHP.jpg!100x100.jpg'), 1000);
+ });
+ },
+ uploadMaxSize: 3
+ }
}
});
@@ -247,12 +263,15 @@ describe('Sku', (done) => {
const skuMessages = wrapper.find('.van-sku-messages')[0];
const inputs = skuMessages.find('input');
const textarea = skuMessages.find('textarea')[0];
+ const uploader = wrapper.find(Uploader)[0];
// 修改留言内容
inputs[0].element.value = 123;
// 测试身份证号
inputs[1].element.value = 234;
inputs[0].trigger('input');
inputs[1].trigger('input');
+ // 测试图片
+ uploader.vm.onChange({ target: { files: [mockFile] }});
wrapper.vm.$nextTick(() => {
// 点击购买
@@ -276,9 +295,9 @@ describe('Sku', (done) => {
textarea.element.value = '';
// 测试数字留言
- inputs[2].element.value = 'abc';
+ inputs[3].element.value = 'abc';
textarea.trigger('input');
- inputs[2].trigger('input');
+ inputs[3].trigger('input');
wrapper.vm.$nextTick(() => {
buyBtn.trigger('click');
@@ -286,10 +305,10 @@ describe('Sku', (done) => {
wrapper.vm.$nextTick(() => {
expect(toastText.textContent).to.equal('请填写正确的数字格式留言');
- inputs[2].element.value = 0;
- inputs[3].element.value = 345;
- inputs[2].trigger('input');
+ inputs[3].element.value = 0;
+ inputs[4].element.value = 345;
inputs[3].trigger('input');
+ inputs[4].trigger('input');
wrapper.vm.$nextTick(() => {
buyBtn.trigger('click');