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

国际惯例先上效果图:

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

数据库

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

数据表结构如下:

部分使用到的字段信息:

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
}

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

(0)

相关推荐

  • python实现扫描ip地址的小程序

    python实现扫描ip地址的小程序,具体代码如下所示: import os,time import sys start_Time=int(time.time()) ip_True = open('ip_True.txt','w+') ip_False = open('ip_False.txt','w+') IPhost = [] IPbegin = (input(u'请输入起始查询IP: ')) IPend = input(u'请输入终止查询IP: ') IP1 = IPbegin.split

  • 微信小程序 可搜索的地址选择实现详解

    这篇文章主要介绍了微信小程序 可搜索的地址选择实现详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 最终实现效果: 效果实现步骤 新建index文件夹 index.wxml <!--pages/index/index.wxml--> <view class='container'> <view bindtap='onChangeAddress'> <input value="{{address}}&q

  • 微信小程序三级联动地址选择器的实例代码

    本文介绍了微信小程序三级联动地址选择器的实例代码,分享给大家,有需要的可以一起了解一下 在一些电商类的小程序中,地址选择这个功能一般是必备的,一般的收货信息都需要有一个能选择省市县的控件,当然也有些人为了省事就直接写了一个供输入的input,那么这样做的缺点不言而喻,而且用户体验也不是那么的好,今天的这篇文章就分享一下微信小程序地址选择的实现.省市县的数据以及区域码可以从国家统计局查询到,具体可以自己搜一下.照例先上源码和效果图 源码传送门 picker和picker-view组件 在正式介绍实

  • 微信小程序实现获取准确的腾讯定位地址功能示例

    本文实例讲述了微信小程序实现获取准确的腾讯定位地址功能.分享给大家供大家参考,具体如下: 官方参考文档:https://lbs.qq.com/qqmap_wx_jssdk/index.html 逆地址解析(坐标位置描述) 1. 申请开发者密钥(key)与设置 个人使用:登录,点击"key管理",进入设置,选择"WebServiceAPI",如果没有小程序ID,勾选"授权IP",如果有小程序ID,勾选"域名白名单",且勾选&qu

  • mpvue构建小程序的方法(步骤+地址)

    mpvue是一个使用Vue.js开发小程序的前端框架(美团的开源项目).框架基于Vue.js核心,mpvue修改了Vue.js的 runtime 和 compiler 实现,使其可以运行在小程序环境中,从而为小程序开发引入了整套Vue.js开发体验. mpvue你可以使用你熟悉的vue框架语法,双向绑定让你不用再使用wx的this.setData了,你可以使用npm方便的引入第三方了,真的是贫穷限制了我的想象力啊.个人感觉mpvue比wepy更加简单,上手更加方便,mpuve五分钟教程快速构建.

  • 微信小程序 ecshop地址三级联动实现实例代码

    微信小程序 ecshop地址3级联动实现实例代码 picker标签,官方给出的实例: <view class="section"> <view class="section__title">地区选择器</view> <picker bindchange="bindPickerChange" value="{{index}}" range="{{array}}">

  • 微信小程序如何获取用户收货地址

    获取用户收货地址需要用户点击授权,所以有两种情况,确认授权.取消授权. 情况一,用户第一次访问用户地址授权,并且点击确定授权. 情况二,用户点击取消授权后,再次获取授权 流程: (代码逻辑整理) 1.点击事件触发函数,获取用户当前设置 2.根据用户当前设置中的用户授权结果,判断是否包含收货地址授权 3.如果包含收货地址授权并且没有取消过收货地址授权,直接调用wx.chooseAddress(),获取用户收货地址. 4.取消过收货地址授权,调用wx.openSetting(),调起客户端小程序设置

  • 微信小程序开发实现的IP地址查询功能示例

    本文实例讲述了微信小程序开发实现的IP地址查询功能.分享给大家供大家参考,具体如下: 微信小程序 开发 参考   https://mp.weixin.qq.com/debug/wxadoc/dev/component/ search.wxml <view class="container"> <view class="page-body"> <view class="weui-search-bar {{searchFocusC

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

    国际惯例先上效果图: 省市区三级联动,选择省自动刷新市,选择市自动刷新区,点击取消自动返回上一级重新选择,点击确定,保存地址. 数据库 这份数据库是某天在网上逛到的,当时未记录出处,直接贴出给读者使用,实在不妥,此处仅贴出表结构,方便大家交流学习.如有读者了解此份数据出处,烦请留言,谢谢! 数据表结构如下: 部分使用到的字段信息: id:唯一标识每一个数据 name:地区名 parent_id:上级地区的id,若parent_id = 0 ,表示无上级信息,当前即为最高行政区. extra:主要

  • 支付宝小程序实现省市区三级联动

    本文实例为大家分享了支付宝小程序实现省市区三级联动的具体代码,供大家参考,具体内容如下 背景 最近做的项目 有省市区联动.不仅要传name还要把对应的id发给后台. 支付宝提供的级联有 my.multiLevelSelect和picker并不能满足需求. picker 组件不支持多列选择,所以使用 picker-view 组件和Popup配合使用. 实现效果图 数据结构 citys - 城市 areas - 区 当然这是处理之后的,行政区划树 不长这样子. [{ code:1, name:'北京

  • 微信小程序实现收货地址左滑删除

    本文实例为大家分享了微信小程序实现收货地址左滑删除的具体代码,供大家参考,具体内容如下 效果: 思路: 一.用相对定位和绝对定位,列表放在上层,删除按钮放在下层(z-index不要为负). 二.触摸事件判断用户是否左滑,有 bindtouchstart,bindtouchmove,bindtouchend 三个触摸事件. 1.bindtouchstart 记录触摸开始的点.开始点的坐标在 e.touches[0] 中,这是相对于屏幕的,也就是以屏幕左上方为原点. 2.bindtouchmove 

  • 微信小程序实现商品属性联动选择

    本文实例为大家分享了微信小程序实现商品属性联动选择的具体代码,供大家参考,具体内容如下 效果演示: 代码示例 1.commodity.xml <!-- <view class="title">属性值联动选择</view> --> <!--options--> <view class="commodity_attr_list"> <!--每组属性--> <view class="a

  • 微信小程序实现按字母排列选择城市功能

    实现效果预览 实现思想 利用小程序腾讯地图将所有城市查出来,并将其渲染至页面(https://lbs.qq.com/qqmap_wx_jssdk/index.html)(其中字母栏也根据获取到的数据变化) 其中涉及三个交互(点击字母时滚动到相应位置:滑动触摸字母时,需滚动到相应位置,并有当前哪个字母的提示,且有震动感:手动滑动页面时,需将当前对应的字母选中) 滑动触摸字母时,首先要得到所有字母所在块的高度,再平均的获取到每个字母的高度.当触摸滚动时,拿到pageY(距离文档左上角的距离,具体解释

  • 微信小程序实现循环嵌套数据选择

    本文实例为大家分享了微信小程序实现循环嵌套数据选择的具体代码,供大家参考,具体内容如下 一.效果展示 二.代码实现 在.wxml文件中,有时从后台传来的数据可能会出现数组嵌套数组的情况,需要利用wx:for嵌套实现数据的展示.这时,外层循环正常循环,内层循环需要利用wx:for-item将item重新命名. <scroll-view scroll-y class="scrollTime">     <view          class="dateItem

  • 微信小程序实现选择内容显示对应内容

    微信小程序中,经常可见选择地区或者商品分类或者其他的分类,选择后显示,选择后删除 先介绍一下主要功能:点击 ‘地区’ ,下面选择区域出现,点击 ‘选择地区’ 中的按钮,上面 ‘已选地区’ 显示选择的地区,点击 ‘x’ 已选的地区就取消,点击 “完成” 整个选择区域隐藏,只留下地区. 整体样式用的弹性布局,就不细说了. wxml: <view class="container">   <text bindtap="show" class="

  • 微信小程序tabBar用法实例详解

    本文实例讲述了微信小程序tabBar用法.分享给大家供大家参考,具体如下: 1.效果展示 2.原理:在app.json中配置tabBar属性 { "pages": [ "index", "picDisplay" ], "window": { "navigationBarBackgroundColor": "#ffffff", "navigationBarTextStyle&qu

随机推荐