Merge remote-tracking branch 'main/dev' into dev

This commit is contained in:
陈嘉涵 2017-09-07 11:16:25 +08:00
commit 594b0e5bb1
7 changed files with 7630 additions and 0 deletions

133
docs/examples-docs/area.md Normal file
View File

@ -0,0 +1,133 @@
<script>
import AreaList from '../mock/area.json';
export default {
data() {
return {
areaList: AreaList
}
}
};
</script>
## Area 省市县选择组件
### 使用指南
``` javascript
import { Area } from 'vant';
Vue.component(Area.name, Area);
```
### 代码演示
#### 基础用法
要初始化一个`Area`组件,你需要传入一个`areaList`属性,`areaList`数据格式具体可看下面数据格式章节。
:::demo 基础用法
```html
<van-area :area-list="areaList"></van-area>
<script>
import AreaList from '../mock/area.json';
export default {
data() {
return {
areaList: AreaList
}
}
};
</script>
```
:::
#### 选中省市县
如果想选中某个省市县,需要传入一个`value`属性,绑定对应的省市县`code`
:::demo 选中省市县
```html
<van-area :area-list="areaList" value="110101"></van-area>
```
:::
#### 配置显示列
可以通过`columnsNum`属性配置省市县显示的列数,默认情况下会显示省市县,当你设置为`2`,则只会显示省市选择。
:::demo 配置显示列
```html
<van-area :area-list="areaList" :columns-num="2"></van-area>
```
:::
### API
| 参数 | 说明 | 类型 | 默认值 | 可选值 |
|-----------|-----------|-----------|-------------|-------------|
| value | 当前选中的省市区`code` | `String` | - | |
| areaList | 省市县数据,必须与`province_list``city_list``county_list`为key | `Object` | | |
| columnsNum | 省市县显示列数3-省市县2-省市1-省 | `String`,`Number` | 3 | |
### Event
| 事件名称 | 说明 | 回调参数 |
|-----------|-----------|-----------|
| confirm | 点击右上方完成按钮 | 一个数组参数,具体格式看下方数据格式章节 |
| cancel | 点击取消按钮时 | - |
### 数据格式
#### 省市县列表数据格式
整体是一个Object包含 `province_list`, `city_list`, `county_list` 三个key。
每项以省市区编码作为key省市区名字作为value。编码为6位数字前两位代表省份中间两位代表城市后两位代表区县以0补足6位。如北京编码为 `11`以零补足6位`110000`
`AreaList`具体格式如下:
```javascript
{
province_list: {
110000: '北京市',
120000: '天津市'
},
city_list: {
110100: '北京市',
110200: '县',
120100: '天津市',
120200: '县'
},
county_list: {
110101: '东城区',
110102: '西城区',
110105: '朝阳区',
110106: '丰台区'
120101: '和平区',
120102: '河东区',
120103: '河西区',
120104: '南开区',
120105: '河北区',
// ....
}
}
```
#### 点击完成时返回的数据格式
返回的数据整体为一个数组,数组内包含 `columnsNum` 个数据, 每个数据对应一列选项中被选中的数据。
`code` 代表被选中的地区编码, `name` 代表被选中的地区名称
```javascript
[{
code: '110000',
name: '北京市'
}, {
code: '110100',
name: '北京市'
},{
code: '110101',
name: '东城区'
}]
```

3607
docs/mock/area.json Normal file

File diff suppressed because it is too large Load Diff

View File

@ -220,6 +220,10 @@ module.exports = {
{
"path": "/switch-cell",
"title": "SwitchCell 开关单元格"
},
{
"path": "/area",
"title": "Area 省市区选择"
}
]
}

159
packages/area/index.vue Normal file
View File

