因为微信小程序自带的区域选择插件,不支持通过code(地区编号)回显,回返的code和其他一些通用区域选择插件(如:element UI)的也有些区别,所以封装了一个自定义插件。
附带代码详细仓库地址:微信小程序省市区选择插件
用的是小程序字典的picker (mode="multiSelector")来进行封装:
先给出调用方式:
<picker-region bindchange="regionChange" />
<picker-region bindchange="regionChange" placeholder="请选择所在区域" />
<picker-region bindchange="regionChange" placeholder="请选择所在区域" value="{{value}}" />
具体实现如下:
<!-- wxml -->
<view class="picker-txt">
<text class="text" wx:if="{{label}}"> {{ label }} </text>
<text class="ccc" wx:else> {{ placeholder }}</text>
</view>
</picker>
// js 实现逻辑
const {
RegionData
} = require('./region-data');
Component({
properties: {
placeholder: {
type: String,
value: '请选择',
},
value: {
type: Array,
value: [],
observer(v) {
if (v && v.length) {
this.setLabel();
}
}
}
},
list: [],
data: {
label: '',
range: [],
pickerValue: [],
},
methods: {
getItem(data) {
return {
label: data.label,
value: data.value
};
},
setList(list) {
return list.map((v) => this.getItem(v));
},
getByCode(list = [], value) {
let index = list.findIndex(item => item.value === value);
return [index, list[index] || {}];
},
/**
* 将省市区联级数据处理成展开显示的列表
* @param list 需要处理的数组, {label: "北京市", value: "11", children: [...]}
* @param keys 需要获取到的展开项下标集合 [0,1,n],对应 picker 的 model:value 绑定的值
*/
openChildren(list, keys) {
let result = [];
const handle = (arr, keys) => {
let newarr = arr.map((v, index) => {
if (keys && keys.length) {
let [currentKey, ...nextKey] = keys;
if (currentKey === index && Array.isArray(v.children)) {
handle(v.children, nextKey);
}
}
return this.getItem(v);
});
result.push(newarr);
}
handle(list, keys);
return result.reverse();
},
// 确认选择
onChange(e) {
let [r1, r2, r3] = this.data.range;
const [v1, v2, v3] = e.detail.value;
const selected = [r1[v1], r2[v2], r3[v3]];
const values = selected.map(v => v.value);
const label = selected.map(v => v.label).join('-');
this.setData({
label
});
this.triggerEvent("change", {
value: values,
label
});
},
// 切换选项
columnChange(e) {
const {
column,
value
} = e.detail;
this.setColumn(column, value);
},
// 设置列表数据
setColumn(column, value) {
let list = this.list;
if (!list || list.length === 0) return;
let [r1, r2, r3] = this.data.range;
if (column === 0) {
// 切换第一列,修改第二第三列数据项
r2 = this.setList(list[value].children);
r3 = this.setList(list[value].children[0].children);
// 修改第一列选中值,在切换第二列的时候用到
this.setData({
pickerValue: [value, 0, 0]
});
} else if (column === 1) {
// 切换第二列,修改第三列数据项
const [v1] = this.data.pickerValue;
r3 = this.setList(list[v1].children[value].children);
this.setData({
pickerValue: [v1, value, 0]
});
}
this.setData({
range: [r1, r2, r3]
});
},
setLabel() {
// 设置回显的默认值
let list = this.list;
if (list && list.length) {
const [v1, v2, v3] = this.data.value; // 回显的省市区对应的value,来自父组件传入
const [s1, {
label: t1,
children: l1
}] = this.getByCode(list, v1);
const [s2, {
label: t2,
children: l2
}] = this.getByCode(l1, v2);
const [s3, {
label: t3
}] = this.getByCode(l2, v3);
// 回显的省市区名称,本控件展示的内容(xx省-xx市-xx区)
const label = [t1, t2, t3].filter(v => v).join('-');
// 回显的省市区下标,小程序piker控件的值([1,2,n])
const pickerValue = [s1, s2, s3];
const range = this.openChildren(list, [s1, s2, s3]);;
if (label.length) {
this.setData({
label,
range,
pickerValue
});
}
} else {
this.getRange();
this.setLabel();
}
},
initRange() {
if (!this.data.value.length) {
// 没有默认值,取第一条作为初始化省市区数据列
const range = this.openChildren(this.list, [0, 0, 0]);
this.setData({
range
});
}
},
// 获取全国省市区列表原始数据
async getRange() {
this.list = RegionData();
},
},
attached: function () {
// 在组件实例进入页面节点树时执行
this.getRange();
if (!this.data.value.length) {
this.initRange();
}
},
})
// json数据格式,可根据需求自行定义
module.exports = {
RegionData: function () {
return [{
"value": "11",
"label": "北京市",
"children": [{
"value": "1101",
"label": "市辖区",
"children": [{
"value": "110101",
"label": "东城区"
},
......
实现的效果