From 309744286e41b58bc556d4c3b6eb23a9d5b2087e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=98=89=E6=B6=B5?= Date: Thu, 21 Sep 2017 16:26:10 +0800 Subject: [PATCH 1/3] Cell: add extra slot --- packages/cell/index.vue | 1 + packages/vant-css/src/cell.css | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/packages/cell/index.vue b/packages/cell/index.vue index aa50d3020..0f43adcef 100644 --- a/packages/cell/index.vue +++ b/packages/cell/index.vue @@ -27,6 +27,7 @@ + diff --git a/packages/vant-css/src/cell.css b/packages/vant-css/src/cell.css index 2ceddb55d..8f3276228 100644 --- a/packages/vant-css/src/cell.css +++ b/packages/vant-css/src/cell.css @@ -25,9 +25,14 @@ .van-icon { margin-right: 5px; + vertical-align: middle; } } + &__text { + vertical-align: middle; + } + &__label { display: block; font-size: 12px; From 522655fdd84eaf0fa19d3d5894c4a5729d234f81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=98=89=E6=B6=B5?= Date: Thu, 21 Sep 2017 16:26:40 +0800 Subject: [PATCH 2/3] add AddressList component --- docs/examples-docs/address-list.md | 122 +++++++++++++++++++++++++ docs/examples-docs/notice-bar.md | 2 +- docs/src/doc.config.js | 4 + docs/src/examples.js | 4 + docs/src/index.js | 4 + packages/address-list/index.vue | 48 ++++++++++ packages/index.js | 3 + packages/notice-bar/index.vue | 4 +- packages/vant-css/src/address-list.css | 69 ++++++++++++++ packages/vant-css/src/base.css | 2 +- packages/vant-css/src/checkbox.css | 1 + packages/vant-css/src/index.css | 3 +- packages/vant-css/src/notice-bar.css | 1 - test/unit/specs/address-list.spec.js | 80 ++++++++++++++++ 14 files changed, 341 insertions(+), 6 deletions(-) create mode 100644 docs/examples-docs/address-list.md create mode 100644 packages/address-list/index.vue create mode 100644 packages/vant-css/src/address-list.css create mode 100644 test/unit/specs/address-list.spec.js diff --git a/docs/examples-docs/address-list.md b/docs/examples-docs/address-list.md new file mode 100644 index 000000000..419621805 --- /dev/null +++ b/docs/examples-docs/address-list.md @@ -0,0 +1,122 @@ + + +## AddressList 地址列表 + +### 使用指南 +``` javascript +import { AddressList } from 'vant'; + +Vue.component(AddressList.name, AddressList); +``` + +### 代码演示 + +#### 基础用法 + +:::demo 基础用法 +```html + +``` + +```javascript +export default { + data() { + return { + chosenAddressId: '1', + list: [ + { + id: '1', + name: '张三', + tel: '13000000000', + address: '浙江省杭州市西湖区文三路 138 号东方通信大厦 7 楼 501 室' + }, + { + id: '2', + name: '李四', + tel: '1310000000', + address: '浙江省杭州市拱墅区莫干山路 50 号' + } + ] + } + }, + + methods: { + onAdd() { + Toast('新增收货地址'); + }, + onEdit(item, index) { + Toast('编辑收货地址:' + index); + } + } +} +``` +::: + +### API + +| 参数 | 说明 | 类型 | 默认值 | 可选值 | +|-----------|-----------|-----------|-------------|-------------| +| v-model | 当前选中地址的 id | String | - | - | +| list | 地址列表 | Array | `[]` | - | +| addButtonText | 底部按钮文字 | String | `新增收货地址` | - | + +### Event + +| 事件名 | 说明 | 参数 | +|-----------|-----------|-----------| +| add | 点击新增按钮时触发 | - | +| edit | 点击编辑按钮时触发 | item: 当前地址对象,index: 索引 | +| change | 切换选中的地址时触发 | item: 当前地址对象,index: 索引 | + +### 数据格式 +#### 地址列表字段说明 +| key | 说明 | 类型 | +|-----------|-----------|-----------| +| id | 每条地址的唯一标识 | `String | Number` | +| name | 收货人姓名 | `String` | +| tel | 收货人手机号 | `String` | +| address | 收货地址 | `String` | diff --git a/docs/examples-docs/notice-bar.md b/docs/examples-docs/notice-bar.md index 7da1faa12..61933d463 100644 --- a/docs/examples-docs/notice-bar.md +++ b/docs/examples-docs/notice-bar.md @@ -21,7 +21,7 @@ Vue.component(NoticeBar.name, NoticeBar); :::demo 基础用法 ```html - + ``` ::: diff --git a/docs/src/doc.config.js b/docs/src/doc.config.js index 7ab9edcd7..619899742 100644 --- a/docs/src/doc.config.js +++ b/docs/src/doc.config.js @@ -214,6 +214,10 @@ module.exports = { { "groupName": "业务组件", "list": [ + { + "path": "/address-list", + "title": "AddressList 地址列表" + }, { "path": "/area", "title": "Area 省市区选择" diff --git a/docs/src/examples.js b/docs/src/examples.js index 674f838a2..50a74e6e4 100644 --- a/docs/src/examples.js +++ b/docs/src/examples.js @@ -36,6 +36,10 @@ router.afterEach(() => { window.vueRouter = router; +if (process.env.NODE_ENV !== 'production') { + Vue.config.productionTip = false; +} + new Vue({ // eslint-disable-line render: h => h(App), router diff --git a/docs/src/index.js b/docs/src/index.js index 6c6b36dd6..2133b5ed0 100644 --- a/docs/src/index.js +++ b/docs/src/index.js @@ -35,6 +35,10 @@ router.afterEach(() => { window.vueRouter = router; +if (process.env.NODE_ENV !== 'production') { + Vue.config.productionTip = false; +} + new Vue({ // eslint-disable-line render: h => h(App), router diff --git a/packages/address-list/index.vue b/packages/address-list/index.vue new file mode 100644 index 000000000..9088f2489 --- /dev/null +++ b/packages/address-list/index.vue @@ -0,0 +1,48 @@ + + + diff --git a/packages/index.js b/packages/index.js index 05c34ce75..de34c9216 100644 --- a/packages/index.js +++ b/packages/index.js @@ -1,4 +1,5 @@ import Actionsheet from './actionsheet'; +import AddressList from './address-list'; import Area from './area'; import Badge from './badge'; import BadgeGroup from './badge-group'; @@ -55,6 +56,7 @@ import Waterfall from './waterfall'; const version = '0.9.6'; const components = [ Actionsheet, + AddressList, Area, Badge, BadgeGroup, @@ -121,6 +123,7 @@ export { install, version, Actionsheet, + AddressList, Area, Badge, BadgeGroup, diff --git a/packages/notice-bar/index.vue b/packages/notice-bar/index.vue index 4060dccc6..3513e55ba 100644 --- a/packages/notice-bar/index.vue +++ b/packages/notice-bar/index.vue @@ -57,10 +57,10 @@ export default { }, contentStyle() { return { - left: -this.offsetWidth + 'px', + transform: `translate3d(${-this.offsetWidth}px, 0, 0)`, transitionDelay: this.delay + 's', transitionDuration: this.duration + 's', - transitionProperty: this.diableTransition ? 'none' : 'left' + transitionProperty: this.diableTransition ? 'none' : 'all' }; } }, diff --git a/packages/vant-css/src/address-list.css b/packages/vant-css/src/address-list.css new file mode 100644 index 000000000..8354ed70d --- /dev/null +++ b/packages/vant-css/src/address-list.css @@ -0,0 +1,69 @@ +@import './common/var.css'; + +.van-address-list { + height: 100%; + + .van-cell__value { + color: $text-color; + padding-right: 34px; + position: relative; + } + + .van-radio__label { + margin-left: 32px; + } + + .van-radio__input { + top: 50%; + left: 0; + position: absolute; + transform: translate(0, -50%); + } + + .van-icon-checked { + color: $blue; + } + + &__group { + height: 100%; + overflow-y: scroll; + -webkit-overflow-scrolling: touch; + } + + &__name { + font-size: 14px; + line-height: 1.5; + } + + &__address { + font-size: 12px; + line-height: 1.5; + color: $gray-darker; + } + + &__edit { + position: absolute; + top: 50%; + right: 4px; + font-size: 24px; + color: $gray-dark; + transform: translate(0, -50%); + } + + &__add { + position: fixed; + left: 0; + bottom: 0; + z-index: 9999; + padding-left: 15px; + + .van-cell__text { + font-size: 16px; + } + + .van-icon-add { + color: $blue; + font-size: 20px; + } + } +} \ No newline at end of file diff --git a/packages/vant-css/src/base.css b/packages/vant-css/src/base.css index 5609574e8..940055af6 100644 --- a/packages/vant-css/src/base.css +++ b/packages/vant-css/src/base.css @@ -1,5 +1,5 @@ /** - * 基本样式入口 + * Entry of basic styles */ @import "./common/var.css"; diff --git a/packages/vant-css/src/checkbox.css b/packages/vant-css/src/checkbox.css index bf70b993a..3272dcfd2 100644 --- a/packages/vant-css/src/checkbox.css +++ b/packages/vant-css/src/checkbox.css @@ -8,6 +8,7 @@ $van-checkbox-size: 18px; .van-icon-success { color: #fff; display: block; + line-height: 1; font-size: 14px; text-align: center; pointer-events: none; diff --git a/packages/vant-css/src/index.css b/packages/vant-css/src/index.css index dc819043f..7a008ee7f 100644 --- a/packages/vant-css/src/index.css +++ b/packages/vant-css/src/index.css @@ -1,5 +1,5 @@ /** - * style entry + * Entry of all component's style */ /* base */ @@ -50,6 +50,7 @@ @import './tree-select.css'; /* business components */ +@import './address-list.css'; @import './coupon-list.css'; @import './goods-action.css'; @import './submit-bar.css'; diff --git a/packages/vant-css/src/notice-bar.css b/packages/vant-css/src/notice-bar.css index 97710ca64..8c9d62a70 100644 --- a/packages/vant-css/src/notice-bar.css +++ b/packages/vant-css/src/notice-bar.css @@ -30,7 +30,6 @@ &__content { position: absolute; white-space: nowrap; - transition-property: left; transition-timing-function: linear; } } diff --git a/test/unit/specs/address-list.spec.js b/test/unit/specs/address-list.spec.js new file mode 100644 index 000000000..8e2caa176 --- /dev/null +++ b/test/unit/specs/address-list.spec.js @@ -0,0 +1,80 @@ +import { mount } from 'avoriaz'; +import AddressList from 'packages/address-list'; + +const list = [ + { + id: '1', + name: '张三', + tel: '13000000000', + address: '浙江省杭州市西湖区文三路 138 号东方通信大厦 7 楼 501 室' + }, + { + id: '2', + name: '李四', + tel: '1310000000', + address: '浙江省杭州市拱墅区莫干山路 50 号' + }, + { + id: '3', + name: '王五', + tel: '1320000000', + address: '浙江省杭州市滨江区江南大道 15 号' + } +]; + +describe('AddressList', () => { + let wrapper; + afterEach(() => { + wrapper && wrapper.destroy(); + }); + + it('create a AddressList', () => { + wrapper = mount(AddressList); + expect(wrapper.hasClass('van-address-list')).to.be.true; + }); + + it('create a AddressList with three items', () => { + wrapper = mount(AddressList, { + propsData: { + value: '1', + list + } + }); + expect(wrapper.find('.van-address-list__group .van-cell').length).to.equal(3); + expect(wrapper.find('.van-icon-checked').length).to.equal(1); + }); + + it('listen to add & edit event', (done) => { + wrapper = mount(AddressList, { + propsData: { + list + } + }); + + const add = sinon.spy(); + wrapper.vm.$on('add', add); + wrapper.find('.van-address-list__add')[0].trigger('click'); + expect(add.calledOnce).to.be.true; + + wrapper.vm.$on('edit', (item, index) => { + expect(index).to.equal(0); + done(); + }); + wrapper.find('.van-address-list__edit')[0].trigger('click'); + }); + + it('listen to change event', (done) => { + wrapper = mount(AddressList, { + propsData: { + value: '1', + list + } + }); + + wrapper.vm.$on('change', (item, index) => { + expect(item.id).to.equal('3'); + done(); + }); + wrapper.find('.van-radio')[2].trigger('click'); + }); +}); From 72b013a44099b4544a64f04c6b5278c00ad3a5bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=98=89=E6=B6=B5?= Date: Fri, 22 Sep 2017 14:54:05 +0800 Subject: [PATCH 3/3] Field: support $attrs & $listeners --- docs/examples-docs/field.md | 139 ++++++++++++++------------------ docs/src/ExamplesApp.vue | 86 +------------------- docs/src/examples.js | 5 +- docs/src/index.js | 5 +- packages/field/index.vue | 118 ++++++++++----------------- packages/vant-css/src/field.css | 2 +- test/unit/specs/field.spec.js | 36 +++------ yarn.lock | 4 +- 8 files changed, 121 insertions(+), 274 deletions(-) diff --git a/docs/examples-docs/field.md b/docs/examples-docs/field.md index 377ab8bfd..4865b5746 100644 --- a/docs/examples-docs/field.md +++ b/docs/examples-docs/field.md @@ -1,8 +1,6 @@ @@ -10,17 +8,11 @@ export default { data() { return { - username: 'zhangmin' + value: '', + password: '', + username: 'zhangmin', + message: '' }; - }, - methods: { - onIconClick() { - this.username = ''; - }, - - onFieldBlur() { - console.log('blured'); - } } }; @@ -39,92 +31,78 @@ Vue.component(Field.name, Field); ### 代码演示 #### 基础用法 - -根据`type`属性显示不同的输入框。 +通过 v-model 绑定输入框的值 :::demo 基础用法 ```html + + + +``` +::: + +#### 自定义类型 +根据`type`属性定义不同类型的输入框 + +:::demo 自定义类型 +```html + placeholder="请输入用户名" + required + @click-icon="username = ''" + > + + - - ``` ::: -#### 无label的输入框 +#### 禁用输入框 -不传入`label`属性即可。 - -:::demo 无label的输入框 +:::demo 禁用输入框 ```html - + ``` ::: -#### 带border的输入框 +#### 错误提示 -传入一个`border`属性。 - -:::demo 带border的输入框 -```html -
- -
-``` -::: - -#### 禁用的输入框 - -传入`disabled`属性即可。 - -:::demo 禁用的输入框 +:::demo 错误提示 ```html - + ``` ::: -#### 错误的输入框 +#### 高度自适应 +对于 textarea,可以通过`autosize`属性设置高度自适应 -传入`error`属性即可。 - -:::demo 错误的输入框 +:::demo 高度自适应 ```html - - -``` -::: - - -#### Autosize的输入框(仅支持textarea) - -传入`autosize`属性, 且将`rows`设为1。 - -:::demo 错误的输入框 -```html - - + + ``` ::: @@ -133,23 +111,24 @@ Vue.component(Field.name, Field); | 参数 | 说明 | 类型 | 默认值 | 可选值 | |-----------|-----------|-----------|-------------|-------------| -| type | 输入框类型 | `String` | `text` | `text`, `number`, `email`, `url`, `tel`, `date`, `datetime`, `password`, `textarea` | -| placeholder | 输入框placeholder | `String` | | | -| value | 输入框的值 | `String` | | | -| label | 输入框标签 | `String` | | | -| disabled | 是否禁用输入框 | `Boolean` | `false` | | -| error | 输入框是否有错误 | `Boolean` | `false` | | -| readonly | 输入框是否只读 | `Boolean` | `false` | | -| maxlength | 输入框maxlength | `String`, `Number` | | | -| rows | textarea rows | `String`, `Number` | | | -| cols | textarea cols | `String`, `Number` | | | -| autosize | 自动调整高度(仅支持textarea) | `Boolean` | `false` | `true`, `false` | -| icon | 输入框尾部图标 | `String` | | icon中支持的类型 | -| onIconClick | 点击图标的回调函数 | `Function` | | | +| type | 输入框类型 | `String` | `text` | `number` `email`
`textarea` `tel`
`datetime` `date`
`password` `url` | +| value | 输入框的值 | `String` | - | - | +| label | 输入框标签 | `String` | - | - | +| disabled | 是否禁用输入框 | `Boolean` | `false` | - | +| error | 输入框是否有错误 | `Boolean` | `false` | - | +| autosize | 高度自适应(仅支持textarea) | `Boolean` | `false` | - | +| icon | 输入框尾部图标 | `String` | - | Icon 组件支持的类型 | + +### Event + +| 事件名称 | 说明 | 回调参数 | +|-----------|-----------|-----------| +| focus | 输入框聚焦时触发 | - | +| blur | 输入框失焦时触发 | - | +| click-icon | 点击尾部图标时触发 | - | ### Slot | name | 描述 | |-----------|-----------| | icon | 自定义icon | - diff --git a/docs/src/ExamplesApp.vue b/docs/src/ExamplesApp.vue index ae9d63a7a..201ab0f1e 100644 --- a/docs/src/ExamplesApp.vue +++ b/docs/src/ExamplesApp.vue @@ -1,93 +1,9 @@ - - diff --git a/docs/src/examples.js b/docs/src/examples.js index 50a74e6e4..edeb94775 100644 --- a/docs/src/examples.js +++ b/docs/src/examples.js @@ -42,5 +42,6 @@ if (process.env.NODE_ENV !== 'production') { new Vue({ // eslint-disable-line render: h => h(App), - router -}).$mount('#app-container'); + router, + el: '#app-container' +}); diff --git a/docs/src/index.js b/docs/src/index.js index 2133b5ed0..bb2d3d9e2 100644 --- a/docs/src/index.js +++ b/docs/src/index.js @@ -41,5 +41,6 @@ if (process.env.NODE_ENV !== 'production') { new Vue({ // eslint-disable-line render: h => h(App), - router -}).$mount('#app-container'); + router, + el: '#app-container' +}); diff --git a/packages/field/index.vue b/packages/field/index.vue index e7b5cb489..ba281a720 100644 --- a/packages/field/index.vue +++ b/packages/field/index.vue @@ -1,47 +1,43 @@