小程序的三级联动
程序员文章站
2022-04-13 22:23:11
项目中经常遇到要选择城市。用到三级联动的方式 微信小程序的 组件 是三级联动的,但是无法自定义,这让我们心痛不已,值得我们欣慰的 picker view 组件是可以自定义添加多个选项,但还是无法联动。既然这样那就自己写一个联动。 做到如下图所示: 分为动态获取地址 引用静态文件获取地址
项目中经常遇到要选择城市。用到三级联动的方式
- 微信小程序的
picker
组件mode=date
是三级联动的,但是无法自定义,这让我们心痛不已,值得我们欣慰的 picker-view 组件是可以自定义添加多个选项,但还是无法联动。既然这样那就自己写一个联动。 - 做到如下图所示:
- 分为动态获取地址
- 引用静态文件获取地址
- addressadd.wxml
<view class="add-address"> <view class="add-form"> <view class="form-item"> <input class="input" bindinput="bindinputname" placeholder="姓名" value="{{address.name}}" /> </view> <view class="form-item"> <input class="input" bindinput="bindinputmobile" value="{{address.mobile}}" placeholder="手机号码" /> </view> <view class="form-item"> <input class="input" bindinput="bindinputaddress" value="{{address.address}}" placeholder="详细地址" /> </view> <view class="form-item" bindtap='select'> <view class="weui-cell__bd"> {{areainfo}} </view> </view> <view class="form-default"> <text bindtap="bindisdefault" class="default-input {{address.isdefault == 1 ? 'selected' : ''}}">设为默认地址</text> </view> </view> <view class="btns"> <button class="cannel" bindtap="canceladdress">取消</button> <button class="save" bindtap="saveaddress">保存</button> </view> </view> <view class="bg-mask" bindtap="cancelselectregion" wx:if="{{openselectregion}}"></view> <view class="picker-view" animation="{{animationaddressmenu}}" style="visibility:{{addressmenuisshow ? 'visible':'hidden'}}"> <!-- 确认取消按钮 --> <view class='btn'> <text catchtap="citycancel">取消</text> <text style="float: right" catchtap="citysure">确定</text> </view> <!-- 选择地址 --> <picker-view class='cont' bindchange="citychange" value="{{value}}" wx:key=""> <!-- 省 --> <picker-view-column> <view wx:for="{{provinces}}" class="picker-item" wx:key="{{index}}">{{item.area}}</view> </picker-view-column> <!-- 市 --> <picker-view-column> <view wx:for="{{citys}}" class="picker-item" wx:key="index">{{item.area}}</view> </picker-view-column> <!-- 区 --> <picker-view-column> <view wx:for="{{areas}}" class="picker-item" wx:key="index">{{item.area}}</view> </picker-view-column> </picker-view> </view>
- addressadd.wxss
page{ height: 100%; background: #f4f4f4; } .add-address .add-form{ background: #fff; width: 100%; height: auto; overflow: hidden; } .add-address .form-item{ height: 116rpx; padding-left: 31.25rpx; border-bottom: 1px solid #d9d9d9; display: flex; align-items: center; padding-right: 31.25rpx; } .add-address .input{ flex: 1; height: 44rpx; line-height: 44rpx; overflow: hidden; } .add-address .form-default{ border-bottom: 1px solid #d9d9d9; height: 96rpx; background: #fafafa; padding-top: 28rpx; font-size: 28rpx; } .default-input{ margin: 0 auto; display: block; width: 240rpx; height: 40rpx; padding-left: 50rpx; line-height: 40rpx; background: url(http://yanxuan.nosdn.127.net/hxm/yanxuan-wap/p/20161201/style/img/sprites/checkbox-sed825af9d3-a6b8540d42.png) 1rpx -448rpx no-repeat; background-size: 38rpx 486rpx; font-size: 28rpx; } .default-input.selected{ background: url(http://yanxuan.nosdn.127.net/hxm/yanxuan-wap/p/20161201/style/img/sprites/checkbox-sed825af9d3-a6b8540d42.png) 0 -192rpx no-repeat; background-size: 38rpx 486rpx; } .add-address .btns{ position: fixed; bottom: 0; left: 0; overflow: hidden; display: flex; height: 100rpx; width: 100%; } .add-address .cannel,.add-address .save{ flex: 1; height: 100rpx; text-align: center; line-height: 100rpx; font-size: 28rpx; color: #fff; border:none; border-radius: 0; } .add-address .cannel{ background: #3f3f3f; } .add-address .save{ background: #a78845; } .region-select{ width: 100%; height: 600rpx; background: #fff; position: fixed; z-index: 10; left:0; bottom: 0; } .region-select .hd{ height: 108rpx; width: 100%; border-bottom: 1px solid #f4f4f4; padding: 46rpx 30rpx 0 30rpx; } .region-select .region-selected{ float: left; height: 60rpx; display: flex; } .region-select .region-selected .item{ max-width: 140rpx; margin-right: 30rpx; text-align: left; line-height: 60rpx; height: 100%; color: #333; font-size: 28rpx; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .region-select .region-selected .item.disabled{ color: #999; } .region-select .region-selected .item.selected{ color: #a78845; } .region-select .done{ float: right; height: 60rpx; width: 60rpx; border: none; background: #fff; line-height: 60rpx; text-align: center; color: #333; font-size: 28rpx; } .region-select .done.disabled{ color: #999; } .region-select .bd{ height: 492rpx; width: 100%; padding: 0 30rpx; } .region-select .region-list{ height: 492rpx; } .region-select .region-list .item{ width: 100%; height: 104rpx; line-height: 104rpx; text-align: left; color: #333; font-size: 28rpx; } .region-select .region-list .item.selected{ color: #b4282d; } .bg-mask{ height: 100%; width: 100%; background: rgba(0, 0, 0, 0.4); position: fixed; top:0; left:0; z-index: 8; } .picker-view { width: 100%; display: flex; z-index:12; background-color: #fff; /* background: rgba(0, 0, 0, .2); */ flex-direction: column; justify-content: center; align-items: center; position: fixed; bottom: 0; left: 0rpx; height: 40vh; } .btn { width: 100%; height: 90rpx; padding: 0 24rpx; box-sizing: border-box; line-height: 90rpx; text-align: center; display: flex; background: rgba(255,255,255,.8); justify-content: space-between; } .cont { width: 100%; height: 389rpx; } .picker-item { line-height: 70rpx; margin-left: 5rpx; margin-right: 5rpx; text-align: center; } .address { width: 100%; height: 90rpx; line-height: 90rpx; text-align: center; border-bottom: 1rpx solid #f1f1f1; }
- addressadd.js (分两个版本一个是动态获取的
就是选择的时候动态向后台获取内容
下方是动态获取的例子:)
var util = require('../../../utils/util.js'); var api = require('../../../config/api.js'); var app = getapp(); page({ data: { addressid: 0, openselectregion: false, regiontype: 1, selectregiondone: false, szxqlist: [], szxq: { id: "", name: "请选择小区" }, szdslist: [], szds: { id: "", name: "" }, fanghao: "", animationaddressmenu: {}, addressmenuisshow: false, value: [0, 0, 0], provinces: [], citys: [], areas: [], areainfo: '', areajson: {} }, bindinputmobile(event) { let address = this.data.address; address.mobile = event.detail.value; this.setdata({ address: address }); }, bindinputname(event) { let address = this.data.address; address.name = event.detail.value; this.setdata({ address: address }); }, bindinputaddress(event) { let address = this.data.address; address.address = event.detail.value; this.setdata({ address: address }); }, bindisdefault() { let address = this.data.address; address.isdefault = !address.isdefault; this.setdata({ address: address }); }, getaddressdetail() { let that = this; // util.request(api.addressdetail, { // id: that.data.addressid // }).then(function(res) { // if (res.errno === 0) { // if (res.data) { // that.setdata({ // address: res.data // }); // } // } // }); }, wxchooseaddress() { let that = this; let address = this.data.address; // 用户已经同意小程序使用地址功能 wx.chooseaddress({ success: function(res) { address.provinceid = 99999; address.cityid = 88888; address.areaid = 77777; address.name = res.username; address.mobile = res.telnumber; address.provincename = res.provincename; address.cityname = res.cityname; address.areaname = res.countyname; address.address = res.provincename + res.cityname + res.countyname + res.detailinfo; that.setdata({ address: address, }); } }); }, wxaddress() { let that = this; // 可以通过 wx.getsetting 先查询一下用户是否授权了 "scope.address" 这个 scope wx.getsetting({ success(res) { if (!res.authsetting['scope.address']) { wx.authorize({ scope: 'scope.address', success() { that.wxchooseaddress(); } }) } else { that.wxchooseaddress(); } } }) }, onload: function(options) { let that = this; // 页面初始化 options为页面跳转所带来的参数 console.log(options); if (options.id && options.id != 0) { this.setdata({ addressid: options.id }); this.getaddressdetail(); } else { that.wxaddress(); } }, onready: function() { }, canceladdress() { wx.navigateback(); }, saveaddress() { console.log(this.data.address); let address = this.data.address; if (address.name == '') { util.showerrortoast('请输入姓名'); return false; } if (address.mobile == '') { util.showerrortoast('请输入手机号码'); return false; } if (address.areaid == 0) { util.showerrortoast('请输入省市区'); return false; } if (address.address == '') { util.showerrortoast('请输入详细地址'); return false; } let that = this; }, onshow: function() { // 获取所在栋数 var animation = wx.createanimation({ duration: 500, timingfunction: 'linear', }) this.animation = animation const that = this // 获取所在地区 console.log() util.getareareq().then(provinces => { util.getareareq(provinces[0].code).then(citys => { util.getareareq(citys[0].code).then(areas => { that.setdata({ provinces: provinces, citys: citys, areas: areas, areajson: { provinces: { id: 40, name: "广东省" }, citys: { id: 4006, name: "河源市" }, areas: { id: 400602, name: "源城区" } } }) var areas = that.data.areajson.areas.name == null ? "" : that.data.areajson.areas.name var areainfo = that.data.areajson.provinces.name + '·' + that.data.areajson.citys.name + '·' + areas that.setdata({ areainfo: areainfo, }) }) }) }) }, // 点击所在地区弹出选择框 select: function(e) { // 如果已经显示,不在执行显示动画 if (this.data.addressmenuisshow) { return false } else { // 执行显示动画 this.startaddressanimation(true) } }, // 处理省市县联动逻辑 citychange: function(e) { // console.log(this.data.provinces) var value = e.detail.value var provinces = this.data.provinces var citys = this.data.citys var areas = this.data.areas var provincenum = value[0] var citynum = value[1] var countynum = value[2] var that = this; // console.log(provinces) // 如果省份选择项和之前不一样,表示滑动了省份,此时市默认是省的第一组数据, if (this.data.value[0] != provincenum) { var id = provinces[provincenum].id // console.log(citys[citynum]) util.getareareq(provinces[provincenum].code).then(citys => { util.getareareq(citys[0].code).then(areas => { this.setdata({ value: [provincenum, 0, 0], citys: citys, areas: areas, areajson: { provinces: { id: provinces[provincenum].code, name: provinces[provincenum].area }, citys: { id: citys[0].code, name: citys[0].area }, areas: { id: areas.length > 0 ? areas[0].code : null, name: areas.length > 0 ? areas[0].area : null, } } }) }) }) } else if (this.data.value[1] != citynum) { // 滑动选择了第二项数据,即市,此时区显示省市对应的第一组数据 var id = citys[citynum].id util.getareareq(citys[citynum].code).then(areas => { this.setdata({ value: [provincenum, citynum, 0], areas: areas, areajson: { provinces: { id: provinces[provincenum].code, name: provinces[provincenum].area }, citys: { id: citys[citynum].code, name: citys[citynum].area }, areas: { id: areas.length > 0 ? areas[0].code : null, name: areas.length > 0 ? areas[0].area : null, } } }) }) } else { // 滑动选择了区 this.setdata({ value: [provincenum, citynum, countynum], areajson: { provinces: { id: provinces[provincenum].code, name: provinces[provincenum].area }, citys: { id: citys[citynum].code, name: citys[citynum].area }, areas: { id: areas[countynum].code, name: areas[countynum].area } } }) // console.log(that.data.areajson) } }, // 执行动画 startaddressanimation: function(isshow) { if (isshow) { // vh是用来表示尺寸的单位,高度全屏是100vh this.animation.translatey(0 + 'vh').step() } else { this.animation.translatey(40 + 'vh').step() } this.setdata({ animationaddressmenu: this.animation.export(), addressmenuisshow: isshow, }) }, // 点击地区选择取消按钮 citycancel: function(e) { this.startaddressanimation(false) }, // 点击地区选择确定按钮 citysure: function(e) { var that = this var city = that.data.city var value = that.data.value this.startaddressanimation(false) // console.log(that.data.areajson) var areas = that.data.areajson.areas.name == null ? "" : that.data.areajson.areas.name // 将选择的城市信息显示到输入框 var areainfo = that.data.areajson.provinces.name + '·' + that.data.areajson.citys.name + '·' + areas that.setdata({ areainfo: areainfo, }) }, onhide: function() { // 页面隐藏 }, onunload: function() { // 页面关闭 } });
- 需要使用外部js(utils) 自己封装的一个工具
var api = require('../config/api.js'); var app = getapp(); var user = require('./user.js'); /** * 封装微信的的request */ function request(url, data = {}, method = "get") { return new promise(function(resolve, reject) { user.checklogin().then(res => { }).catch(() => { wx.switchtab({ url: '/pages/ucenter/index/index?show=true' }); }); wx.request({ url: url, data: data, method: method, header: { 'content-type': 'application/x-www-form-urlencoded', 'cookie': "token=" + wx.getstoragesync('token') + ";" + wx.getstoragesync('sessionid'), 'x-requested-with': "xmlhttprequest" }, success: function(res) { if (res.statuscode == 400) { user.loginbyweixin().then(res => { app.globaldata.haslogin = true; }); wx.redirectto({ url: '/pages/index/index' }); wx.showtoast({ title: '已经重新登录', }) } if (res.header["set-cookie"]) { wx.setstoragesync("sessionid", res.header["set-cookie"]) } if (res.statuscode == 200) { if (res.data.errno == 501) { } else { resolve(res); } } else { reject(res); } }, fail: function(err) { reject(err) } }) }); } function getareareq(id) { const that = this; return new promise(function(resolve, reject) { that.request("****", json.stringify({ }), "post").then(response => { console.log(response.data.rs_data) resolve(response.data.rs_data); }) }) } module.exports = { request, getareareq };
- 使用静态获取的时候。js如下
var util = require('../../../utils/util.js'); var api = require('../../../config/api.js'); var area = require('../../../config/area.js'); var app = getapp(); page({ data: { address: { id: 0, provinceid: 0, cityid: 0, areaid: 0, address: '', name: '', mobile: '', isdefault: 0, provincename: '', cityname: '', areaname: '' }, addressid: 0, openselectregion: false, regiontype: 1, selectregiondone: false, szxqlist: [], szxq: { id: "", name: "请选择小区" }, szdslist: [], szds: { id: "", name: "" }, fanghao: "", animationaddressmenu: {}, addressmenuisshow: false, value: [0, 0, 0], provinces: [], citys: [], areas: [], areainfo: '', areajson: {} }, bindinputmobile(event) { let address = this.data.address; address.mobile = event.detail.value; this.setdata({ address: address }); }, bindinputname(event) { let address = this.data.address; address.name = event.detail.value; this.setdata({ address: address }); }, bindinputaddress(event) { let address = this.data.address; address.address = event.detail.value; this.setdata({ address: address }); }, bindisdefault() { let address = this.data.address; address.isdefault = !address.isdefault; this.setdata({ address: address }); }, getaddressdetail() { let that = this; util.request(api.addressdetail, { id: that.data.addressid }).then(function(res) { if (res.errno === 0) { if (res.data) { that.setdata({ address: res.data }); } } }); }, wxchooseaddress() { let that = this; let address = this.data.address; // 用户已经同意小程序使用地址功能 wx.chooseaddress({ success: function(res) { address.provinceid = 99999; address.cityid = 88888; address.areaid = 77777; address.name = res.username; address.mobile = res.telnumber; address.provincename = res.provincename; address.cityname = res.cityname; address.areaname = res.countyname; address.address = res.provincename + res.cityname + res.countyname + res.detailinfo; that.setdata({ address: address, }); } }); }, wxaddress() { let that = this; // 可以通过 wx.getsetting 先查询一下用户是否授权了 "scope.address" 这个 scope wx.getsetting({ success(res) { if (!res.authsetting['scope.address']) { wx.authorize({ scope: 'scope.address', success() { that.wxchooseaddress(); } }) } else { that.wxchooseaddress(); } } }) }, onload: function(options) { let that = this; // 页面初始化 options为页面跳转所带来的参数 console.log(options); if (options.id && options.id != 0) { this.setdata({ addressid: options.id }); this.getaddressdetail(); } else { that.wxaddress(); } }, onready: function() { }, canceladdress() { wx.navigateback(); }, saveaddress() { console.log(this.data.address); let address = this.data.address; if (address.name == '') { util.showerrortoast('请输入姓名'); return false; } if (address.mobile == '') { util.showerrortoast('请输入手机号码'); return false; } if (address.areaid == 0) { util.showerrortoast('请输入省市区'); return false; } if (address.address == '') { util.showerrortoast('请输入详细地址'); return false; } if (!check.isvalidphone(address.mobile)) { util.showerrortoast('手机号不正确'); return false; } }, onshow: function() { // 获取所在栋数 var animation = wx.createanimation({ duration: 500, timingfunction: 'linear', }) this.animation = animation util.request("https://www.xaibox.com/czbb/interface/datainfo.php", json.stringify({ "param_key": { "info_mode": "getcity_jd" }, "secret_key": "047709aaa7df22205d818bf4c1707458" }), "post").then(response => { console.log(response) that.setdata({ szxqlist: response.data.rs_data }) that.setdata({ szxq: response.data.data[0] }) that.setdata({ szds: response.data.data[0]['buildinglist']['0'] }) that.setdata({ szdslist: response.data.data[0]['buildinglist'] }) }) // 获取所在地区 that.setdata({ provinces: areajs, citys: areajs[0].children, areas: areajs[0].children ? areajs[0].children[0].children : [], areajson: { provinces: { id: 40, name: "广东省" }, citys: { id: 4006, name: "河源市" }, areas: { id: 400602, name: "源城区" } } }) var areas = that.data.areajson.areas.name == null ? "" : that.data.areajson.areas.name var areainfo = that.data.areajson.provinces.name + '·' + that.data.areajson.citys.name + '·' + areas that.setdata({ areainfo: areainfo, }) }, // 点击所在地区弹出选择框 select: function(e) { // 如果已经显示,不在执行显示动画 if (this.data.addressmenuisshow) { return false } else { // 执行显示动画 this.startaddressanimation(true) } }, // 处理省市县联动逻辑 citychange: function(e) { // console.log(this.data.provinces) var value = e.detail.value var provinces = this.data.provinces var citys = this.data.citys var areas = this.data.areas var provincenum = value[0] var citynum = value[1] var countynum = value[2] var that = this; // console.log(provinces) // 如果省份选择项和之前不一样,表示滑动了省份,此时市默认是省的第一组数据, if (this.data.value[0] != provincenum) { var id = provinces[provincenum].id // console.log(citys[citynum]) this.setdata({ value: [provincenum, 0, 0], citys: provinces[provincenum].children, areas: provinces[provincenum].children ? provinces[provincenum].children[0].children : [], areajson: { provinces: { id: provinces[provincenum].code, name: provinces[provincenum].area }, citys: { id: provinces[provincenum].children[0].code, name: provinces[provincenum].children[0].area }, areas: { id: citys[citynum].children.length > 0 ? citys[citynum].children[0].code : null, name: citys[citynum].children.length > 0 ? citys[citynum].children[0].area : null } } }) } else if (this.data.value[1] != citynum) { // 滑动选择了第二项数据,即市,此时区显示省市对应的第一组数据 var id = citys[citynum].id this.setdata({ value: [provincenum, citynum, 0], areas: citys[citynum].children, areajson: { provinces: { id: provinces[provincenum].code, name: provinces[provincenum].area }, citys: { id: citys[citynum].code, name: citys[citynum].area }, areas: { id: citys[citynum].children.length > 0 ? citys[citynum].children[0].code : null, name: citys[citynum].children.length > 0 ? citys[citynum].children[0].area : null } } }) } else { // 滑动选择了区 this.setdata({ value: [provincenum, citynum, countynum], areajson: { provinces: { id: provinces[provincenum].code, name: provinces[provincenum].area }, citys: { id: citys[citynum].code, name: citys[citynum].area }, areas: { id: areas[countynum].code, name: areas[countynum].area } } }) // console.log(that.data.areajson) } }, // 执行动画 startaddressanimation: function(isshow) { if (isshow) { // vh是用来表示尺寸的单位,高度全屏是100vh this.animation.translatey(0 + 'vh').step() } else { this.animation.translatey(40 + 'vh').step() } this.setdata({ animationaddressmenu: this.animation.export(), addressmenuisshow: isshow, }) }, // 点击地区选择取消按钮 citycancel: function(e) { this.startaddressanimation(false) }, // 点击地区选择确定按钮 citysure: function(e) { var that = this var city = that.data.city var value = that.data.value this.startaddressanimation(false) // console.log(that.data.areajson) var areas = that.data.areajson.areas.name == null ? "" : that.data.areajson.areas.name // 将选择的城市信息显示到输入框 var areainfo = that.data.areajson.provinces.name + '·' + that.data.areajson.citys.name + '·' + areas that.setdata({ areainfo: areainfo, }) }, onhide: function() { // 页面隐藏 }, onunload: function() { // 页面关闭 } });
- 静态获取三级联动 的话则需要文件点击下载