mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-04-06 03:57:59 +08:00
Merge branch 'dev' of https://github.com/youzan/vant into dev
This commit is contained in:
commit
6c7f8342b9
@ -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',
|
||||
|
@ -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')),
|
||||
|
78
docs/demos/views/circle.vue
Normal file
78
docs/demos/views/circle.vue
Normal file
@ -0,0 +1,78 @@
|
||||
<template>
|
||||
<demo-section>
|
||||
<demo-block :title="$t('basicUsage')">
|
||||
<van-circle
|
||||
v-model="currentRate1"
|
||||
:rate="rate"
|
||||
:speed="100"
|
||||
size="120px"
|
||||
:text="currentRate1.toFixed(0) + '%'"
|
||||
/>
|
||||
<van-circle
|
||||
v-model="currentRate2"
|
||||
color="#13ce66"
|
||||
fill="#fff"
|
||||
:rate="rate"
|
||||
size="120px"
|
||||
layer-color="#eee"
|
||||
:speed="100"
|
||||
:stroke-width="60"
|
||||
:clockwise="false"
|
||||
:text="currentRate2.toFixed(0) + '%'"
|
||||
/>
|
||||
<div>
|
||||
<van-button :text="$t('add')" type="primary" size="small" @click="add" />
|
||||
<van-button :text="$t('decrease')" type="danger" size="small" @click="reduce" />
|
||||
</div>
|
||||
</demo-block>
|
||||
</demo-section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const format = rate => Math.min(Math.max(rate, 0), 100);
|
||||
|
||||
export default {
|
||||
i18n: {
|
||||
'zh-CN': {
|
||||
title2: '样式定制'
|
||||
},
|
||||
'en-US': {
|
||||
title2: 'Custom Style'
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
rate: 30,
|
||||
currentRate1: 0,
|
||||
currentRate2: 0
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
add() {
|
||||
this.rate = format(this.rate + 20);
|
||||
},
|
||||
|
||||
reduce() {
|
||||
this.rate = format(this.rate - 20);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="postcss">
|
||||
.demo-circle {
|
||||
.van-circle {
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
.van-button {
|
||||
margin: 15px 0 0 10px;
|
||||
|
||||
&:first-of-type {
|
||||
margin-left: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -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 @@
|
||||
<demo-block :title="$t('title2')">
|
||||
<div class="sku-container">
|
||||
<van-sku
|
||||
v-model="showBase"
|
||||
v-model="showStepper"
|
||||
:sku="$t('sku').sku"
|
||||
:goods="$t('sku').goods_info"
|
||||
:goods-id="$t('sku').goods_id"
|
||||
@ -34,7 +35,7 @@
|
||||
@buy-clicked="onBuyClicked"
|
||||
@add-cart="onAddCartClicked"
|
||||
/>
|
||||
<van-button type="primary" @click="showBase = true" block>{{ $t('title2') }}</van-button>
|
||||
<van-button type="primary" @click="showStepper = true" block>{{ $t('title2') }}</van-button>
|
||||
</div>
|
||||
</demo-block>
|
||||
|
||||
@ -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
|
||||
}
|
||||
};
|
||||
},
|
||||
|
@ -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
|
||||
|
||||
|
69
docs/markdown/en-US/circle.md
Normal file
69
docs/markdown/en-US/circle.md
Normal file
@ -0,0 +1,69 @@
|
||||
## Circle
|
||||
|
||||
### Install
|
||||
``` javascript
|
||||
import { Circle } from 'vant';
|
||||
|
||||
Vue.use(Circle);
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
#### Basic Usage
|
||||
|
||||
```html
|
||||
<van-circle
|
||||
v-model="currentRate"
|
||||
:rate="30"
|
||||
:speed="100"
|
||||
:text="text"
|
||||
/>
|
||||
```
|
||||
|
||||
``` javascript
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
currentRate: 0
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
text() {
|
||||
return this.currentRate.toFixed(0) + '%'
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
#### Custom style
|
||||
|
||||
```html
|
||||
<van-circle
|
||||
v-model="currentRate"
|
||||
color="#13ce66"
|
||||
fill="#fff"
|
||||
size="120px"
|
||||
layer-color="#eee"
|
||||
:text="text"
|
||||
:rate="rate"
|
||||
:speed="100"
|
||||
:clockwise="false"
|
||||
:stroke-width="60"
|
||||
/>
|
||||
```
|
||||
|
||||
|
||||
### 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` | - |
|
@ -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` |
|
||||
|
@ -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
|
||||
|
@ -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')),
|
||||
|
@ -72,6 +72,7 @@ export default {
|
||||
| cancel-text | 取消按钮文案 | `String` | - | - |
|
||||
| overlay | 是否显示遮罩 | `Boolean` | - | - |
|
||||
| close-on-click-overlay | 点击遮罩是否关闭`Actionsheet` | `Boolean` | - | - |
|
||||
| get-container | 指定挂载的 HTML 节点 | `Function` | - | `() => HTMLElement` |
|
||||
|
||||
### actions
|
||||
|
||||
|
70
docs/markdown/zh-CN/circle.md
Normal file
70
docs/markdown/zh-CN/circle.md
Normal file
@ -0,0 +1,70 @@
|
||||
## Circle 环形进度条
|
||||
|
||||
### 使用指南
|
||||
``` javascript
|
||||
import { Circle } from 'vant';
|
||||
|
||||
Vue.use(Circle);
|
||||
```
|
||||
|
||||
### 代码演示
|
||||
|
||||
#### 基础用法
|
||||
通过 `rate` 指定目标进度,`v-model` 代表当前进度,`speed` 控制动画速度
|
||||
|
||||
```html
|
||||
<van-circle
|
||||
v-model="currentRate"
|
||||
:rate="30"
|
||||
:speed="100"
|
||||
:text="text"
|
||||
/>
|
||||
```
|
||||
|
||||
``` javascript
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
currentRate: 0
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
text() {
|
||||
return this.currentRate.toFixed(0) + '%'
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
#### 样式定制
|
||||
|
||||
```html
|
||||
<van-circle
|
||||
v-model="currentRate"
|
||||
color="#13ce66"
|
||||
fill="#fff"
|
||||
size="120px"
|
||||
layer-color="#eee"
|
||||
:text="text"
|
||||
:rate="rate"
|
||||
:speed="100"
|
||||
:clockwise="false"
|
||||
:stroke-width="60"
|
||||
/>
|
||||
```
|
||||
|
||||
|
||||
### 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` | - |
|
@ -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` |
|
||||
|
@ -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: {
|
||||
|
@ -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'
|
||||
|
@ -60,10 +60,6 @@ export default create({
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.value && this.open();
|
||||
},
|
||||
|
||||
methods: {
|
||||
onClickItem(item) {
|
||||
if (typeof item.callback === 'function') {
|
||||
|
126
packages/circle/index.vue
Normal file
126
packages/circle/index.vue
Normal file
@ -0,0 +1,126 @@
|
||||
<template>
|
||||
<div class="van-circle" :style="style">
|
||||
<svg viewBox="0 0 1060 1060">
|
||||
<path class="van-circle__hover" :style="hoverStyle" :d="path" />
|
||||
<path class="van-circle__layer" :style="layerStyle" :d="path" />
|
||||
</svg>
|
||||
<slot>
|
||||
<div class="van-circle__text">{{ text }}</div>
|
||||
</slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { create } from '../utils';
|
||||
import { raf, cancel } from '../utils/raf';
|
||||
|
||||
export default create({
|
||||
name: 'van-circle',
|
||||
|
||||
props: {
|
||||
text: String,
|
||||
value: Number,
|
||||
speed: Number,
|
||||
size: {
|
||||
type: String,
|
||||
default: '100px'
|
||||
},
|
||||
fill: {
|
||||
type: String,
|
||||
default: 'none'
|
||||
},
|
||||
rate: {
|
||||
type: Number,
|
||||
default: 100
|
||||
},
|
||||
layerColor: {
|
||||
type: String,
|
||||
default: '#fff'
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: '#38f'
|
||||
},
|
||||
strokeWidth: {
|
||||
type: Number,
|
||||
default: 40
|
||||
},
|
||||
clockwise: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
|
||||
beforeCreate() {
|
||||
this.perimeter = Math.PI * 1000;
|
||||
this.path = 'M 530 530 m -500, 0 a 500, 500 0 1, 1 1000, 0 a 500, 500 0 1, 1 -1000, 0';
|
||||
},
|
||||
|
||||
computed: {
|
||||
style() {
|
||||
return {
|
||||
width: this.size,
|
||||
height: this.size
|
||||
};
|
||||
},
|
||||
|
||||
layerStyle() {
|
||||
let offset = this.perimeter * (100 - this.value) / 100;
|
||||
offset = this.clockwise ? offset : this.perimeter * 2 - offset;
|
||||
return {
|
||||
stroke: `${this.color}`,
|
||||
strokeDashoffset: `${offset}px`,
|
||||
strokeWidth: `${this.strokeWidth + 1}px`
|
||||
};
|
||||
},
|
||||
|
||||
hoverStyle() {
|
||||
return {
|
||||
fill: `${this.fill}`,
|
||||
stroke: `${this.layerColor}`,
|
||||
strokeWidth: `${this.strokeWidth}px`
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.render();
|
||||
},
|
||||
|
||||
watch: {
|
||||
rate() {
|
||||
this.render();
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
render() {
|
||||
this.startTime = Date.now();
|
||||
this.startRate = this.value;
|
||||
this.endRate = this.format(this.rate);
|
||||
this.increase = this.endRate > this.startRate;
|
||||
this.duration = Math.abs((this.startRate - this.endRate) * 1000 / this.speed);
|
||||
if (this.speed) {
|
||||
cancel(this.rafId);
|
||||
this.rafId = raf(this.animate);
|
||||
} else {
|
||||
this.$emit('input', this.endRate);
|
||||
}
|
||||
},
|
||||
|
||||
animate() {
|
||||
const now = Date.now();
|
||||
const progress = Math.min((now - this.startTime) / this.duration, 1);
|
||||
const rate = progress * (this.endRate - this.startRate) + this.startRate;
|
||||
this.$emit('input', this.format(parseFloat(rate.toFixed(1))));
|
||||
if (this.increase ? rate < this.endRate : rate > this.endRate) {
|
||||
this.rafId = raf(this.animate);
|
||||
}
|
||||
},
|
||||
|
||||
format(rate) {
|
||||
return Math.min(Math.max(rate, 0), 100);
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
@ -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
|
||||
},
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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`,
|
||||
|
@ -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}件`,
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -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 });
|
||||
|
@ -13,6 +13,7 @@
|
||||
<li
|
||||
v-for="(option, index) in options"
|
||||
v-text="getOptionText(option)"
|
||||
class="van-ellipsis"
|
||||
:class="{
|
||||
'van-picker-column--disabled': isDisabled(option),
|
||||
'van-picker-column--selected': index === currentIndex
|
||||
|
@ -3,8 +3,8 @@
|
||||
<div class="van-picker__toolbar van-hairline--top-bottom" v-if="showToolbar">
|
||||
<slot>
|
||||
<div class="van-picker__cancel" @click="emit('cancel')">{{ cancelButtonText || $t('cancel') }}</div>
|
||||
<div class="van-picker__title van-ellipsis" v-if="title" v-text="title" />
|
||||
<div class="van-picker__confirm" @click="emit('confirm')">{{ confirmButtonText || $t('confirm') }}</div>
|
||||
<div class="van-picker__title" v-if="title" v-text="title" />
|
||||
</slot>
|
||||
</div>
|
||||
<div class="van-picker__columns" @touchmove.prevent>
|
||||
|
@ -41,12 +41,6 @@ export default create({
|
||||
currentValue: false,
|
||||
currentTransition: transition
|
||||
};
|
||||
},
|
||||
|
||||
mounted() {
|
||||
if (this.value) {
|
||||
this.open();
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
@ -1,5 +1,12 @@
|
||||
<template>
|
||||
<popup v-model="show" v-if="!isSkuEmpty" position="bottom" lock-on-scroll prevent-scroll>
|
||||
<popup
|
||||
v-if="!isSkuEmpty"
|
||||
v-model="show"
|
||||
position="bottom"
|
||||
lock-on-scroll
|
||||
prevent-scroll
|
||||
:get-container="getContainer"
|
||||
>
|
||||
<div class="van-sku-container">
|
||||
<div class="van-sku-layout">
|
||||
<!-- sku-header -->
|
||||
@ -74,7 +81,7 @@
|
||||
<sku-messages
|
||||
ref="skuMessages"
|
||||
:goods-id="goodsId"
|
||||
:message-placeholder-map="messagePlaceholderMap"
|
||||
:message-config="messageConfig"
|
||||
:messages="sku.messages"
|
||||
/>
|
||||
</slot>
|
||||
@ -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,
|
||||
|
@ -4,7 +4,7 @@
|
||||
<img class="van-sku__goods-img" :src="goodsImg" >
|
||||
</div>
|
||||
<div class="van-sku-header__goods-info">
|
||||
<div class="van-sku__goods-name">{{ goods.title }}</div>
|
||||
<div class="van-sku__goods-name van-ellipsis">{{ goods.title }}</div>
|
||||
<div class="van-sku__goods-price"><span class="van-sku__price-symbol">¥</span><span class="van-sku__price-num">{{ price }}</span></div>
|
||||
<span class="van-sku__close-icon" @click="skuEventBus.$emit('sku:close')" />
|
||||
</div>
|
||||
|
122
packages/sku/components/SkuImgUploader.vue
Normal file
122
packages/sku/components/SkuImgUploader.vue
Normal file
@ -0,0 +1,122 @@
|
||||
<template>
|
||||
<div class="van-sku-img-uploader">
|
||||
<!-- 头部 -->
|
||||
<van-uploader
|
||||
:disabled="!canUpload"
|
||||
:before-read="beforeReadFile"
|
||||
:after-read="afterReadFile"
|
||||
accept="image/*">
|
||||
<div class="van-sku-img-uploader__header">
|
||||
<div v-if="paddingImg">{{ $t('uploading') }}</div>
|
||||
<template v-else>
|
||||
<van-icon name="photograph" />
|
||||
<span class="label">{{ getPhotoText(value) }}</span> {{ $t('or') }}
|
||||
<van-icon name="photo" />
|
||||
<span class="label">{{ getPicText(value) }}</span>
|
||||
</template>
|
||||
</div>
|
||||
</van-uploader>
|
||||
<!-- 图片列表区域 -->
|
||||
<div class="van-sku-img-uploader__imglist" v-if="paddingImg || imgList.length > 0">
|
||||
<!-- 已有的图片,图片右上角显示删除按钮 -->
|
||||
<div
|
||||
v-for="(img, index) in imgList"
|
||||
:key="index"
|
||||
class="van-sku-img-uploader__img-container">
|
||||
<span class="van-sku-img-uploader__delete-picture" @click="deleteImg(index)">
|
||||
<van-icon name="clear" />
|
||||
</span>
|
||||
<img :src="img">
|
||||
</div>
|
||||
<!-- 正在上传的图片,有上传等待提示 -->
|
||||
<div
|
||||
v-if="paddingImg"
|
||||
class="van-sku-img-uploader__img-container">
|
||||
<img :src="paddingImg">
|
||||
<van-loading class="van-sku-img-uploader__uploading" type="spinner" color="black" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Icon from '../../icon';
|
||||
import Uploader from '../../uploader';
|
||||
import Loading from '../../loading';
|
||||
import { create } from '../../utils';
|
||||
|
||||
export default create({
|
||||
name: 'van-sku-img-uploader',
|
||||
|
||||
components: {
|
||||
'van-uploader': Uploader,
|
||||
'van-icon': Icon,
|
||||
'van-loading': Loading
|
||||
},
|
||||
|
||||
props: {
|
||||
value: String,
|
||||
uploadImg: {
|
||||
type: Function,
|
||||
required: true
|
||||
},
|
||||
maxSize: {
|
||||
type: Number,
|
||||
default: 6
|
||||
}
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
// 正在上传的图片base 64
|
||||
paddingImg: ''
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
imgList() {
|
||||
return this.value && !this.paddingImg ? [this.value] : [];
|
||||
},
|
||||
canUpload() {
|
||||
// 判断当前是否允许上传图片
|
||||
if (this.paddingImg) return false;
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
getPhotoText(value) {
|
||||
return value ? this.$t('rephoto') : this.$t('photo');
|
||||
},
|
||||
|
||||
getPicText(value) {
|
||||
return value ? this.$t('reselect') : this.$t('select');
|
||||
},
|
||||
beforeReadFile(file) {
|
||||
// 拦截非图片的文件,以及大小限制
|
||||
if (file.size > this.maxSize * 1024 * 1024) {
|
||||
Toast(this.$t('maxSize', this.maxSize));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
afterReadFile(file) {
|
||||
// 上传文件
|
||||
this.paddingImg = file.content;
|
||||
this.uploadImg(file.file).then(img => {
|
||||
this.updateImg(img);
|
||||
this.$nextTick(() => {
|
||||
this.paddingImg = '';
|
||||
});
|
||||
}).catch(() => {
|
||||
this.paddingImg = '';
|
||||
});
|
||||
},
|
||||
deleteImg() {
|
||||
this.$emit('input', '');
|
||||
},
|
||||
updateImg(img) {
|
||||
this.$emit('input', img);
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
@ -1,14 +1,29 @@
|
||||
<template>
|
||||
<cell-group class="van-sku-messages">
|
||||
<field
|
||||
v-for="(message, index) in internalMessages"
|
||||
v-model="messageValues[index]"
|
||||
:key="`${goodsId}-${index}`"
|
||||
:required="message.required == '1'"
|
||||
:label="message.name"
|
||||
:placeholder="getPlaceholder(message)"
|
||||
:type="getType(message)"
|
||||
/>
|
||||
<template v-for="(message, index) in messages">
|
||||
<cell
|
||||
v-if="message.type === 'image'"
|
||||
class="van-sku-messages__image-cell"
|
||||
:label="$t('onePic')"
|
||||
:key="`${goodsId}-${index}`"
|
||||
:required="message.required == '1'"
|
||||
:title="message.name">
|
||||
<sku-img-uploader
|
||||
v-model="messageValues[index].value"
|
||||
:upload-img="messageConfig.uploadImg"
|
||||
:max-size="messageConfig.uploadMaxSize"
|
||||
/>
|
||||
</cell>
|
||||
<field
|
||||
v-else
|
||||
v-model="messageValues[index].value"
|
||||
:key="`${goodsId}-${index}`"
|
||||
:required="message.required == '1'"
|
||||
:label="message.name"
|
||||
:placeholder="getPlaceholder(message)"
|
||||
:type="getType(message)"
|
||||
/>
|
||||
</template>
|
||||
</cell-group>
|
||||
</template>
|
||||
|
||||
@ -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)) {
|
||||
|
@ -9,6 +9,7 @@
|
||||
:max="stepperLimit"
|
||||
:disable-input="disableStepperInput"
|
||||
@overlimit="onOverLimit"
|
||||
@change="onChange"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="!hideStock" class="van-sku__stock">{{ $t('remain', stock) }}</div>
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -8,7 +8,7 @@
|
||||
</div>
|
||||
<div class="van-steps__message">
|
||||
<div class="van-steps__title" v-text="title" />
|
||||
<div class="van-steps__desc" v-text="description" />
|
||||
<div class="van-steps__desc van-ellipsis" v-text="description" />
|
||||
</div>
|
||||
<slot name="message-extra" />
|
||||
</div>
|
||||
|
@ -22,7 +22,7 @@
|
||||
@click="onClick(index)"
|
||||
>
|
||||
<van-node v-if="tab.$slots.title" :node="tab.$slots.title" />
|
||||
<span v-else>{{ tab.title }}</span>
|
||||
<span class="van-ellipsis" v-else>{{ tab.title }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -3,7 +3,7 @@
|
||||
<div class="van-tree-select__nav">
|
||||
<div
|
||||
v-for="(item, index) in items"
|
||||
class="van-tree-select__nitem"
|
||||
class="van-tree-select__nitem van-ellipsis"
|
||||
:class="{ 'van-tree-select__nitem--active': mainActiveIndex === index }"
|
||||
@click="$emit('navclick', index)">
|
||||
{{ item.text }}
|
||||
@ -13,7 +13,7 @@
|
||||
<div
|
||||
v-for="item in subItems"
|
||||
:key="item.id"
|
||||
class="van-tree-select__item"
|
||||
class="van-tree-select__item van-ellipsis"
|
||||
:class="{ 'van-tree-select__item--active': activeId === item.id }"
|
||||
@click="onItemSelect(item)">
|
||||
{{ item.text }}
|
||||
|
@ -4,5 +4,6 @@
|
||||
|
||||
@import "./common/var.css";
|
||||
@import "./common/normalize.css";
|
||||
@import "./common/ellipsis.css";
|
||||
@import "./common/hairline.css";
|
||||
@import "./common/animation.css";
|
||||
|
32
packages/vant-css/src/circle.css
Normal file
32
packages/vant-css/src/circle.css
Normal file
@ -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%);
|
||||
}
|
||||
}
|
5
packages/vant-css/src/common/ellipsis.css
Normal file
5
packages/vant-css/src/common/ellipsis.css
Normal file
@ -0,0 +1,5 @@
|
||||
@import '../mixins/ellipsis.css';
|
||||
|
||||
.van-ellipsis {
|
||||
@mixin ellipsis;
|
||||
}
|
@ -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';
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
65
test/unit/specs/circle.spec.js
Normal file
65
test/unit/specs/circle.spec.js
Normal file
@ -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);
|
||||
});
|
||||
});
|
||||
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
@ -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');
|
||||
|
Loading…
x
Reference in New Issue
Block a user