微信小程序自定義數(shù)據(jù)實(shí)現(xiàn)級聯(lián)省市區(qū)組件功能
前言
在微信小程序中,官方文檔提供的省市區(qū)組件,可以讓用戶更加方便快捷地選擇省市區(qū),但是官方提供的組件有一個(gè)缺點(diǎn),無法自定義數(shù)據(jù),但如果項(xiàng)目中需要使用自己的數(shù)據(jù),顯然就得尋找其它的組件實(shí)現(xiàn)。
官方組件
優(yōu)點(diǎn)
- 使用官方組件具有穩(wěn)定性和兼容性,可以保證在不同的微信小程序版本中正常運(yùn)行;
- 官方組件的使用文檔詳細(xì),易于上手,可以快速實(shí)現(xiàn)級聯(lián)省市區(qū)組件;
- 官方組件的樣式和交互效果都比較簡潔,符合微信小程序的設(shè)計(jì)風(fēng)格。
缺點(diǎn)
- 官方組件的樣式和交互效果比較單一,無法滿足一些特殊需求;
- 官方組件的自定義能力比較有限,無法進(jìn)行個(gè)性化定制。
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 }) } })
實(shí)現(xiàn)效果
vant-weapp 實(shí)現(xiàn)
vant-weapp 中為我們提供了級聯(lián)選擇器,并且組件的樣式和交互效果比較豐富,可以滿足各種特殊需求,使用這個(gè)組件也可以實(shí)現(xiàn),但是 vant-weapp
也有一個(gè)問題,當(dāng)數(shù)據(jù)量比較大時(shí),組件就會變得異常卡頓。
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() }, });
實(shí)現(xiàn)效果
肉眼可見非??D,每點(diǎn)擊一次都要等好幾秒才能反應(yīng)過來。
自定義組件
既然上面兩種實(shí)現(xiàn)方法都不符合我們的需求,那么自己自定義組件就可以完全按照自己的需求進(jìn)行設(shè)計(jì)和開發(fā)。
封裝 wxml
文件
<picker mode="multiSelector" model:value="{{pickerValue}}" range-key="label" range="{{range}}" bindchange="onChange" bindcolumnchange="columnChange"> <view> <!-- 如果已經(jīng)選擇了選項(xiàng),則顯示選項(xiàng)的label屬性,否則顯示placeholder屬性。 --> <text wx:if="{{label}}"> {{ label }} </text> <text style="color: #999" wx:else> {{ placeholder }}</text> </view> </picker>
封裝 js
文件
Component({ properties: { // placeholder為選擇器的默認(rèn)提示文字 placeholder: { type: String, value: '請選擇', }, // value為選擇器的默認(rèn)值,類型為數(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為選擇器的可選項(xiàng),類型為數(shù)組,包含三個(gè)數(shù)組,分別為省、市、區(qū)/縣 range: [], // pickerValue為選擇器的選中值,類型為數(shù)組,包含三個(gè)數(shù)字,分別為省、市、區(qū)/縣的下標(biāo) pickerValue: [], // addressList為選擇器的數(shù)據(jù)源,類型為數(shù)組,包含省、市、區(qū)/縣的信息 addressList: [], }, // attached生命周期函數(shù),在組件實(shí)例進(jìn)入頁面節(jié)點(diǎn)樹時(shí)執(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ù)組中的下標(biāo) 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 } ] } ] } ]
實(shí)現(xiàn)效果
到此這篇關(guān)于微信小程序自定義數(shù)據(jù)實(shí)現(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-12Three.js源碼閱讀筆記(基礎(chǔ)的核心Core對象)
Three.js是一個(gè)比較偉大的webgl開源庫,它簡化了瀏覽器3D編程,使得使用JavaScript在瀏覽器中創(chuàng)建復(fù)雜的場景變得容易很多接下來先從最基礎(chǔ)的核心(Core)對象開始,感興趣的朋友可以參考下2012-12-12JavaScript 判斷判斷某個(gè)對象是Object還是一個(gè)Array
在開發(fā)中,我們經(jīng)常需要判斷某個(gè)對象是否為數(shù)組類型,在Js中檢測對象類型的常見方法都有哪些呢?2010-01-01深入理解JavaScript系列(21):S.O.L.I.D五大原則之接口隔離原則ISP詳解
這篇文章主要介紹了深入理解JavaScript系列(21):S.O.L.I.D五大原則之接口隔離原則ISP詳解,本文講解了JavaScript接口、ISP與JavaScript、墮落的實(shí)現(xiàn)、靜態(tài)耦合、語義耦合、可擴(kuò)展性等內(nèi)容,需要的朋友可以參考下2015-03-03JavaScript中用getDate()方法返回指定日期的教程
這篇文章主要介紹了JavaScript中用getDate()方法返回指定日期的教程,是JS入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下2015-06-06javascript 數(shù)組學(xué)習(xí)資料收集
由于javascript 數(shù)組應(yīng)用比較廣泛,使用的朋友越來越多,腳本之家特為大家整理了一些js 數(shù)據(jù)方面的學(xué)習(xí)資料,大家看完了,基本上應(yīng)該對數(shù)組有個(gè)理解了。2010-04-04Javascript中的getUTCHours()方法使用詳解
這篇文章主要介紹了Javascript中的getUTCHours()方法使用詳解,是JS入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下2015-06-06