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


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 播放器 控制
Jan 22 Javascript
JS实现淘宝幻灯片效果的实现方法
Mar 22 Javascript
javascript编写实用的省市选择器
Feb 12 Javascript
利用BootStrap弹出二级对话框的简单实现方法
Sep 21 Javascript
浅谈jQuery中的$.extend方法来扩展JSON对象
Feb 12 Javascript
Angular JS 生成动态二维码的方法
Feb 23 Javascript
js实现不提示直接关闭网页窗口
Mar 30 Javascript
Node.js 使用request模块下载文件的实例
Sep 05 Javascript
ES6知识点整理之函数对象参数默认值及其解构应用示例
Apr 17 Javascript
详解Vscode中使用Eslint终极配置大全
Nov 08 Javascript
详解钉钉小程序组件之自定义模态框(弹窗封装实现)
Mar 07 Javascript
JS Thunk 函数的含义和用法实例总结
Apr 08 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中生成UUID自定义函数分享
2015/06/10 PHP
php实现的简易扫雷游戏实例
2015/07/09 PHP
php+ajax 文件上传代码实例
2019/03/18 PHP
学习ExtJS TextField常用方法
2009/10/07 Javascript
js实现图片放大和拖拽特效代码分享
2015/09/05 Javascript
使用jQuery mobile库检测url绝对地址和相对地址的方法
2015/12/04 Javascript
Bootstrap每天必学之折叠(Collapse)插件
2016/04/25 Javascript
JavaScript正则表达式exec/g实现多次循环用法示例
2017/01/17 Javascript
详解Vue.js分发之作用域槽
2017/06/13 Javascript
利用require.js与angular搭建spa应用的方法实例
2017/07/19 Javascript
初探JavaScript 面向对象(推荐)
2017/09/03 Javascript
JavaScript数组方法的错误使用例子
2018/09/13 Javascript
vue 实现边输入边搜索功能的实例讲解
2018/09/16 Javascript
使用vue根据状态添加列表数据和删除列表数据的实例
2018/09/29 Javascript
javascript实现考勤日历功能
2018/11/29 Javascript
用原生 JS 实现 innerHTML 功能实例详解
2019/04/03 Javascript
angular4+百分比进度显示插件用法示例
2019/05/05 Javascript
Vue.js项目实战之多语种网站的功能实现(租车)
2019/08/07 Javascript
JavaScript常用工具函数汇总(浏览器环境)
2020/09/17 Javascript
Vue开发中常见的套路和技巧总结
2020/11/24 Vue.js
Linux中Python 环境软件包安装步骤
2016/03/31 Python
Python获取linux主机ip的简单实现方法
2016/04/18 Python
python中文分词教程之前向最大正向匹配算法详解
2017/11/02 Python
python set内置函数的具体使用
2019/07/02 Python
简单瞅瞅Python vars()内置函数的实现
2019/09/27 Python
wxPython电子表格功能wx.grid实例教程
2019/11/19 Python
使用Tkinter制作信息提示框
2020/02/18 Python
Anaconda+VSCode配置tensorflow开发环境的教程详解
2020/03/30 Python
荷兰家电销售网站:Welhof
2020/12/08 全球购物
美国乒乓球设备、配件和服装品牌:Killerspin
2020/06/07 全球购物
Yahoo-PHP面试题2
2014/12/06 面试题
预备党员2014全国两会学习心得体会
2014/03/10 职场文书
班训口号大全
2014/06/18 职场文书
教育合作协议范本
2014/10/17 职场文书
大学生国家助学金感谢信
2015/01/23 职场文书
2015年为民办实事工作总结
2015/05/26 职场文书