微信小程序自定義數(shù)據(jù)實現(xiàn)級聯(lián)省市區(qū)組件功能
前言
在微信小程序中,官方文檔提供的省市區(qū)組件,可以讓用戶更加方便快捷地選擇省市區(qū),但是官方提供的組件有一個缺點,無法自定義數(shù)據(jù),但如果項目中需要使用自己的數(shù)據(jù),顯然就得尋找其它的組件實現(xiàn)。
官方組件
優(yōu)點
- 使用官方組件具有穩(wěn)定性和兼容性,可以保證在不同的微信小程序版本中正常運行;
- 官方組件的使用文檔詳細,易于上手,可以快速實現(xiàn)級聯(lián)省市區(qū)組件;
- 官方組件的樣式和交互效果都比較簡潔,符合微信小程序的設(shè)計風(fēng)格。
缺點
- 官方組件的樣式和交互效果比較單一,無法滿足一些特殊需求;
- 官方組件的自定義能力比較有限,無法進行個性化定制。
wxml 文件
<picker mode="region" bindchange="bindRegionChange" value="{{region}}" custom-item="{{customItem}}">
<view class="picker">
當(dāng)前選擇:{{region[0]}},{{region[1]}},{{region[2]}}
</view>
</picker>js 文件
Page({
data: {
region: [],
},
bindRegionChange: function (e) {
console.log('picker發(fā)送選擇改變,攜帶值為', e.detail.value)
this.setData({
region: e.detail.value
})
}
})實現(xiàn)效果

vant-weapp 實現(xiàn)
vant-weapp 中為我們提供了級聯(lián)選擇器,并且組件的樣式和交互效果比較豐富,可以滿足各種特殊需求,使用這個組件也可以實現(xiàn),但是 vant-weapp 也有一個問題,當(dāng)數(shù)據(jù)量比較大時,組件就會變得異常卡頓。
wxml 文件
<van-field value="{{ fieldValue }}" is-link readonly label="地區(qū)" placeholder="請選擇所在地區(qū)" bind:tap="onClick" />
<van-popup show="{{ show }}" round position="bottom">
<van-cascader field-names="{{ fieldNames }}" wx:if="{{ show }}" value="{{ cascaderValue }}" title="請選擇所在地區(qū)"
options="{{ options }}" bind:close="onClose" bind:finish="onFinish" />
</van-popup>js 文件
Page({
data: {
show: false,
fieldValue: '',
cascaderValue: '',
fieldNames: {
text: 'label',
value: 'value',
children: 'children',
},
options: [],
},
onLoad() {
this.setData({
options: JSON.parse(wx.getStorageSync('addressInfo'))
})
},
onClick() {
this.setData({
show: true,
});
},
onClose() {
this.setData({
show: false,
});
},
onFinish(e) {
const {
selectedOptions,
value
} = e.detail;
const fieldValue = selectedOptions
.map((item) => item.label || item.value)
.join('/');
this.setData({
fieldValue,
cascaderValue: value,
})
console.log(fieldValue);
this.onClose()
},
});實現(xiàn)效果
肉眼可見非常卡頓,每點擊一次都要等好幾秒才能反應(yīng)過來。

