微信小程序实现省市区三级地址选择
国际惯例先上效果图:
省市区三级联动,选择省自动刷新市,选择市自动刷新区,点击取消自动返回上一级重新选择,点击确定,保存地址。
数据库
这份数据库是某天在网上逛到的,当时未记录出处,直接贴出给读者使用,实在不妥,此处仅贴出表结构,方便大家交流学习。如有读者了解此份数据出处,烦请留言,谢谢!
数据表结构如下:
部分使用到的字段信息:
id:唯一标识每一个数据
name:地区名
parent_id:上级地区的id,若parent_id = 0 ,表示无上级信息,当前即为最高行政区。
extra:主要标识少数民族自治州或者自治县的信息,如:巴音郭楞 蒙古 自治州,此处存储 蒙古
例:
suffix:行政级别 市 省 县 区等
部分地区数据信息如下:
后台
后台仅需提供一个接口,根据parent_id,查询地区信息
此处使用的后台是SSM框架,贴出主要接口、sql
1.与小程序交互接口
@RequestMapping(value = "/getArea", method = RequestMethod.POST)
private @ResponseBody
List<District> getArea(HttpServletRequest request) {
int parentId = Integer.parseInt(request.getParameter("parentId"));
logger.info("getArea");
List<District> list = new ArrayList<District>();
try {
list = districtService.getAreas(parentId);
} catch (Exception e) {
}
return list;
}
2.查询sql
<select id="getAreas" resultType="District">
<!-- 具体的sql -->
SELECT
id,concat(name,extra,suffix) as name,parent_id as parentId
FROM
district
WHERE
parent_id = #{parentId}
</select>
前端
先贴出css:
.hotCity {
padding-right: 50rpx;
margin: auto;
}
.weui-grid {
padding: 10rpx 0;
width: 160rpx;
box-sizing: border-box;
border: 1rpx solid #ececec;
border-radius: 8rpx;
background-color: white;
margin: 8rpx 0;
}
.weui-grids {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.weui-grid__label {
display: block;
text-align: center;
color: #333;
font-size: 30rpx;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.county {
display: flex;
flex-wrap: wrap;
margin-top: 30px;
margin-left: 15px;
}
/** 头部css **/
.headTitle{
display: flex;
}
.headButton{
background: #f68135;
border-radius: 25rpx;
border: 1px solid #f68135;
color: #fff;
height: 80rpx;
line-height: 80rpx;
margin: 0 auto;
width: 150rpx;
font-size: 45rpx;
text-align: center;
padding:0px;
vertical-align:middle ;
}
html
html仅由两部分组成:
头部:确定、取消按钮,显示当前选择地址信息
确定取消主要绑定了两个方法:submitChoose 及 cancleChoose 两个方法,点击不同按钮,执行不同js方法。
显示当前地址信息:finalCity,只要在js中使用setData设置该值,该值就会动态改变。
city:显示当前可选的地区
使用block组件,对json数组areaList进行循环显示,同样,使用setData设置该值,该值就会动态改变,达到省市区联动选择的效果。每一个小地区控件,有bindArea方法,并且在用户选择该地区,执行bindArea方法时,使用data-数据名的方法,向后台传递用户选择数据。
<view class="headTitle">
<button class="headButton" bindtap="cancleChoose">取消</button>
<view>{{finalCity == "" ? "请选择地址" : finalCity}}</view>
<button class="headButton" bindtap="submitChoose">确定</button>
</view>
<view class="county">
<block class="hotCity" wx:for-items="{{areaList}}" wx:key="id">
<view class="weui-grid" style="margin-right: 16rpx;" data-parentId="{{item.parentId}}" data-id="{{item.id}}" data-city="{{item.name}}" bindtap="bindArea">
<view class="weui-grid__label">{{item.name}}</view>
</view>
</block>
</view>
js:
// pages/chooseCity/chooseCity.js
//获取应用实例
const model = require('../cityChoose/cityChoose.js')
const config = require('../../utils/config.js')
const util = require('../../utils/util.js')
const app = getApp();
//记录省市区
var nav = 0;
var chooseCity = new Array(3);
//记录每一次的parentId
var finalParentId = new Array(3);
var flag = 0;
Page({
/**
* 页面的初始数据
*/
data: {
finalCity:"",
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function(options) {
//parentId = 0 取所有省份数据
var that = this;
that.getData(0);
chooseCity = new Array("","","");
finalParentId = new Array(0,0,0);
nav = 0;
},
submitChoose:function(e){
if(flag != 1){
util.showLog("请选择完整地址")
return;
}else{
var address_components = { "province": "", "city": "", "district": ""};
address_components["province"] = chooseCity[0];
address_components["city"] = chooseCity[1];
address_components["district"] = chooseCity[2];
console.log(address_components);
app.globalData.address_components = address_components;
wx.navigateBack();
}
},
cancleChoose:function(e){
console.log(finalParentId);
var that = this;
if(nav == 0){
wx.navigateBack();
} else {
nav = nav - 1;
chooseCity[nav] = "";
console.log(chooseCity);
that.setData({
finalCity: chooseCity[0] + chooseCity[1] + chooseCity[2]
})
that.getData(finalParentId[nav]);
}
},
bindArea: function(e) {
if(flag == 0){
console.log(e);
var that = this;
var parentId = e.currentTarget.dataset.id;
var city = e.currentTarget.dataset.city;
that.getData(parentId);
chooseCity[nav] = city;
finalParentId[nav] = e.currentTarget.dataset.parentid;
nav++;
console.log(chooseCity)
that.setData({
finalCity:chooseCity[0]+chooseCity[1]+chooseCity[2]
})
}
},
getData(parentId) {
var that = this;
var url = config.getArea + "?parentId=" + parentId;
wx.request({
url: url,
success: (res) => {
console.log("地区数据请求成功");
console.log(res)
if (res.data.length != 0) {
flag = 0;
//设置数据到全局变量
that.setData({
areaList: res.data,
});
}else{
//防止用户再次点击;
flag = 1;
}
},
method: "POST",
header: {
"content-type": "application/x-www-form-urlencoded;charset=utf-8",
},
fail: (res) => {
console.log("地区数据请求失败");
}
})
},
})
js解析
全局变量作用:
//记录用户已选择层次
var nav = 0;
//记录省市区三级数据
var chooseCity = new Array(3);
//记录每一次的parentId,主要记录用户选择路径,取消时根据用户路径显示上一级数据
var finalParentId = new Array(3);
//记录是否已经到最底层,再无数据可以选择
var flag = 0;
执行过程:
进入页面执行onLoad生命周期函数,在onLoad中调用getData初始化数据,及默认显示行政级别为省的数据,即请求parent_id为0的数据
getData:
getData(parentId) {
var that = this;
//请求的url,由后台决定,此处填入你的请求url即可
var url = config.getArea + "?parentId=" + parentId;
wx.request({
url: url,
success: (res) => {
console.log("地区数据请求成功");
console.log(res)
if (res.data.length != 0) {
flag = 0;
//设置数据到全局变量
that.setData({
areaList: res.data,
});
}else{
//已到最后一层数据
flag = 1;
}
},
method: "POST",
header: {
"content-type": "application/x-www-form-urlencoded;charset=utf-8",
},
fail: (res) => {
console.log("地区数据请求失败");
}
})
},
点击地区数据执行bindArea
bindArea: function(e) {
//如果未到最后一层,即可向下执行
if(flag == 0){
console.log(e);
var that = this;
//获取html传参,获取用户点击信息
var parentId = e.currentTarget.dataset.id;
var city = e.currentTarget.dataset.city;
//根据用户点击的数据,传入当前的id作为下一层的parentId,请求下一层数据,
that.getData(parentId);
//记录用户选择
chooseCity[nav] = city;
//用户点击取消,到此层时,需要使用当前的parientid来请求此层应显示的数据
finalParentId[nav] = e.currentTarget.dataset.parentid;
//记录路径数+1
nav++;
console.log(chooseCity)
//更新用户选择地区显示
that.setData({
finalCity:chooseCity[0]+chooseCity[1]+chooseCity[2]
})
}
},
点击取消,执行方法cancleChoose
cancleChoose:function(e){
var that = this;
//已是最后一层,则返回上一页
if(nav == 0){
wx.navigateBack();
} else {
//记录路径数-1
nav = nav - 1;
//将上次已选择的地区清空
chooseCity[nav] = "";
console.log(chooseCity);
//更新选择数据
that.setData({
finalCity: chooseCity[0] + chooseCity[1] + chooseCity[2]
})
//根据finalParent中记录的每一层应请求的数据来更新地区数据
that.getData(finalParentId[nav]);
}
},
点击确定,执行方法submitChoose
submitChoose:function(e){
//如果未到最后一层,表示地址未选择完,如果不需要选择完整地址,此处去掉即可
if(flag != 1){
util.showLog("请选择完整地址")
return;
}else{
//存储数据到全局变量中,采用了json的方式存储,可以分别存储省市区数据
var address_components = { "province": "", "city": "", "district": ""};
address_components["province"] = chooseCity[0];
address_components["city"] = chooseCity[1];
address_components["district"] = chooseCity[2];
console.log(address_components);
app.globalData.address_components = address_components;
//返回上一次页面
wx.navigateBack();
}
},
谢谢大家查看,评论里希望贴出cityChoose.js 及 util.js ,在下面贴出来啦,注:util.js里不是所有方法都要用到。
希望能够帮助到大家。
cityChoose
// pages/chooseCity/chooseCity.js
//获取应用实例
const model = require('../cityChoose/cityChoose.js')
const config = require('../../utils/config.js')
const util = require('../../utils/util.js')
const app = getApp();
//记录省市区
var nav = 0;
var chooseCity = new Array(3);
//记录每一次的parentId
var finalParentId = new Array(3);
//记录是否到最后一级
var flag = 0;
Page({
/**
* 页面的初始数据
*/
data: {
finalCity:"",
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function(options) {
//parentId = 0 取所有省份数据
var that = this;
that.getData(0);
chooseCity = new Array("","","");
finalParentId = new Array(0,0,0);
nav = 0;
},
submitChoose:function(e){
if(flag != 1){
util.showLog("请选择完整地址")
return;
}else{
var address_components = { "province": "", "city": "", "district": ""};
address_components["province"] = chooseCity[0];
address_components["city"] = chooseCity[1];
address_components["district"] = chooseCity[2];
console.log(address_components);
app.globalData.address_components = address_components;
wx.navigateBack();
}
},
cancleChoose:function(e){
console.log(finalParentId);
var that = this;
if(nav == 0){
wx.navigateBack();
} else {
nav = nav - 1;
chooseCity[nav] = "";
console.log(chooseCity);
that.setData({
finalCity: chooseCity[0] + chooseCity[1] + chooseCity[2]
})
that.getData(finalParentId[nav]);
}
},
bindArea: function(e) {
if(flag == 0){
console.log(e);
var that = this;
var parentId = e.currentTarget.dataset.id;
var city = e.currentTarget.dataset.city;
//刷新出下一级地址前重复点击
console.log(chooseCity[nav - 1] );
console.log(city);
if(chooseCity[nav-1] == city){
return;
}
that.getData(parentId);
chooseCity[nav] = city;
finalParentId[nav] = e.currentTarget.dataset.parentid;
nav++;
console.log(chooseCity)
that.setData({
finalCity:chooseCity[0]+chooseCity[1]+chooseCity[2]
})
}
},
getData(parentId) {
var that = this;
var url = config.getArea + "?parentId=" + parentId;
wx.request({
url: url,
success: (res) => {
console.log("地区数据请求成功");
console.log(res)
if (res.data.length != 0) {
flag = 0;
//设置数据到全局变量
that.setData({
areaList: res.data,
});
}else{
//防止用户再次点击;
flag = 1;
}
},
method: "POST",
header: {
"content-type": "application/x-www-form-urlencoded;charset=utf-8",
},
fail: (res) => {
console.log("地区数据请求失败");
}
})
},
})
util.js
const formatTime = date => {
const year = date.getFullYear()
const month = date.getMonth() + 1
const day = date.getDate()
const hour = date.getHours()
const minute = date.getMinutes()
const second = date.getSeconds()
return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':')
}
const formatNumber = n => {
n = n.toString()
return n[1] ? n : '0' + n
}
function showLog(e) {
wx.showToast({
title: e,
icon: "none"
})
}
function trim(str) {
return str.replace(/(^\s*)|(\s*$)/g, "");
}
function showLoading() {
wx.showLoading({
title: '加载中',
mask: true
})
}
// 验证码倒计时
function phone_code(t, second) {
// t是this,second是重新发送的间隔时间,需要设置按钮可点击
var s = second;
// 避免重复点击
t.setData({
phone_code_text: s + "s",
phone_code_class: "",
phone_code_buff: true
});
// 倒计时
var clock = setInterval(function () {
if (s > 1) {
t.setData({
phone_code_text: --s + "s"
})
} else {
clearInterval(clock);
t.setData({
phone_code_text: "重新发送",
phone_code_class: "on",
phone_code_buff: false
});
// 重置数据
s = second;
}
}, 1000)
}
function getNowFormatDate() {
var date = new Date();
var seperator1 = "-";
var year = date.getFullYear();
var month = date.getMonth() + 1;
var strDate = date.getDate();
if (month >= 1 && month <= 9) {
month = "0" + month;
}
if (strDate >= 0 && strDate <= 9) {
strDate = "0" + strDate;
}
var currentdate = year + seperator1 + month + seperator1 + strDate;
return currentdate;
}
function checkAndCall(sourceId,recordType,tele,app,config){
console.log(app.globalData.haulUserInfo)
console.log(tele);
if (app.globalData.haulUserInfo == null) {
showLog("正在获取用户数据,请稍后。")
app.Promise.then(function (value) {
console.log(value);
if (value) {
// success
wx.makePhoneCall({
phoneNumber: tele,
success: ph => {
mycall(config, app,recordType, sourceId, function () {
//记录联系次数
})
}
})
} else {
// failure
showLog("注册完成即可联系" + "。。。即将跳转")
setTimeout(function () {
wx.navigateTo({
url: '../registUser/registUser',
})
}, 1000);
}
}).catch(function (error) {
});
} else {
// success
wx.makePhoneCall({
phoneNumber: tele,
success: ph => {
mycall(config,app, recordType, sourceId,function () {
//记录联系次数
})
}
})
}
}
//记录互相联系
function mycall(config,app, recordType, sourceId, callback) {
console.log(typeof (recordType))
var that = this;
wx.request({
url: config.insertRecord,
method: "POST",
data: {
sourceId: sourceId,
userId: app.globalData.haulUserInfo.id,
recordType: recordType
},
header: {
"content-type": "application/x-www-form-urlencoded",
},
success: res => {
if (res.data.success) {
console.log('联系成功');
callback();
} else {
showLog(res.data.error);
}
}
})
}
module.exports = {
formatNumber: formatNumber,
formatTime: formatTime,
phone_code_clock: phone_code,
showLoading: showLoading,
showLog: showLog,
getNowFormatDate: getNowFormatDate,
trim: trim,
mycall: mycall,
checkAndCall: checkAndCall
}
以上是 微信小程序实现省市区三级地址选择 的全部内容, 来源链接: utcz.com/z/318849.html