微信小程序实现省市区三级地址选择

国际惯例先上效果图:

省市区三级联动,选择省自动刷新市,选择市自动刷新区,点击取消自动返回上一级重新选择,点击确定,保存地址。

数据库

这份数据库是某天在网上逛到的,当时未记录出处,直接贴出给读者使用,实在不妥,此处仅贴出表结构,方便大家交流学习。如有读者了解此份数据出处,烦请留言,谢谢!

数据表结构如下:

部分使用到的字段信息:

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

回到顶部