自定義組件
既然上面兩種實現(xiàn)方法都不符合我們的需求,那么自己自定義組件就可以完全按照自己的需求進行設(shè)計和開發(fā)。
封裝 wxml 文件
<picker mode="multiSelector" model:value="{{pickerValue}}" range-key="label" range="{{range}}" bindchange="onChange"
bindcolumnchange="columnChange">
<view>
<!-- 如果已經(jīng)選擇了選項,則顯示選項的label屬性,否則顯示placeholder屬性。 -->
<text wx:if="{{label}}"> {{ label }} </text>
<text style="color: #999" wx:else> {{ placeholder }}</text>
</view>
</picker>封裝 js 文件
Component({
properties: {
// placeholder為選擇器的默認提示文字
placeholder: {
type: String,
value: '請選擇',
},
// value為選擇器的默認值,類型為數(shù)組
value: {
type: Array,
value: [],
// observer監(jiān)聽value的變化,如果有值則調(diào)用setLabel方法設(shè)置選擇器的label
observer(selectedValues) {
if (selectedValues && selectedValues.length) {
this.setLabel();
}
}
}
},
data: {
// label為選擇器的顯示值
label: '',
// range為選擇器的可選項,類型為數(shù)組,包含三個數(shù)組,分別為省、市、區(qū)/縣
range: [],
// pickerValue為選擇器的選中值,類型為數(shù)組,包含三個數(shù)字,分別為省、市、區(qū)/縣的下標
pickerValue: [],
// addressList為選擇器的數(shù)據(jù)源,類型為數(shù)組,包含省、市、區(qū)/縣的信息
addressList: [],
},
// attached生命周期函數(shù),在組件實例進入頁面節(jié)點樹時執(zhí)行
attached() {
// 獲取地址列表,如果value為空則初始化range
this.getAddressList().then(() => {
if (!this.data.value.length) {
this.initRange();
}
});
},
methods: {
// getAddressItem方法用于將地址信息轉(zhuǎn)換為選擇器可用的格式
getAddressItem(data) {
return {
label: data.label,
value: data.value
};
},
// setAddressList方法用于將地址列表轉(zhuǎn)換為選擇器可用的格式
setAddressList(list) {
return list.map((v) => this.getAddressItem(v));
},
// getAddressByCode方法用于根據(jù)value值獲取地址信息及其在數(shù)組中的下標
getAddressByCode(list = [], value) {
let index = list.findIndex(item => item.value === value);
return [index, list[index] || {}];
},
// openChildren方法用于根據(jù)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.getAddressItem(v);
});
result.push(newarr);
}
handle(list, keys);
return result.reverse();
},
// onChange方法為選擇器的change事件處理函數(shù),用于設(shè)置label和觸發(fā)change事件
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方法為選擇器的columnchange事件處理函數(shù),用于設(shè)置range和pickerValue
columnChange(e) {
const {
column,
value
} = e.detail;
this.setColumn(column, value);
},
// setColumn方法用于設(shè)置range和pickerValue
setColumn(column, value) {
let addressList = this.data.addressList;
if (!addressList || addressList.length === 0) return;
let [r1, r2, r3] = this.data.range;
if (column === 0) {
r2 = this.setAddressList(addressList[value].children);
r3 = this.setAddressList(addressList[value].children[0].children);
this.setData({
pickerValue: [value, 0, 0]
});
} else if (column === 1) {
const [v1] = this.data.pickerValue;
r3 = this.setAddressList(addressList[v1].children[value].children);
this.setData({
pickerValue: [v1, value, 0]
});
}
this.setData({
range: [r1, r2, r3]
});
},
// setLabel方法用于設(shè)置label
setLabel() {
let addressList = this.data.addressList;
if (addressList && addressList.length) {
const [v1, v2, v3] = this.data.value;
const [s1, {
label: t1,
children: l1
}] = this.getAddressByCode(addressList, v1);
const [s2, {
label: t2,
children: l2
}] = this.getAddressByCode(l1, v2);
const [s3, {
label: t3
}] = this.getAddressByCode(l2, v3);
const label = [t1, t2, t3].filter(v => v).join('-');
const pickerValue = [s1, s2, s3];
const range = this.openChildren(addressList, [s1, s2, s3]);
if (label.length) {
this.setData({
label,
range,
pickerValue
});
}
} else {
this.getAddressList().then(() => {
this.setLabel();
});
}
},
// initRange方法用于初始化range
initRange() {
if (!this.data.value.length) {
const range = this.openChildren(this.data.addressList, [0, 0, 0]);
this.setData({
range
});
}
},
// getAddressList方法用于獲取地址列表
getAddressList() {
return new Promise((resolve, reject) => {
wx.getStorage({
key: 'addressInfo',
success: (res) => {
this.setData({
addressList: JSON.parse(res.data)
});
resolve();
},
fail: (err) => {
reject(err);
}
});
});
},
},
});使用 wxml 文件
<picker-region bindchange="regionChange" placeholder="請選擇所在區(qū)域" value="{{value}}" />使用 js 文件
Page({
data: {
value: ""
},
regionChange(e) {
console.log(e)
},
})模擬 json 數(shù)據(jù)格式
[
{
"value": "110000",
"label": "北京市",
"regionLevel": "1",
"parentRegionCode": "0",
"children": [
{
"value": "110100",
"label": "市轄區(qū)",
"regionLevel": "2",
"parentRegionCode": "110000",
"children": [
{
"value": "110101",
"label": "東城區(qū)",
"regionLevel": "3",
"parentRegionCode": "110100",
"children": null
},
{
"value": "110118",
"label": "密云區(qū)",
"regionLevel": "3",
"parentRegionCode": "110100",
"children": null
}
]
}
]
},
{
"value": "120000",
"label": "天津市",
"regionLevel": "1",
"parentRegionCode": "0",
"children": [
{
"value": "120100",
"label": "市轄區(qū)",
"regionLevel": "2",
"parentRegionCode": "120000",
"children": [
{
"value": "120101",
"label": "和平區(qū)",
"regionLevel": "3",
"parentRegionCode": "120100",
"children": null
},
{
"value": "120102",
"label": "河?xùn)|區(qū)",
"regionLevel": "3",
"parentRegionCode": "120100",
"children": null
}
]
}
]
}
]實現(xiàn)效果

