mirror of
https://gitee.com/vant-contrib/vant-weapp.git
synced 2025-04-06 03:58:05 +08:00
[new feature] Area: 增加省市区选择组件 (#591)
This commit is contained in:
parent
916d467ab6
commit
265ce6a982
@ -15,6 +15,7 @@ const PREFIX = 'https://img.yzcdn.cn/vant-weapp/';
|
||||
const MAP = {
|
||||
index: 'index-201808121630.png',
|
||||
'action-sheet': 'action-sheet-201809071648.png',
|
||||
area: 'area-20180918.png',
|
||||
badge: 'badge-201808092138.png',
|
||||
button: 'button-201808092138.png',
|
||||
card: 'card-201808092138.png',
|
||||
|
@ -28,7 +28,8 @@
|
||||
"pages/tag/index",
|
||||
"pages/toast/index",
|
||||
"pages/transition/index",
|
||||
"pages/tree-select/index"
|
||||
"pages/tree-select/index",
|
||||
"pages/area/index"
|
||||
],
|
||||
"window": {
|
||||
"navigationBarBackgroundColor": "#f8f8f8",
|
||||
|
@ -130,6 +130,10 @@ export default [
|
||||
{
|
||||
groupName: '业务组件',
|
||||
list: [
|
||||
{
|
||||
path: '/area',
|
||||
title: 'Area 省市区选择'
|
||||
},
|
||||
{
|
||||
path: '/card',
|
||||
title: 'Card 卡片'
|
||||
|
3760
example/pages/area/area.js
Normal file
3760
example/pages/area/area.js
Normal file
File diff suppressed because it is too large
Load Diff
12
example/pages/area/index.js
Normal file
12
example/pages/area/index.js
Normal file
@ -0,0 +1,12 @@
|
||||
import Page from '../../common/page';
|
||||
import AreaList from './area';
|
||||
|
||||
Page({
|
||||
data: {
|
||||
areaList: AreaList,
|
||||
value: 330302
|
||||
},
|
||||
onChange(event) {
|
||||
console.log(event);
|
||||
}
|
||||
});
|
7
example/pages/area/index.json
Normal file
7
example/pages/area/index.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"navigationBarTitleText": "Area 省市区选择",
|
||||
"usingComponents": {
|
||||
"demo-block": "../../components/demo-block/index",
|
||||
"van-area": "../../dist/area/index"
|
||||
}
|
||||
}
|
11
example/pages/area/index.wxml
Normal file
11
example/pages/area/index.wxml
Normal file
@ -0,0 +1,11 @@
|
||||
<demo-block title="基础用法">
|
||||
<van-area area-list="{{ areaList }}" />
|
||||
</demo-block>
|
||||
|
||||
<demo-block title="选中省市县">
|
||||
<van-area area-list="{{ areaList }}" value="{{ value }}" />
|
||||
</demo-block>
|
||||
|
||||
<demo-block title="配置显示列">
|
||||
<van-area area-list="{{ areaList }}" columns-num="{{ 2 }}" title="标题" bind:confirm="onChange" bind:change="onChange" />
|
||||
</demo-block>
|
1
example/pages/area/index.wxss
Normal file
1
example/pages/area/index.wxss
Normal file
@ -0,0 +1 @@
|
||||
|
131
packages/area/README.md
Normal file
131
packages/area/README.md
Normal file
@ -0,0 +1,131 @@
|
||||
## Area 省市区选择
|
||||
省市区选择组件通常与 [弹出层](#/popup) 组件配合使用
|
||||
|
||||
### 使用指南
|
||||
|
||||
在 index.json 中引入组件
|
||||
```json
|
||||
"usingComponents": {
|
||||
"van-area": "path/to/vant-weapp/dist/area/index"
|
||||
}
|
||||
```
|
||||
|
||||
### 代码演示
|
||||
|
||||
#### 基础用法
|
||||
|
||||
要初始化一个`Area`组件,你需要传入一个`area-list`属性,数据格式具体可看下面数据格式章节
|
||||
|
||||
```html
|
||||
<van-area area-list="{{ areaList }}" />
|
||||
```
|
||||
|
||||
#### 选中省市区
|
||||
|
||||
如果想选中某个省市区,需要传入一个`value`属性,绑定对应的省市区`code`
|
||||
|
||||
```html
|
||||
<van-area area-list="{{ areaList }}" value="110101" />
|
||||
```
|
||||
|
||||
#### 配置显示列
|
||||
|
||||
可以通过`columns-num`属性配置省市区显示的列数,默认情况下会显示省市区,当你设置为`2`,则只会显示省市选择
|
||||
|
||||
```html
|
||||
<van-area area-list="{{ areaList }}" columns-num="{{ 2 }}" title="标题" />
|
||||
```
|
||||
|
||||
### API
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| --- | --- | --- | --- |
|
||||
| value | 当前选中的省市区`code` | `String` | - |
|
||||
| title | 顶部栏标题 | `String` | - |
|
||||
| area-list | 省市区数据,格式见下方 | `Object` | - |
|
||||
| columns-num | 省市区显示列数,3-省市区,2-省市,1-省 | `String | Number` | `3` |
|
||||
| loading | 是否显示加载状态 | `Boolean` | `false` |
|
||||
| item-height | 选项高度 | `Number` | `44` |
|
||||
| visible-item-count | 可见的选项个数 | `Number` | `5` |
|
||||
|
||||
### Event
|
||||
|
||||
| 事件 | 说明 | 回调参数 |
|
||||
| --- | --- | --- |
|
||||
| confirm | 点击右上方完成按钮 | 一个数组参数,具体格式看下方数据格式章节 |
|
||||
| cancel | 点击取消按钮时 | - |
|
||||
| change | 选项改变时触发 | Picker 实例,所有列选中值,当前列对应的索引 |
|
||||
|
||||
### 方法
|
||||
|
||||
通过 ref 可以获取到 area 实例并调用实例方法
|
||||
|
||||
| 方法名 | 参数 | 返回值 | 介绍 |
|
||||
|-----------|-----------|-----------|-------------|
|
||||
| reset | - | - | 重置所有选项到第一项 |
|
||||
|
||||
### 数据格式
|
||||
|
||||
#### 省市区列表数据格式
|
||||
|
||||
整体是一个 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: '河北区',
|
||||
// ....
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
完整数据见 [Area.json](https://github.com/youzan/vant/blob/dev/packages/area/demo/area.js)
|
||||
|
||||
#### 点击完成时返回的数据格式
|
||||
|
||||
返回的数据整体为一个 Object,包含 `values`, `indexs` 两个 key
|
||||
|
||||
`values` 整体为一个数组,数组内包含 `columnsNum` 个数据, 每个数据对应一列选项中被选中的数据。
|
||||
|
||||
`code` 代表被选中的地区编码, `name` 代表被选中的地区名称
|
||||
|
||||
```javascript
|
||||
[
|
||||
{
|
||||
code: '110000',
|
||||
name: '北京市'
|
||||
},
|
||||
{
|
||||
code: '110100',
|
||||
name: '北京市'
|
||||
},
|
||||
{
|
||||
code: '110101',
|
||||
name: '东城区'
|
||||
}
|
||||
];
|
||||
```
|
||||
|
||||
`indexs` 为一个数组,数组内包含 `columnsNum` 个数据, 每个数据对应一列选项中被选中项的序号。
|
146
packages/area/index.js
Normal file
146
packages/area/index.js
Normal file
@ -0,0 +1,146 @@
|
||||
import { create } from '../common/create';
|
||||
|
||||
create({
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
observer(value) {
|
||||
this.code = value;
|
||||
this.setValues();
|
||||
}
|
||||
},
|
||||
title: String,
|
||||
loading: Boolean,
|
||||
itemHeight: {
|
||||
type: Number,
|
||||
value: 44
|
||||
},
|
||||
visibleItemCount: {
|
||||
type: Number,
|
||||
value: 5
|
||||
},
|
||||
columnsNum: {
|
||||
type: [String, Number],
|
||||
value: 3
|
||||
},
|
||||
areaList: {
|
||||
type: Object,
|
||||
value: {},
|
||||
observer() {
|
||||
this.setValues();
|
||||
}
|
||||
}
|
||||
},
|
||||
data: {
|
||||
pickerValue: [0, 0, 0],
|
||||
columns: []
|
||||
},
|
||||
computed: {
|
||||
displayColumns() {
|
||||
const { columns = [], columnsNum } = this.data;
|
||||
return columns.slice(0, +columnsNum);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onCancel() {
|
||||
this.triggerEvent('cancel', {
|
||||
values: this.getValues(),
|
||||
indexs: this.getIndexs()
|
||||
});
|
||||
},
|
||||
|
||||
onConfirm() {
|
||||
this.triggerEvent('confirm', {
|
||||
values: this.getValues(),
|
||||
indexs: this.getIndexs()
|
||||
});
|
||||
},
|
||||
|
||||
onChange(event) {
|
||||
const { value } = event.detail;
|
||||
const { pickerValue, displayColumns } = this.data;
|
||||
const index = pickerValue.findIndex((item, index) => item !== value[index]);
|
||||
const values = displayColumns[index];
|
||||
|
||||
this.code = values[value[index]].code;
|
||||
this.setValues();
|
||||
this.triggerEvent('change', {
|
||||
picker: this,
|
||||
values: this.getValues(),
|
||||
index
|
||||
});
|
||||
},
|
||||
|
||||
getList(type, code) {
|
||||
let result = [];
|
||||
if (type !== 'province' && !code) {
|
||||
return result;
|
||||
}
|
||||
|
||||
const list = this.data.areaList[`${type}_list`] || {};
|
||||
result = Object.keys(list).map(code => ({
|
||||
code,
|
||||
name: list[code]
|
||||
}));
|
||||
|
||||
if (code) {
|
||||
result = result.filter(item => item.code.indexOf(code) === 0);
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
getIndex(type, code) {
|
||||
const compareNum = type === 'province' ? 2 : type === 'city' ? 4 : 6;
|
||||
const list = this.getList(type, code.slice(0, compareNum - 2));
|
||||
code = code.slice(0, compareNum);
|
||||
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
if (list[i].code.slice(0, compareNum) === code) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
},
|
||||
|
||||
setValues() {
|
||||
let code = this.code || Object.keys(this.data.areaList.county_list)[0] || '';
|
||||
const province = this.getList('province');
|
||||
const city = this.getList('city', code.slice(0, 2));
|
||||
|
||||
this.setData({
|
||||
'columns[0]': province,
|
||||
'columns[1]': city
|
||||
});
|
||||
|
||||
if (city.length && code.slice(2, 4) === '00') {
|
||||
code = city[0].code;
|
||||
}
|
||||
|
||||
this.setData({
|
||||
'columns[2]': this.getList('county', code.slice(0, 4)),
|
||||
pickerValue: [
|
||||
this.getIndex('province', code),
|
||||
this.getIndex('city', code),
|
||||
this.getIndex('county', code)
|
||||
]
|
||||
});
|
||||
},
|
||||
|
||||
getValues() {
|
||||
const { displayColumns = [], pickerValue = [] } = this.data;
|
||||
return displayColumns.map((option, index) => option[pickerValue[index]]);
|
||||
},
|
||||
|
||||
getIndexs() {
|
||||
const { pickerValue, columnsNum } = this.data;
|
||||
return pickerValue.slice(0, columnsNum);
|
||||
},
|
||||
|
||||
reset() {
|
||||
this.code = '';
|
||||
this.setValues();
|
||||
}
|
||||
}
|
||||
});
|
6
packages/area/index.json
Normal file
6
packages/area/index.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {
|
||||
"van-loading": "../loading/index"
|
||||
}
|
||||
}
|
69
packages/area/index.pcss
Normal file
69
packages/area/index.pcss
Normal file
@ -0,0 +1,69 @@
|
||||
@import '../common/style/var.pcss';
|
||||
|
||||
.van-picker {
|
||||
-webkit-text-size-adjust: 100%; /* avoid iOS text size adjust */
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
background-color: $white;
|
||||
user-select: none;
|
||||
|
||||
&__toolbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
height: 40px;
|
||||
font-size: 16px;
|
||||
line-height: 40px;
|
||||
}
|
||||
|
||||
&__cancel,
|
||||
&__confirm {
|
||||
padding: 0 15px;
|
||||
color: $blue;
|
||||
|
||||
&:active {
|
||||
background-color: $active-color;
|
||||
}
|
||||
}
|
||||
|
||||
&__title {
|
||||
max-width: 50%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&__columns {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
&__loading {
|
||||
display: flex;
|
||||
z-index: 4;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: rgba(255, 255, 255, .9);
|
||||
}
|
||||
|
||||
&-column {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
font-size: 16px;
|
||||
text-align: center;
|
||||
|
||||
&__item {
|
||||
padding: 0 5px;
|
||||
color: $gray-dark;
|
||||
|
||||
&--selected {
|
||||
color: $black;
|
||||
}
|
||||
|
||||
&--disabled {
|
||||
opacity: .3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
34
packages/area/index.wxml
Normal file
34
packages/area/index.wxml
Normal file
@ -0,0 +1,34 @@
|
||||
<view class="van-picker">
|
||||
<view class="van-picker__toolbar">
|
||||
<view class="van-picker__cancel" bindtap="onCancel">取消</view>
|
||||
<view class="van-picker__title">{{ title }}</view>
|
||||
<view class="van-picker__confirm" bindtap="onConfirm">确定</view>
|
||||
</view>
|
||||
|
||||
<view wx:if="{{ loading }}" class="van-picker__loading">
|
||||
<van-loading color="#38f"/>
|
||||
</view>
|
||||
|
||||
<picker-view
|
||||
indicator-style="height: {{ itemHeight }}px;"
|
||||
style="width: 100%; height: {{ itemHeight * visibleItemCount + 'px' }}"
|
||||
bindchange="onChange"
|
||||
value="{{ pickerValue }}"
|
||||
class="van-picker__columns"
|
||||
>
|
||||
<picker-view-column
|
||||
wx:for="{{ displayColumns }}"
|
||||
wx:for-item="row"
|
||||
wx:for-index="rowIndex"
|
||||
wx:key="rowIndex"
|
||||
class="van-picker-column"
|
||||
>
|
||||
<view
|
||||
wx:for="{{ row }}"
|
||||
wx:key="{{ item.code }}"
|
||||
style="line-height: {{ itemHeight }}px;"
|
||||
class="van-picker-column__item {{ index === pickerValue[rowIndex] ? 'van-picker-column__item--selected' : '' }}"
|
||||
>{{ item.name }}</view>
|
||||
</picker-view-column>
|
||||
</picker-view>
|
||||
</view>
|
Loading…
x
Reference in New Issue
Block a user