小程序腾讯地图经纬度及添加地址

379 阅读8分钟

添加地址

效果:

JS代码

const app = getApp();
import Address from "../../api/address.js"

Page({

  /**
   * 页面的初始数据
   */
  data: {
    userName: '',
    mobile: '',
    address: '', // 详细地址
    region: ["", "", ""], // 省市区选择器
    region_id: [0, 0, 0], // 省市区选择器id
    addressId: '',
    location:{},
    isCheck: false,
    districtName:'',
    district:[],
    selectAddress:''//定位地址
  },
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function(options) { 
    this.load(options);
    if (this.data.addressId){ //页面标题控制
      wx.setNavigationBarTitle({
        title: '编辑地址'
      })
    }else{
      wx.setNavigationBarTitle({
        title: '新增地址'
      })
    }
   
  },
  load(options) {
    const {
      status,
      id
    } = options;
    this.setData({
      addressId: id || ''
    })
    if (this.data.addressId) this.getAddressDetail(status); //编辑地址调用
  },
  //保存地址事件
  submit() {
    const msg = this.checkMsg();
    if (msg) {
      app.commonTip(msg);
      return false;
    }
    const data = {
     //略
    }
    
    function cb(msg) {
      app.successTip(msg);
      setTimeout(() => { //返回页面
        wx.navigateBack({ 
          delta: 1
        })
      }, 200);
    }

    if (this.data.addressId) { 
      Address.addressupdate(data).then(res => {
        cb('修改成功');
      })
    } else {
      Address.addressadd(data).then(res => {
        cb('保存成功');
      })
    }
  },
  //编辑地址状态调用事件  
  getAddressDetail(status) {
    const data = {
      status,
      id: this.data.addressId
    }
    Address.getAddressInfo(data).then(res => {
      const {
        provinceId,
        provinceName,
        cityId,
        cityName,
        districtId,
        districtName,
        address,
        latitude,
        longitude,
        selectAddress,
        name,
        phone,
        defaultVal,
      } = res.d[0];
      this.setData({
        address,
        userName: name,
        mobile: phone,
        region: [provinceName, cityName, districtName],
        ['location.lat']:latitude,
        ['location.lng']: longitude,
        selectAddress: selectAddress,
        region_id: [provinceId, cityId, districtId],
        isCheck: defaultVal == 1 ? true : false
      })
    }).catch(err => {
      console.error(err);
    })
  },
   //键盘输入事件:姓名
  handleInputName(e) {
    this.setData({
      userName: e.detail.value
    })
  },
    //数字键盘输入事件
  handleInputMobile(e) {
    this.setData({
      mobile: e.detail.value
    })
  },
     //键盘输入事件:地址
  handleInputAddress(e) {
    this.setData({
      address: e.detail.value
    })
  },
    //一键清空
  handleClearInput(e) {
    const attrName = e.currentTarget.dataset.name;
    this.setData({
      [`${attrName}`]: ''
    })
  },
  // 处理鼠标移入显示一键清除
  hadnleFocus(e) {
    const type = e.type;
    const value = e.detail.value;
    const {
      msg
    } = e.currentTarget.dataset;
    if (type == 'blur') {
      if (!value) app.commonTip(msg);
    }
  },
  hadnleCancel() {
    this.handleIsShowCropper();
    this.clearImageSrc();
  },
   //picker事件:点击触发弹起选择事件
  bindRegionChange(e) {
    const {
      code,
      value
    } = e.detail
    this.setData({
      region: value,
      region_id: code,
      address: '',
      selectAddress: ''
    })
  },
    //校验
  checkMsg() {
    let msg = '';
   //略
    return msg;
  },
  // 默认地址选项
  handleIsCheck(e) {
    if (e.currentTarget.dataset.check == 0) {
      this.setData({
        isCheck: false
      })
    } else {
      this.setData({
        isCheck: true
      })
    }
  },
  //选择地址
  chooseSite() {
    const site = this.data.address;
    const city = this.data.region_id[1];
    const district = this.data.region_id[2];

    if (city && district) {
      wx.navigateTo({
        url: `/pages/map/index?districtName=${district}`,
      })
    } else {
      app.commonTip('请选择省市区')
    }
  },
  // 删除地址
  delSite(e) {
    const id = e.currentTarget.dataset.id
    wx.showModal({
      title: '提示',
      content: '是否删除',
      success: (res) => {
        if (res.confirm) {
          Address.getDeleteAddress(id).then(res => {
            if (res.success) {
              app.successTip('删除成功');
              setTimeout(() => {
                wx.navigateBack({
                  delta: 1
                })
              }, 200)
            }
          }).catch(res => {
            console.log(res)
          })
        } else if (res.cancel) {
          console.log('用户点击取消')
        }
      }
    })
  }
})