到此這篇關(guān)于微信小程序自定義數(shù)據(jù)實現(xiàn)級聯(lián)省市區(qū)組件的文章就介紹到這了,更多相關(guān)小程序級聯(lián)省市區(qū)組件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
javascript document.execCommand() 常用解析
dom下execCommand命令的一些參數(shù)整理,需要的朋友可以參考下。2009-12-12
Three.js源碼閱讀筆記(基礎(chǔ)的核心Core對象)
Three.js是一個比較偉大的webgl開源庫,它簡化了瀏覽器3D編程,使得使用JavaScript在瀏覽器中創(chuàng)建復(fù)雜的場景變得容易很多接下來先從最基礎(chǔ)的核心(Core)對象開始,感興趣的朋友可以參考下2012-12-12
JavaScript 判斷判斷某個對象是Object還是一個Array
在開發(fā)中,我們經(jīng)常需要判斷某個對象是否為數(shù)組類型,在Js中檢測對象類型的常見方法都有哪些呢?2010-01-01
深入理解JavaScript系列(21):S.O.L.I.D五大原則之接口隔離原則ISP詳解
這篇文章主要介紹了深入理解JavaScript系列(21):S.O.L.I.D五大原則之接口隔離原則ISP詳解,本文講解了JavaScript接口、ISP與JavaScript、墮落的實現(xiàn)、靜態(tài)耦合、語義耦合、可擴展性等內(nèi)容,需要的朋友可以參考下2015-03-03
JavaScript中用getDate()方法返回指定日期的教程
這篇文章主要介紹了JavaScript中用getDate()方法返回指定日期的教程,是JS入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下2015-06-06
javascript 數(shù)組學(xué)習(xí)資料收集
由于javascript 數(shù)組應(yīng)用比較廣泛,使用的朋友越來越多,腳本之家特為大家整理了一些js 數(shù)據(jù)方面的學(xué)習(xí)資料,大家看完了,基本上應(yīng)該對數(shù)組有個理解了。2010-04-04
Javascript中的getUTCHours()方法使用詳解
這篇文章主要介紹了Javascript中的getUTCHours()方法使用詳解,是JS入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下2015-06-06

