mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-04-06 03:57:59 +08:00
commit
8e9151bf96
130
docs/examples-docs/express-way.md
Normal file
130
docs/examples-docs/express-way.md
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
## ExpressWay 配送方式
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { Toast, CellGroup } from 'packages/index';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
currentExpressType: 1,
|
||||||
|
expressList: [{
|
||||||
|
'postage': 10050,
|
||||||
|
'postage_desc': '由商家门店提供配送服务, 起送价 0.01 元',
|
||||||
|
'postage_title': '同城配送',
|
||||||
|
'express_type': 1
|
||||||
|
}, {
|
||||||
|
'postage': 0,
|
||||||
|
'postage_desc': '由商家选择合作快递为您服务',
|
||||||
|
'postage_title': '快递发货',
|
||||||
|
'express_type': 2,
|
||||||
|
'postage_warn_desc': '3天后发货'
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
onChange(item, index) {
|
||||||
|
Toast('配送方式更换为:' + item.postage_title);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
components: {
|
||||||
|
[CellGroup.name]: CellGroup
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
### 使用指南
|
||||||
|
``` javascript
|
||||||
|
import { ExpressWay } from 'vant';
|
||||||
|
|
||||||
|
Vue.component(ExpressWay.name, ExpressWay);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 代码演示
|
||||||
|
|
||||||
|
#### 基础用法
|
||||||
|
|
||||||
|
:::demo 基础用法
|
||||||
|
```html
|
||||||
|
<template>
|
||||||
|
<van-cell-group>
|
||||||
|
<van-express-way
|
||||||
|
v-model="currentExpressType"
|
||||||
|
:express-list="expressList"
|
||||||
|
@change="onChange"
|
||||||
|
/>
|
||||||
|
</van-cell-group>
|
||||||
|
</tempalte>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
currentExpressType: 1,
|
||||||
|
expressList: [{
|
||||||
|
'postage': 10050,
|
||||||
|
'postage_desc': '由商家门店提供配送服务, 起送价 0.01 元',
|
||||||
|
'postage_title': '同城配送',
|
||||||
|
'express_type': 1
|
||||||
|
}, {
|
||||||
|
'postage': 0,
|
||||||
|
'postage_desc': '由商家选择合作快递为您服务',
|
||||||
|
'postage_title': '快递发货',
|
||||||
|
'express_type': 2,
|
||||||
|
'postage_warn_desc': '3天后发货'
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
onChange(item, index) {
|
||||||
|
Toast('配送方式更换为:' + item.postage_title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
:::
|
||||||
|
|
||||||
|
#### 不可修改配送方式
|
||||||
|
|
||||||
|
:::demo 不可修改配送方式
|
||||||
|
```html
|
||||||
|
<van-cell-group>
|
||||||
|
<van-express-way
|
||||||
|
:value="-1"
|
||||||
|
:express-list="expressList"
|
||||||
|
:editable="false"
|
||||||
|
@change="onChange"
|
||||||
|
/>
|
||||||
|
</van-cell-group>
|
||||||
|
```
|
||||||
|
:::
|
||||||
|
|
||||||
|
### API
|
||||||
|
|
||||||
|
| 参数 | 说明 | 类型 | 默认值 | 必须 |
|
||||||
|
|-----------|-----------|-----------|-------------|-------------|
|
||||||
|
| v-model | 当前选择的配送类型 | `Number` | | 是 |
|
||||||
|
| expressList | 配送方式列表数据 | `Array` | | 是 |
|
||||||
|
| cellTitle | Cell 标题 | `String` | `配送方式` | 否 |
|
||||||
|
| actionsheetTitle | Actionsheet 标题 | `String` | `配送方式` | 否 |
|
||||||
|
| editable | 能否修改配送方式 | `Boolean` | `true` | 否 |
|
||||||
|
|
||||||
|
|
||||||
|
### 数据格式
|
||||||
|
#### expressList中的配送方式字段说明
|
||||||
|
| key | 说明 | 类型 |
|
||||||
|
|-----------|-----------|-----------|
|
||||||
|
| postage | 运费,以分为单位 | Number |
|
||||||
|
| postage_title | 配送方式 | String |
|
||||||
|
| postage_desc | 描述信息 | String |
|
||||||
|
| express_type | 配送类型 | Number |
|
||||||
|
| postage_warn_desc | 提示信息 | String |
|
||||||
|
|
||||||
|
### Event
|
||||||
|
|
||||||
|
| 事件名 | 说明 | 参数 |
|
||||||
|
|-----------|-----------|-----------|
|
||||||
|
| change | 修改配送方式时触发 | item: 对应的数据, index:对应的索引 |
|
@ -185,6 +185,10 @@ module.exports = {
|
|||||||
{
|
{
|
||||||
"groupName": "业务组件",
|
"groupName": "业务组件",
|
||||||
"list": [
|
"list": [
|
||||||
|
{
|
||||||
|
"path": "/express-way",
|
||||||
|
"title": "ExpressWay 配送方式"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"path": "/switch-cell",
|
"path": "/switch-cell",
|
||||||
"title": "SwitchCell 开关单元格"
|
"title": "SwitchCell 开关单元格"
|
||||||
|
32
packages/express-way/Option.vue
Normal file
32
packages/express-way/Option.vue
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<template>
|
||||||
|
<van-cell class="van-express-way-option" @click="$emit('change')">
|
||||||
|
<van-radio :name="data.express_type" :value="currentExpressWay" />
|
||||||
|
<div class="van-express-way-option__content">
|
||||||
|
<h3 class="van-express-way-option__title">
|
||||||
|
<span>{{ data.postage_title }}</span>
|
||||||
|
<span>{{ data.postage }}</span>
|
||||||
|
</h3>
|
||||||
|
<p>{{ data.postage_desc }}</p>
|
||||||
|
<div class="van-express-way-option__warn" v-if="data.postage_warn_desc">{{ data.postage_warn_desc }}</div>
|
||||||
|
</div>
|
||||||
|
</van-cell>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Cell from '../cell';
|
||||||
|
import Radio from '../radio';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'van-express-way-option',
|
||||||
|
|
||||||
|
components: {
|
||||||
|
[Cell.name]: Cell,
|
||||||
|
[Radio.name]: Radio
|
||||||
|
},
|
||||||
|
|
||||||
|
props: {
|
||||||
|
data: Object,
|
||||||
|
currentExpressWay: Number
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
100
packages/express-way/index.vue
Normal file
100
packages/express-way/index.vue
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
<template>
|
||||||
|
<van-cell class="van-express-way">
|
||||||
|
<van-actionsheet v-if="computedEditable" v-model="showActionsheet" :title="actionsheetTitle" >
|
||||||
|
<van-cell-group>
|
||||||
|
<van-express-way-option
|
||||||
|
v-for="(item, index) in computedList"
|
||||||
|
:key="item.express_type"
|
||||||
|
:data="item"
|
||||||
|
:currentExpressWay="value"
|
||||||
|
@change="onSelectExpressWay(item, index)"
|
||||||
|
/>
|
||||||
|
</van-cell-group>
|
||||||
|
</van-actionsheet>
|
||||||
|
<van-cell :title="cellTitle" :isLink="computedEditable" @click="showActionsheet = computedEditable">
|
||||||
|
<p class="van-express-way__fee">{{ currentOption.postage }}</p>
|
||||||
|
<p class="van-express-way__type">{{ currentOption.postage_title }}</p>
|
||||||
|
</van-cell>
|
||||||
|
</van-cell>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Option from './Option.vue';
|
||||||
|
import Actionsheet from '../actionsheet';
|
||||||
|
import Cell from '../cell';
|
||||||
|
import CellGroup from '../cell-group';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'van-express-way',
|
||||||
|
|
||||||
|
components: {
|
||||||
|
[Option.name]: Option,
|
||||||
|
[Cell.name]: Cell,
|
||||||
|
[CellGroup.name]: CellGroup,
|
||||||
|
[Actionsheet.name]: Actionsheet
|
||||||
|
},
|
||||||
|
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: Number,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
expressList: {
|
||||||
|
type: Array,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
cellTitle: {
|
||||||
|
type: String,
|
||||||
|
default: '配送方式'
|
||||||
|
},
|
||||||
|
actionsheetTitle: {
|
||||||
|
type: String,
|
||||||
|
default: '配送方式'
|
||||||
|
},
|
||||||
|
editable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
showActionsheet: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
computedList() {
|
||||||
|
return this.expressList.map(item => ({
|
||||||
|
...item,
|
||||||
|
postage: this.calcPostage(item.postage)
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
computedEditable() {
|
||||||
|
return this.expressList && this.expressList.length >= 2 && this.editable;
|
||||||
|
},
|
||||||
|
|
||||||
|
currentOption() {
|
||||||
|
for (let i = 0; i < this.computedList.length; i++) {
|
||||||
|
if (this.computedList[i].express_type === this.value) {
|
||||||
|
return this.computedList[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
onSelectExpressWay(item, index) {
|
||||||
|
this.showActionsheet = false;
|
||||||
|
this.$emit('input', item.express_type);
|
||||||
|
this.$emit('change', item, index);
|
||||||
|
},
|
||||||
|
|
||||||
|
calcPostage(postage) {
|
||||||
|
return postage === 0 ? '免运费' : '¥' + (postage / 100).toFixed(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
@ -11,6 +11,7 @@ import CheckboxGroup from './checkbox-group';
|
|||||||
import Col from './col';
|
import Col from './col';
|
||||||
import DatetimePicker from './datetime-picker';
|
import DatetimePicker from './datetime-picker';
|
||||||
import Dialog from './dialog';
|
import Dialog from './dialog';
|
||||||
|
import ExpressWay from './express-way';
|
||||||
import Field from './field';
|
import Field from './field';
|
||||||
import Icon from './icon';
|
import Icon from './icon';
|
||||||
import ImagePreview from './image-preview';
|
import ImagePreview from './image-preview';
|
||||||
@ -53,6 +54,7 @@ const components = [
|
|||||||
CheckboxGroup,
|
CheckboxGroup,
|
||||||
Col,
|
Col,
|
||||||
DatetimePicker,
|
DatetimePicker,
|
||||||
|
ExpressWay,
|
||||||
Field,
|
Field,
|
||||||
Icon,
|
Icon,
|
||||||
Loading,
|
Loading,
|
||||||
@ -107,6 +109,7 @@ export {
|
|||||||
Col,
|
Col,
|
||||||
DatetimePicker,
|
DatetimePicker,
|
||||||
Dialog,
|
Dialog,
|
||||||
|
ExpressWay,
|
||||||
Field,
|
Field,
|
||||||
Icon,
|
Icon,
|
||||||
ImagePreview,
|
ImagePreview,
|
||||||
|
58
packages/vant-css/src/express-way.css
Normal file
58
packages/vant-css/src/express-way.css
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
.van-express-way {
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
&__fee,
|
||||||
|
&__type {
|
||||||
|
color: #666;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__fee {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__type {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.van-actionsheet__content {
|
||||||
|
max-height: 290px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-option {
|
||||||
|
position: relative;
|
||||||
|
padding: 14px 15px 14px 0;
|
||||||
|
|
||||||
|
.van-radio {
|
||||||
|
top: 50%;
|
||||||
|
left: 0;
|
||||||
|
margin-top: -11px;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__content {
|
||||||
|
padding-left: 30px;
|
||||||
|
|
||||||
|
p {
|
||||||
|
color: #999;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
span {
|
||||||
|
vertical-align: middle;
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__warn {
|
||||||
|
color: #f09000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -32,3 +32,4 @@
|
|||||||
@import './swipe.css';
|
@import './swipe.css';
|
||||||
@import './notice-bar.css';
|
@import './notice-bar.css';
|
||||||
@import './switch-cell.css';
|
@import './switch-cell.css';
|
||||||
|
@import './express-way.css';
|
||||||
|
201
test/unit/specs/express-way.spec.js
Normal file
201
test/unit/specs/express-way.spec.js
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
import ExpressWay from 'packages/express-way';
|
||||||
|
import { mount } from 'avoriaz';
|
||||||
|
import { DOMChecker } from '../utils';
|
||||||
|
|
||||||
|
const mockData = [{
|
||||||
|
'postage': 10050,
|
||||||
|
'postage_desc': '由商家门店提供配送服务, 起送价 0.01 元',
|
||||||
|
'postage_title': '同城配送',
|
||||||
|
'express_type': 1
|
||||||
|
}, {
|
||||||
|
'postage': 0,
|
||||||
|
'postage_desc': '由商家选择合作快递为您服务',
|
||||||
|
'postage_title': '快递发货',
|
||||||
|
'express_type': 2,
|
||||||
|
'postage_warn_desc': '3天后发货'
|
||||||
|
}];
|
||||||
|
|
||||||
|
describe('ExpressWay', () => {
|
||||||
|
let wrapper;
|
||||||
|
afterEach(() => {
|
||||||
|
wrapper && wrapper.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('default', () => {
|
||||||
|
wrapper = mount(ExpressWay, {
|
||||||
|
attachToDocument: true,
|
||||||
|
propsData: {
|
||||||
|
value: 1,
|
||||||
|
expressList: mockData
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
DOMChecker(wrapper, {
|
||||||
|
text: {
|
||||||
|
'.van-cell__text': '配送方式',
|
||||||
|
'.van-express-way__fee': '¥100.50',
|
||||||
|
'.van-express-way__type': mockData[0].postage_title,
|
||||||
|
'.van-actionsheet__header h3': '配送方式',
|
||||||
|
'.van-express-way-option__title span': mockData[0].postage_title,
|
||||||
|
'.van-express-way-option__content p': mockData[0].postage_desc
|
||||||
|
},
|
||||||
|
count: {
|
||||||
|
'.van-icon-arrow': 1
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
'.van-actionsheet': {
|
||||||
|
display: 'none'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('show actionsheet', (done) => {
|
||||||
|
wrapper = mount(ExpressWay, {
|
||||||
|
attachToDocument: true,
|
||||||
|
propsData: {
|
||||||
|
value: 1,
|
||||||
|
expressList: mockData
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 点击后弹出 actionsheet
|
||||||
|
const cells = wrapper.find('.van-cell');
|
||||||
|
cells[cells.length - 1].trigger('click');
|
||||||
|
setTimeout(() => {
|
||||||
|
expect(wrapper.find('.van-actionsheet')[0].hasStyle('display', 'none')).to.equal(false);
|
||||||
|
done();
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('change express way', (done) => {
|
||||||
|
wrapper = mount(ExpressWay, {
|
||||||
|
attachToDocument: true,
|
||||||
|
propsData: {
|
||||||
|
value: 1,
|
||||||
|
expressList: mockData
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
wrapper.vm.$on('input', val => {
|
||||||
|
wrapper.vm.value = val;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 点击后弹出 actionsheet
|
||||||
|
const cells = wrapper.find('.van-cell');
|
||||||
|
cells[cells.length - 1].trigger('click');
|
||||||
|
|
||||||
|
// 监听 change 事件
|
||||||
|
const submitSpyFunc = sinon.spy();
|
||||||
|
wrapper.vm.$on('change', submitSpyFunc);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
expect(wrapper.find('.van-actionsheet')[0].hasStyle('display', 'none')).to.equal(false);
|
||||||
|
|
||||||
|
const secondOption = wrapper.find('.van-express-way-option')[1];
|
||||||
|
secondOption.trigger('click');
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
expect(wrapper.find('.van-actionsheet')[0].hasStyle('display', 'none')).to.equal(true);
|
||||||
|
|
||||||
|
DOMChecker(wrapper, {
|
||||||
|
text: {
|
||||||
|
'.van-express-way__fee': '免运费',
|
||||||
|
'.van-express-way__type': mockData[1].postage_title
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 修改后触发 change 事件
|
||||||
|
expect(submitSpyFunc.calledOnce).to.be.true;
|
||||||
|
done();
|
||||||
|
}, 500);
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('cellTitle prop', () => {
|
||||||
|
wrapper = mount(ExpressWay, {
|
||||||
|
attachToDocument: true,
|
||||||
|
propsData: {
|
||||||
|
value: 1,
|
||||||
|
cellTitle: '测试标题',
|
||||||
|
expressList: mockData
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
DOMChecker(wrapper, {
|
||||||
|
text: {
|
||||||
|
'.van-cell__text': '测试标题'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('actionsheetTitle prop', () => {
|
||||||
|
wrapper = mount(ExpressWay, {
|
||||||
|
attachToDocument: true,
|
||||||
|
propsData: {
|
||||||
|
value: 1,
|
||||||
|
actionsheetTitle: '测试标题',
|
||||||
|
expressList: mockData
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
DOMChecker(wrapper, {
|
||||||
|
text: {
|
||||||
|
'.van-actionsheet__header h3': '测试标题'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('set editable false ', () => {
|
||||||
|
wrapper = mount(ExpressWay, {
|
||||||
|
attachToDocument: true,
|
||||||
|
propsData: {
|
||||||
|
value: 1,
|
||||||
|
editable: false,
|
||||||
|
expressList: mockData
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
DOMChecker(wrapper, {
|
||||||
|
count: {
|
||||||
|
'.van-icon-arrow': 0,
|
||||||
|
'.van-actionsheet': 0
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('not editable when only one option', () => {
|
||||||
|
wrapper = mount(ExpressWay, {
|
||||||
|
attachToDocument: true,
|
||||||
|
propsData: {
|
||||||
|
value: 1,
|
||||||
|
editable: true,
|
||||||
|
expressList: mockData.slice(0, 1)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
DOMChecker(wrapper, {
|
||||||
|
count: {
|
||||||
|
'.van-icon-arrow': 0,
|
||||||
|
'.van-actionsheet': 0
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('unexist express type', () => {
|
||||||
|
wrapper = mount(ExpressWay, {
|
||||||
|
attachToDocument: true,
|
||||||
|
propsData: {
|
||||||
|
value: -1,
|
||||||
|
expressList: mockData
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
DOMChecker(wrapper, {
|
||||||
|
text: {
|
||||||
|
'.van-express-way__fee': '',
|
||||||
|
'.van-express-way__type': ''
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user