WXML代码

<view class='mt20 site'>
  <!-- 名字-->
  <view class='site-v dflex'>
    <input class='flex-1 site-input' placeholder-class='cc' value='{{userName}}' style="font-size:30rpx;font-weight:350;" placeholder='姓名' bindinput='handleInputName' bindfocus="hadnleFocus" bindblur="hadnleFocus"></input>
    <icon class='iconshuruguanbi' data-name='userName' catchtap='handleClearInput' type='clear' size='16' wx:if='{{userName}}'></icon>
  </view>
  <!-- 电话 -->
  <view class='site-v dflex'>
    <input class='flex-1 site-input' placeholder-class='cc' maxlength="13" type='number' placeholder='手机号或固话' value='{{mobile}}' bindinput='handleInputMobile' style="font-size:30rpx;font-weight:350;"></input>
    <icon class='iconshuruguanbi' data-name='mobile' catchtap='handleClearInput' type='clear' size='16' wx:if='{{mobile}}'></icon>
  </view>
  <!-- 省市区 -->
  <view class='site-v dflex' style="padding:35rpx 0rpx;">
    <picker class='flex-1 site-sex {{region[0]?"":"cc"}}' mode="region" bindchange="bindRegionChange" value="{{region}}">
      <text wx:if="{{region[0]}}" style="font-size:30rpx;font-weight:350;"> {{region[0]}} {{region[1]}} {{region[2]}}</text>
      <text wx:else style="font-size:30rpx;font-weight:350;">请选择省市区</text>
      <icon class='iconfont iconenter site-icon'></icon>
    </picker>
  </view>
  <!-- 定位 -->
  <view class='site-v dflex' style="padding:25rpx 0rpx;">
    <view class="detail">
      <view class="detail-up">
        <view class="detail-icon" bindtap='chooseSite'>
          <image src="https://file.baimipay.cn/location.png"></image>
        </view>
        <view class="detail-textarea rel">
        <view wx:if="{{!selectAddress}}" class='main-input cc' bindtap='chooseSite' style="font-size:30rpx;font-weight:350;">请选择定位</view>
          <!-- <textarea wx:else bindtap='chooseSite' auto-height value='{{selectAddress}}' disabled="true" style="font-size:30rpx;margin-top:-20rpx;"></textarea> -->
          <view wx:else bindtap='chooseSite' auto-height disabled="true" style="font-size:30rpx;">{{selectAddress}}</view>
        </view>
      </view>
    </view>
  </view>
  <!-- 详细地址 -->
  <view class='site-v dflex no-bot'>
    <textarea bindinput="handleInputAddress" style="height:150rpx;" class='flex-1 site-input' placeholder-class='cc' value='{{address}}' placeholder='请填写详细地址、至少5个字' bindfocus="hadnleFocus" bindblur="hadnleFocus" maxlength="60" ></textarea>
    <icon class='iconshuruguanbi' data-name='address' catchtap='handleClearInput' type='clear' size='16' wx:if='{{address}}'></icon>
    <view class="textarea-length-tip">
      <text style="color:red;" class='{{address.length?"col-f40":""}}'>{{address.length?address.length:"0"}}</text>/60
    </view>
  </view>
</view>
<view>
  <text class="detail-tip">请确保定位与填写的地址为同一位置</text>
