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


Posted in Javascript onJune 21, 2020

国际惯例先上效果图:

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

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

数据库

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

数据表结构如下:

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

部分使用到的字段信息:

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
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JavaScript中变量提升 Hoisting
Jul 03 Javascript
JavaScript创建对象的方式小结(4种方式)
Dec 17 Javascript
JavaScript中判断数据类型的方法总结
May 24 Javascript
js 判断登录界面的账号密码是否为空
Feb 08 Javascript
完美实现js选项卡切换效果(二)
Mar 08 Javascript
JS实现简单的浮动碰撞效果示例
Dec 28 Javascript
axios+Vue实现上传文件显示进度功能
Apr 14 Javascript
js实现的格式化数字和金额功能简单示例
Jul 30 Javascript
JS常见面试试题总结【去重、遍历、闭包、继承等】
Aug 27 Javascript
JS中FormData类实现文件上传
Mar 27 Javascript
Vue props中Object和Array设置默认值操作
Jul 30 Javascript
解决vue打包报错Unexpected token: punc的问题
Oct 24 Javascript
Vue一次性简洁明了引入所有公共组件的方法
Nov 28 #Javascript
react脚手架如何配置less和ant按需加载的方法步骤
Nov 28 #Javascript
微信小程序仿知乎实现评论留言功能
Nov 28 #Javascript
微信小程序实现评论功能
Nov 28 #Javascript
在 Angular-cli 中使用 simple-mock 实现前端开发 API Mock 接口数据模拟功能的方法
Nov 28 #Javascript
小程序点击图片实现自动播放视频
May 29 #Javascript
django使用channels2.x实现实时通讯
Nov 28 #Javascript
You might like
PHP入门学习的几个不错的实例代码
2008/07/13 PHP
php join函数应用
2011/05/04 PHP
PHP数据流应用的一个简单实例
2012/09/14 PHP
深入解析PHP垃圾回收机制对内存泄露的处理
2013/06/14 PHP
php中Ctype函数用法详解
2014/12/09 PHP
php实现图片局部打马赛克的方法
2015/02/11 PHP
php 批量查询搜狗sogou代码分享
2015/05/17 PHP
给Javascript数组插入一条记录的代码
2007/08/30 Javascript
自定义百度分享的分享按钮
2015/03/18 Javascript
js表单处理中单选、多选、选择框值的获取及表单的序列化
2016/03/08 Javascript
分享12个非常实用的JavaScript小技巧
2016/05/11 Javascript
js阻止默认浏览器行为与冒泡行为的实现代码
2016/05/15 Javascript
AngularJS HTML DOM详解及示例代码
2016/08/17 Javascript
Angularjs结合Bootstrap制作的一个TODO List
2016/08/18 Javascript
让DIV的滚动条自动滚动到最底部的3种方法(推荐)
2016/09/24 Javascript
简单实现Bootstrap标签页
2020/08/09 Javascript
AngularJs定时器$interval 和 $timeout详解
2017/05/25 Javascript
自定义事件解决重复请求BUG的问题
2017/07/11 Javascript
JavaScript门面模式详解
2017/10/19 Javascript
jQuery UI实现动画效果代码分享
2018/08/19 jQuery
vue集成百度UEditor富文本编辑器使用教程
2018/09/21 Javascript
vue使用自定义指令实现拖拽
2021/01/29 Javascript
vue 翻页组件vue-flip-page效果
2020/02/05 Javascript
Python序列操作之进阶篇
2016/12/08 Python
对python csv模块配置分隔符和引用符详解
2018/12/12 Python
python如何导出微信公众号文章方法详解
2020/08/31 Python
CSS3实现任意图片lowpoly动画效果实例
2017/05/11 HTML / CSS
CSS3实现复选框动画特效示例代码
2016/09/27 HTML / CSS
澳大利亚手表品牌:Time IV Change
2018/10/06 全球购物
知识竞赛活动方案
2014/02/18 职场文书
小学生推普周国旗下讲话稿
2014/09/21 职场文书
2014年师德师风自我剖析材料
2014/09/27 职场文书
男人帮观后感
2015/06/18 职场文书
环保主题班会教案
2015/08/13 职场文书
小学班主任教育随笔
2015/08/15 职场文书
Python爬虫入门案例之爬取二手房源数据
2021/10/16 Python