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

国际惯例 上效果图:

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

数据库

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

数据表结构如下:

部分使用到的字段信息:

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
}

猜你喜欢

转载自blog.csdn.net/melon__/article/details/82462566
今日推荐