</view>
<!-- 默认选项 -->
<view class='check clearfix'>
  <checkbox wx:if="{{!isCheck}}" color="#fff" class='left' bindtap='handleIsCheck' checked="{{isCheck}}" data-check='1'></checkbox>
  <checkbox wx:else color="#fff" class='left' bindtap='handleIsCheck' checked="{{isCheck}}" data-check='0'></checkbox>
  <view class='check-right left'>默认地址</view>
</view>
<!-- 按钮 -->
<view class="site-btn">
  <button class='btn save' bindtap='submit'>保存</button>
  <button class='btn del' wx:if="{{addressId}}" data-id="{{addressId}}" bindtap='delSite'>删除地址</button>
</view>

WXSS代码

.site {
  /* padding: 0 32rpx; */
  background: #fff;
}

.site-v {
  position: relative;
  padding: 29rpx 0;
  border-bottom: 1rpx solid #e8e9ea;
}

.site-input {
  margin-left: 30rpx;
  width:80%;
  text-align: left;
  height: 52rpx;
  line-height: 52rpx;
  font-size: 30rpx;
  box-sizing: border-box;
}

.no-bot {
  border-bottom: none;
}

.site-l {
  height: 52rpx;
  font-size: 30rpx;
  font-weight: 400;
  line-height: 52rpx;
}

.site-sex {
  padding-right: 30rpx;
  /* display: flex; */
  align-items: center;
  justify-content: flex-end;
  box-sizing: border-box;
  font-size: 30rpx;
  text-align: left;
  font-weight: 400;
  margin-left: 30rpx;
}

.site-tx {
  padding-right: 70rpx;
  box-sizing: border-box;
  font-size: 28rpx;
  line-height: 40rpx;
  display: flex;
  display: -webkit-flex;
  align-items: center;
  min-height: 40px;
  max-height: 100rpx;
}

.site-icon {
  position: absolute;
  top: 50%;
  right: 0;
  transform: translateY(-50%) rotate(90deg);
  line-height: 90rpx;
  font-size: 24rpx;
  color: #000;
  margin-right: 32rpx;
}

.site-a {
  position: relative;
  min-height: 40rpx;
  padding: 29rpx 0;
}

.font30 {
  padding-right: 0;
  padding-left: 129rpx;
  font-size: 30rpx;
  font-weight: 400;
}

.address-icon {
  position: absolute;
  right: 0rpx;
  top: 50%;
  transform: translateY(-71%);
  color: #ccc;
}

.check {
  padding: 20rpx 32rpx;
  height: 40rpx;
  line-height: 40rpx;
}

.check-right {
  font-size: 26rpx;
  margin-top: 2rpx;
  color: #333;
}

.check checkbox {
  margin-right: 4rpx;
}

.check checkbox .wx-checkbox-input {
  width: 32rpx;
  height: 32rpx;
  overflow: hidden;
  /* background-color: #F3CB3CFF */
}

checkbox .wx-checkbox-input.wx-checkbox-input-checked::before {
  background-color: #f3cb3c;
  border: 2rpx solid #f3cb3c;
  width: 32rpx; /* 选中后对勾大小,不要超过背景的尺寸 */
  height: 32rpx; /* 选中后对勾大小,不要超过背景的尺寸 */
  line-height: 32rpx;
  text-align: center;
  font-size: 30rpx; /* 对勾大小 30rpx */
  color: #fff; /* 对勾颜色 白色 */
  transform: translate(-50%, -50%) scale(1);
}

.site-btn {
  padding: 0 66rpx;
  margin-top: 68rpx;
}

.site-btn .btn {
  border-radius: 48rpx;
  font-size: 32rpx;
  height: 96rpx;
  line-height: 96rpx;
}

.save {
  background: #f3cb3c;
  border: 1rpx solid #f3cb3c;
}

.del {
  margin-top: 40rpx;
  border: 1rpx solid #ccc;
  background: #fff;
}

.icon-close {
  position: absolute;
  color: #ccc;
  top: 50%;
  transform: translateY(-62%);
  right: 0rpx;
  line-height: 40rpx;
}

.detail {
  width: 100%;
  padding: 10rpx 0;
  box-sizing: border-box;
}

.detail-up {
  width: 100%;
  /* display: flex; */
  align-items: center;
}