@ -0,0 +1,159 @@
<template>
<div class="van-area">
<van-picker ref="picker" :columns="areaColumns" value-key="name" show-toolbar @change="handleAreaChange" @confirm="handleAreaConfirm" @cancel="handleAreaCancel"></van-picker>
</div>
</template>
<script>
import Picker from '../picker';
const DEFAULT_PROVINCE = {
code: '-1',
name: '选择省份'
};
const DEFAULT_CITY = {
code: '-1',
name: '选择城市'
};
const DEFAULT_COUNTY = {
code: '-1',
name: '选择地区'
};
const PROVINCE_TYPE = 'provice';
const CITY_TYPE = 'city';
const COUNTY_TYPE = 'county';
export default {
name: 'van-area',
components: {
[Picker.name]: Picker
},
props: {
value: {},
areaList: Object,
/**
* 省市县显示列数3-省市县2-省市1-
*/
columnsNum: {
type: [String, Number],
default: 3
}
},
computed: {
areaColumns() {
const areaList = this.areaList;
if (!areaList || (areaList && typeof areaList.province_list !== 'object')) return [];
const columns = [];
const curValue = this.value || '';
columns.push({
values: [DEFAULT_PROVINCE].concat(this.computedAreaList(PROVINCE_TYPE)),
className: 'van-area__province',
defaultIndex: this.getAreaIndex(PROVINCE_TYPE, curValue)
});
const columnsNum = this.columnsNum;
if (+columnsNum > 1) {
columns.push({
values: [DEFAULT_CITY].concat(this.computedAreaList(CITY_TYPE, curValue.slice(0, 2))),
className: 'van-area__city',
defaultIndex: this.getAreaIndex(CITY_TYPE, curValue)
});
}
if (+columnsNum > 2) {
columns.push({
values: [DEFAULT_COUNTY].concat(this.computedAreaList(COUNTY_TYPE, curValue.slice(0, 4))),
className: 'van-area__county',
defaultIndex: this.getAreaIndex(COUNTY_TYPE, curValue)
});
}
return columns;
}
},
methods: {
/**
* 根据省市县类型和对应的`code`获取对应列表
*
* @param {string} type 省市县类型
* @param {string} code 对应code
*/
computedAreaList(type, code) {
const result = [];
const curAreaList = this.areaList;
const areaList = type === PROVINCE_TYPE
? curAreaList.province_list
: (type === CITY_TYPE ? curAreaList.city_list : curAreaList.county_list);
for (const i in areaList) {
//
//
if (type === PROVINCE_TYPE || (code && i.slice(0, code.length) === code)) {
result.push({
code: i,
name: areaList[i]
});
}
}
return result;
},
/**
* 获取对应省市县在列表中的索引
*/
getAreaIndex(type, code) {
const compareNum = type === PROVINCE_TYPE
? 2
: (type === CITY_TYPE ? 4 : 6);
const areaList = this.computedAreaList(type, code.slice(0, compareNum - 2));
for (let i = 0; i < areaList.length; i++) {
if (+areaList[i].code.slice(0, compareNum) === +code.slice(0, compareNum)) {
return i + 1;
}
}
return 0;
},
handleAreaChange(picker, values, index) {
const code = values[index].code;
//
if (index === 0) {
picker.setColumnValues(
1,
[DEFAULT_CITY].concat(this.computedAreaList(CITY_TYPE, code.slice(0, 2)))
);
picker.setColumnValues(
2,
[DEFAULT_COUNTY].concat(this.computedAreaList(COUNTY_TYPE, code.slice(0, 4)))
);
} else if (index === 1) {
picker.setColumnValues(
2,
[DEFAULT_COUNTY].concat(this.computedAreaList(COUNTY_TYPE, code.slice(0, 4)))
);
}
},
handleAreaConfirm(values) {
this.$emit('confirm', values);
},
handleAreaCancel() {
this.$emit('cancel');
}
}
};
</script>

View File

@ -1,4 +1,5 @@
import Actionsheet from './actionsheet';
import Area from './area';
import Badge from './badge';
import BadgeGroup from './badge-group';
import Button from './button';
@ -53,6 +54,7 @@ import Waterfall from './waterfall';
const version = '0.8.9';
const components = [
Actionsheet,
Area,
Badge,
BadgeGroup,
Button,
@ -117,6 +119,7 @@ export {
install,
version,
Actionsheet,
Area,
Badge,
BadgeGroup,
Button,

3607
test/unit/mock/area.json Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,117 @@
import Area from 'packages/area';
import { mount } from 'avoriaz';
import AreaList from '../mock/area.json';
describe('Area', () => {
let wrapper;
afterEach(() => {
wrapper && wrapper.destroy();
});
it('create an area', () => {
wrapper = mount(Area, {
propsData: {
areaList: AreaList
}
});
expect(wrapper.hasClass('van-area')).to.be.true;
});
it('create an area with default value', (done) => {
wrapper = mount(Area, {
propsData: {
areaList: AreaList,
value: '110101'
}
});
expect(wrapper.hasClass('van-area')).to.be.true;
const confirmBtn = wrapper.find('.van-picker__confirm')[0];
const eventStub = sinon.stub(wrapper.vm, '$emit');
confirmBtn.trigger('click');
wrapper.vm.$nextTick(() => {
expect(eventStub.calledOnce).to.be.true;
expect(eventStub.calledWith('confirm'));
expect(wrapper.vm.$refs.picker.getColumnValue(2).code).to.equal('110101');
done();
});
});
it('create an area and set value', (done) => {
wrapper = mount(Area, {
propsData: {
areaList: AreaList,
value: '110101'
}
});
expect(wrapper.hasClass('van-area')).to.be.true;
expect(wrapper.vm.$refs.picker.getColumnValue(2).code).to.equal('110101');
wrapper.setProps({
value: '110102'
});
wrapper.vm.$nextTick(() => {
expect(wrapper.vm.$refs.picker.getColumnValue(2).code).to.equal('110102');
done();
});
});
it('create an area with invalid areaList', () => {
wrapper = mount(Area, {
propsData: {
areaList: null
}
});
expect(wrapper.hasClass('van-area')).to.be.true;
expect(wrapper.vm.areaColumns.length).to.equal(0);
});
it('create an area with columnsNum equal 2', () => {
wrapper = mount(Area, {
propsData: {
areaList: AreaList,
columnsNum: 2
}
});
expect(wrapper.hasClass('van-area')).to.be.true;
expect(wrapper.vm.areaColumns.length).to.equal(2);
});
it('create an area with columnsNum equal 1', () => {
wrapper = mount(Area, {
propsData: {
areaList: AreaList,
columnsNum: 1
}
});
expect(wrapper.hasClass('van-area')).to.be.true;
expect(wrapper.vm.areaColumns.length).to.equal(1);
});
it('create an area and click cancel', (done) => {
wrapper = mount(Area, {
propsData: {
areaList: AreaList
}
});
expect(wrapper.hasClass('van-area')).to.be.true;
const cancelBtn = wrapper.find('.van-picker__cancel')[0];
const eventStub = sinon.stub(wrapper.vm, '$emit');
cancelBtn.trigger('click');
wrapper.vm.$nextTick(() => {
expect(eventStub.calledOnce).to.be.true;
expect(eventStub.calledWith('cancel'));
done();
});
});
});