diff --git a/docs/examples-docs/express-way.md b/docs/examples-docs/express-way.md new file mode 100644 index 000000000..1aed0e45a --- /dev/null +++ b/docs/examples-docs/express-way.md @@ -0,0 +1,130 @@ +## ExpressWay 配送方式 + + + +### 使用指南 +``` javascript +import { ExpressWay } from 'vant'; + +Vue.component(ExpressWay.name, ExpressWay); +``` + +### 代码演示 + +#### 基础用法 + +:::demo 基础用法 +```html + + + + + + + +``` +::: + +#### 不可修改配送方式 + +:::demo 不可修改配送方式 +```html + + + +``` +::: + +### 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:对应的索引 | diff --git a/docs/src/doc.config.js b/docs/src/doc.config.js index 58c899777..364ce26be 100644 --- a/docs/src/doc.config.js +++ b/docs/src/doc.config.js @@ -185,6 +185,10 @@ module.exports = { { "groupName": "业务组件", "list": [ + { + "path": "/express-way", + "title": "ExpressWay 配送方式" + }, { "path": "/switch-cell", "title": "SwitchCell 开关单元格" diff --git a/packages/express-way/Option.vue b/packages/express-way/Option.vue new file mode 100644 index 000000000..c29521dfa --- /dev/null +++ b/packages/express-way/Option.vue @@ -0,0 +1,32 @@ + + + + + + {{ data.postage_title }} + {{ data.postage }} + + {{ data.postage_desc }} + {{ data.postage_warn_desc }} + + + + + diff --git a/packages/express-way/index.vue b/packages/express-way/index.vue new file mode 100644 index 000000000..ac6743579 --- /dev/null +++ b/packages/express-way/index.vue @@ -0,0 +1,100 @@ + + + + + + + + + {{ currentOption.postage }} + {{ currentOption.postage_title }} + + + + + diff --git a/packages/index.js b/packages/index.js index fcb708c38..ad330f79c 100644 --- a/packages/index.js +++ b/packages/index.js @@ -11,6 +11,7 @@ import CheckboxGroup from './checkbox-group'; import Col from './col'; import DatetimePicker from './datetime-picker'; import Dialog from './dialog'; +import ExpressWay from './express-way'; import Field from './field'; import Icon from './icon'; import ImagePreview from './image-preview'; @@ -53,6 +54,7 @@ const components = [ CheckboxGroup, Col, DatetimePicker, + ExpressWay, Field, Icon, Loading, @@ -107,6 +109,7 @@ export { Col, DatetimePicker, Dialog, + ExpressWay, Field, Icon, ImagePreview, diff --git a/packages/vant-css/src/express-way.css b/packages/vant-css/src/express-way.css new file mode 100644 index 000000000..a0507b435 --- /dev/null +++ b/packages/vant-css/src/express-way.css @@ -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; + } + } +} \ No newline at end of file diff --git a/packages/vant-css/src/index.css b/packages/vant-css/src/index.css index d897aacbd..04bb59827 100644 --- a/packages/vant-css/src/index.css +++ b/packages/vant-css/src/index.css @@ -32,3 +32,4 @@ @import './swipe.css'; @import './notice-bar.css'; @import './switch-cell.css'; +@import './express-way.css'; diff --git a/test/unit/specs/express-way.spec.js b/test/unit/specs/express-way.spec.js new file mode 100644 index 000000000..06185dddd --- /dev/null +++ b/test/unit/specs/express-way.spec.js @@ -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': '' + } + }); + }); +});
{{ data.postage_desc }}
{{ currentOption.postage }}
{{ currentOption.postage_title }}