.detail-icon {
  width: 30rpx;
  height: 34rpx;
  margin-left: 30rpx;
  float: left;
}

.detail-textarea {
  width: 88%;
  margin-left:15rpx;
  text-align: left;
  float: left;
  margin-top: -5rpx;
}

.detail-textarea textarea{
  width: 100%;
}

.detail-textarea icon{
  position: absolute;
  color: #ccc;
  top: 50%;
  transform: translateY(-62%);
  left: 30rpx;
  line-height: 40rpx;
}

.detail image {
  max-width: 100%;
  max-height: 100%;
}

.detail-down{
  /* width: 100%; */
  font-size: 24rpx;
  color: #ccc;
  text-align: right;
  margin-top: 10rpx;
}

.detail-tip{
  word-spacing: 1px;
  margin-left: 15px;
  width: 100%;
  font-size: 24rpx;
  color: red;
  margin-top: 10rpx;
}

.iconshuruguanbi{
  margin-right: 30rpx;
  margin-top: 10rpx;

}

.textarea-length-tip {
  position: absolute;
  right: 28rpx;
  bottom: 20rpx;
  z-index: 100;
  color: #999;
}

选择地址页面代码

JS代码

const app = getApp();
import Serve from '../../api/address.js'

Page({
  /**
   * 页面的初始数据
   */
  data: {
    keyWords: '',
    districtName: '',
    timer: null,
    items: [],
    latitude: 31.080632,
    longitude: 121.590618,
    markers: [{
      id: 1,
      latitude: 31.080632,
      longitude: 121.590618,
    }],
    isAuth: false,
    initialized: false,
    flag: false //刚进来的时候
  },

  /**
   * 生命周期函数--监听页面加载
   */

  onLoad: function(options) {
    if (options.districtName) {
      this.setData({
        districtName: options.districtName
      })
      const community = wx.getStorageSync("siteInfo");
      const defKeyWords = community.address || '小区';
      this.getUserLocation(defKeyWords);
    }
  },

  onReady: function() {
    this.mapCtx = wx.createMapContext('myMap');
  },
	//查找附近地址
  searchNearbyShop() {
    this.setData({
      flag: true
    })
    Serve.searchSite(this.data.keyWords, this.data.districtName).then(res => {
      if (res.statusCode == 200) {
        if (res.data.data && res.data.data.length > 0) {
          const items = res.data.data;
          const {
            lat,
            lng
          } = items[0].location;
          this.setData({
            items,
            [`markers[0].latitude`]: items[0].location.lat,
            [`markers[0].longitude`]: items[0].location.lng,
            latitude: lat,
            longitude: lng,
          })
          this.translateMarker(lat, lng);
        } else {
          app.commonTip("抱歉没有搜到您想到的地址");
        }
      } else {
        if (res.message) app.commonTip(res.message);
      }
    })
  },
	//输入地址
  handleKeyWords(e) {
    const keyWords = e.detail;
    if (keyWords) {
      this.setData({
        keyWords,
      })
    } else {
      var address = this.data.addressName
      this.setData({
        keyWords: address
      })
    }
    clearTimeout(this.timer);
    this.timer = setTimeout(() => {
      this.searchNearbyShop();
    }, 100)
  },
   //获取用户附近地区
  getUserLocation(keywords) {
    let that = this;
    Serve.searchSite(keywords, that.data.districtName).then(res => {
      const items = res.data.data;
      if (res.data.data && res.data.data.length > 0) {
        that.setData({
          latitude: items[0].location.lat,
          longitude: items[0].location.lng,
          [`markers[0].latitude`]: items[0].location.lat,
          [`markers[0].longitude`]: items[0].location.lng,
          isAuth: true,
        })
      } else {
        app.commonTip("未搜索到您选择的地区,请手动输入");
      }
    })
  },
  // 移动地图上的标注点
  translateMarker: function(latitude, longitude) {
    const self = this
    this.mapCtx.translateMarker({
      markerId: 1,
      duration: 1000,
      destination: {
        latitude: latitude,
        longitude: longitude,
      },
      animationEnd() {
        console.log('animation end')
        self.setData({
          flag: false
        })
      }
    })
  },
  clearKeyWords() {
    this.setData({
      keyWords: '',
      items: []
    })
  },
    //选择地址
  selectAddress(e) {
    const index = e.currentTarget.dataset.index;
    const pages = getCurrentPages(); //获取当前页面js里面的pages里的所有信息。
    const prevPage = pages[pages.length - 2]; //上一个页面
    const address = this.siteAddress(this.data.items[index].address, this.data.items[index].title);
    const location = this.data.items[index].location;
    const districtName = this.data.items[index].ad_info.district;
    const districtId = this.data.items[index].ad_info.adcode;
    console.log(location);
    prevPage.setData({
      address,
      location,
      districtName,
      selectAddress: address,
      ['region[2]']: districtName ? districtName : prevPage.data.region[2],
      ['region_id[2]']: districtId
    })
    wx.navigateBack({
      delta: 1
    })
  },
  // 处理用户移动地图
  handleRegionChange(e) {
    if (this.data.flag) {
      return false
    }
    this.mapCtx.getCenterLocation({
      success: res => {
        // this.translateMarker(res.latitude, res.longitude)
        clearTimeout(this.data.timer)
        this.data.timer = setTimeout(() => {
          this.searchCity(res.latitude, res.longitude)
        }, 500)
      }
    });

  },
  //滑动查找地址
  searchCity(latitude, longitude) {
    Serve.cansearchSite(latitude, longitude).then(res => {

      const items = res.data.result.pois;
      this.setData({
        items,
      })
      this.translateMarker(latitude, longitude)
      console.log(res)
    })
  
  },
  siteAddress(address, title) {
    var index = address.indexOf("区")
    console.log()
    if (index == address.length - 1) {
      return title
    } else if (index > 0) {
      return address.substr(index + 1)
    } else {
      return title
    }
  }

})

JSON代码

{
  "usingComponents": {
    "van-search": "../../components/dist/search/index"
  },
  "navigationBarTitleText": "选择地址"
}

WXML代码

<!--pages/buy/shop_address/index.wxml-->
<view class='page'>
  <van-search class="search" placeholder="请输入搜索关键词" use-action-slot shape="round" bind:change="handleKeyWords" bind:clear="clearKeyWords" bind:confirm="searchNearbyShop" searchIcon="'iconfont iconsearch c9'">
  </van-search>
  <view class='map'>
    <map id="myMap" style="width:100%;height:540rpx" longitude="{{longitude}}" latitude="{{latitude}}" markers="{{markers}}" scale='15'  bindregionchange="handleRegionChange">
    </map>
  </view>
  <scroll-view scroll-y class='list'>
    <view class='list-item' wx:for="{{items}}" wx:key="index" data-index="{{index}}" bindtap='selectAddress'>
      <view class='list-item_l'>
        <view class='icon'>
          <image src='/images/shop-address-location.png'></image>
        </view>
        <view class='text'>
          <view class='f-16'>{{item.title}}</view> 
          <view class='f-13'>{{item.address}}</view>
        </view>
      </view>
    </view>
  </scroll-view>
</view>

WXSS代码

.page {
  position: relative;
  width: 100vw;
  height: 100vh;
}

.search {
  width: 100vw;
  position: fixed;
  left: 0;
  top: 0;
  z-index: 99;
}

.map {
  width: 100vw;
  position: fixed;
  left: 0;
  top: 108rpx;
}

.list {
  width: 100%;
  position: absolute;
  top: 648rpx;
  left: 0;
  bottom: 0;
  background-color: #fff;
  padding: 0 32rpx;
  box-sizing: border-box;
}

.list-item {
  display: flex;
  justify-content: space-between;
  padding: 22rpx 0;
  align-items: center;
  box-sizing: border-box;
  border-bottom: 1rpx solid #e8e9ea;
}

.list-item:last-child {
  border: none;
}

.list-item .list-item_l {
  display: flex;
  align-items: center;
  margin-right: 10rpx;
}

.list-item .list-item_l .icon {
  width: 30rpx;
  height: 34rpx;
  margin-right: 24rpx;
}

image {
  max-width: 100%;
  max-height: 100%;
}