• 微信小程序 ---- 慕尚花坊 收货地址


    收货地址

    1. 收货地址列表
    2. 新增收货地址
    3. 编辑收货地址
    4. 删除收货地址

    01. 定义新增参数以及封装接口 API

    思路分析:

    点击新建地址按钮,需要跳转到新增地址页面

    因为新增和编辑收货地址页面是同一个页面,我们需要在这个页面处理新增和编辑功能,为了做区分处理。

    我们在后续做进行编辑的时候传递 id 属性,值为 收货地址的 id 值。

    首先熟悉接口文档获取用户信息

    接收文档在这一节,我们先来收集添加收货地址的请求参数

    参数名称参数说明是否必须
    收货人nametrue
    手机号phonetrue
    provinceNametrue
    省 编码provinceCodetrue
    cityNametrue
    市 编码cityCodetrue
    districtNametrue
    区 编码districtCodetrue
    详细地址fullAddresstrue
    设置默认地址isDefault (是否默认地址 → 0:否 1:是)false

    实现步骤:

    1. 在新增收货地址页面 data 中声明所需要的字段
    2. 定义收货地址所需要的全部接口 API 函数

    落地代码:

    ➡️ modules/settingModule/pages/address/add/index

    Page{{
      
      // 页面的初始数据
      data: {
    	  name: '', // 收货人
          phone: '', // 手机号
          provinceName: '', // 省
          provinceCode: '', // 省 编码
          cityName: '', // 市
          cityCode: '', // 市 编码
          districtName: '', // 区
          districtCode: '', // 区 编码
          address: '',  // 详细地址
          fullAddress: '', // 完整地址 (省 + 市 + 区 + 详细地址)
          isDefault: 0 // 设置默认地址,是否默认地址 → 0:否  1:是
      }
    }}
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    ➡️ /api/address

    import http from '../utils/http'
    
    /**
     * @description 实现新增收货地址
     * @param {*} data
     * @returns Promise
     */
    export const reqAddAddress = (data) => {
      return http.post('/userAddress/save', data)
    }
    
    /**
     * @description 获取收货地址列表
     * @returns Promise
     */
    export const reqAddressList = () => {
      return http.get('/userAddress/findUserAddress')
    }
    
    /**
     * @description 获取收货地址详情
     * @param {*} id 收货地址id
     * @returns Promise
     */
    export const reqAddressInfo = (id) => {
      return http.get(`/userAddress/${id}`)
    }
    
    /**
     * @description 编辑收货地址
     * @param {*} data
     * @returns Promise
     */
    export const reqUpdateAddress = (data) => {
      return http.post('/userAddress/update', data)
    }
    
    /**
     * @description 删除收货地址
     * @param {*} id 收货地址 id
     * @returns Promise
     */
    export const reqDelAddress = (id) => {
      return instance.get(`/userAddress/delete/${id}`)
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    02. 收集省市区数据

    思路分析

    省市区的结构使用了小程序本身自带的picker 件,并将组件的 mode 属性设置为了 region,从而变成省市区选择器

    如果想获取省市区的数据,需要给 picker 选择组件添加change 事件来监听属性值的改变,获取选中的省市区

    
    <view class="item">
      <text class="label">省/市/县 (区)text>
    
      
      
      
      <picker
        mode="region"
        value="{{ [provinceName, cityName, districtName] }}"
        bindchange="onAddressChange"
      >
        <view wx:if="{{ provinceName }}" class="region">
         {{ provinceName + ' ' + cityName + ' ' + districtName }}
        view>
        <view wx:else class="placeholder">请填写收货人所在城市view>
      picker>
    
      <view class="location" bindtap="onLocation">
        <van-icon name="location-o" color="#777" />
        <text>定位text>
      view>
    view>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    实现步骤

    1. picker 选择组件添加change 事件来监听属性值的改变,获取选中的省市区
    2. 将获取到省市区标识和编码赋值给 data中的字段

    落地代码

    ➡️ modules/settingModule/pages/address/add/index

    Page({
       
      // coding...
        
      // 省市区选择
      onAddressChange(event) {
        const [provinceCode, cityCode, districtCode] = event.detail.code
        const [provinceName, cityName, districtName] = event.detail.value
    
        // 存储省市区对应的编码
        this.setData({
          provinceCode,
          provinceName,
          cityCode,
          cityName,
          districtName,
          districtCode
        })
      }
        
      // coding...
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    03. 收集新增地址其他请求参数

    思路分析:

    使用简易双向数据 model:value 绑定来收集新增地址表单数据。

    在将数据收集以后,需要组织两个数据:

    1. 是否是默认地址,0 不设置为默认地址,1 设置为默认地址
    2. 拼接完整的收货地址

    实现步骤:

    1. 使用简易双向数据绑定来收集新增地址表单数据。
    2. 给按钮绑定点击事件,在事件处理函数中收集并整理数据

    落地代码:

    Page({
        
      // coding...
        
      // 获取表单元素的值
      saveAddrssForm(event) {
          
        // 解构出省市区以及 是否是默认地址
        const { provinceName, cityName, districtName, address, isDefault } = this.data
        
        // 拼接完整的地址
        const fullAddress = provinceName + cityName + districtName + address
          
        // 合并接口请求参数
        const params = {
          ...this.data,
          fullAddress,
          isDefault: isDefault ? 1 : 0
        }
    
    
        console.log(params)
      }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    04. 地理定位功能介绍

    地理定位介绍:

    小程序地理定位是指通过小程序开发平台提供的 API,来获取用户的地理位置信息。用户在使用小程序时,可以授权小程序获取自己的地理位置信息

    1. wx.getLocation() :获取当前的地理位置
    2. wx.chooseLocation():打开地图选择位置

    申请开通:

    暂时只对部分类目的小程序开放,需要先通过类目审核,然后在小程序管理后台,「开发」-「开发管理」-「接口设置」中自助开通该接口权限。

    使用方法:

    1. 在 app.json 中配置 requiredPrivateInfos 进行声明启用

    2. 在调用 wx.getLocation() 时需要在 app.json 配置 permission 字段,同时使用 scope.userLocation 声明收集用户选择的位置信息的目的,wx.chooseLocation() 接口不需要配置该字段,可以直接进行调用

    3. 在配置好以后,调用 wx.getLocation()wx.chooseLocation() 接口

    参考文档:

    1. 地理位置接口新增与相关流程调整
    2. permission 字段说明

    app.json 中进行配置

    {
      "requiredPrivateInfos": [
        "getLocation",
        "chooseLocation"
      ],
      "permission": {
        "scope.userLocation": {
          "desc": "获取用户位置信息用于填写收货地址"
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    getLocation 使用:

    // 地理定位
    async onLocation() {
      // 获取 纬度 、精度
      const { latitude, longitude } = await wx.getLocation()
      console.log(location)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    chooseLocation 使用:

    // 地理定位
    async onLocation() {
      // 打开地图选择位置,获取 纬度 、精度
      const { latitude, longitude }  = await wx.chooseLocation()
      console.log(res)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    05. 拒绝授权后的解决方案

    在调用 wx.getLocation() 获取用地理位置时,如果用户选择拒绝授权,代码会直接抛出错误。

    在拒绝授权以后,再次调用 wx.getLocation() 时,就不会在弹窗询问用户是否允许授权。

    接下来,就需要优化授权的流程:

    在这里插入图片描述

    1. wx.getSetting():获取用户的当前设置。返回值中只会出现小程序已经向用户请求过的权限
    2. wx.openSetting(): 调起客户端小程序设置界面,返回用户设置的操作结果

    📌 注意事项:

    1. 如果希望用户再次授权,就需要让用户进行 手动开启授权
    2. wx.openSetting() 必须用户发生点击行为后,才可以跳转到设置页进行授权信息管理。
    // 获取用户地理位置信息
    async onLocation() {
      // 调用 getSetting 方法获取用户所有的授权信息
      // 返回的 authSetting 包含小程序已向小程序申请过的权限已经授权结果(true、false)
      const { authSetting } = await wx.getSetting()
      console.log(authSetting)
    
      // scope.userLocation 是否已经授权获取地理位置的信息
      // 如果之前没有申请过返回 undefined,需要调用 getLocation
      // 如果之前同意了授权,返回 true,需要调用 getLocation
      // 如果之前拒绝了授权,返回 false,需要用户手动进行授权
      // 等于 true,或者不等于 undefined,说明需要进行授权
      // const isAuth =
      //   authSetting['scope.userLocation'] ||
      //   authSetting['scope.userLocation'] === undefined
    
      // 为了避免冗余的条件判断,使用 !! 把代码进行优化
      const isAuth = !!authSetting['scope.userLocation']
    
      if (!isAuth) {
        // 弹窗询问用户是否进行授权
        const modalRes = await wx.modal({
          title: '授权提示',
          content: '需要需要您的地理位置信息,请确认授权'
        })
    
        // 如果用户点击了取消,说明用户拒绝了授权,给用户提示
        if (!modalRes) return wx.toast({ title: '您拒绝了授权' })
    
        // 如果用户点击了确定,调用 wx.openSetting 打开微信客户端小程序授权页面
        // 并返回授权以后的结果
        const { authSetting } = await wx.openSetting()
    
        // 如果用户没有更新授权信息,提示没有更新授权
        if (!authSetting['scope.userLocation'])
          return wx.toast({ title: '授权失败!' })
    
        try {
          // 如果用户更新授权信息,则调用 getLocation 获取用户地理位置信息
          const locationRes = await wx.getLocation()
          // 打印地理位置信息
          console.log(locationRes)
        } catch (err) {
          console.log(err)
        }
      } else {
        try {
          // 如果是第一次调用 getLocation 或者之前授权过
          // 直接调用 getLocation 获取用户信息即可
          const locationRes = await wx.getLocation()
          console.log(locationRes)
        } catch (error) {
          wx.toast({ title: '您拒绝授权获取地址位置' })
        }
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    06. 开通腾讯位置服务

    腾讯位置服务简介:

    使用wx.chooseLocation()能够很方便的让用户来选择地理位置,但是wx.chooseLocation()返回的数据并没有包含省市区、省市区编码数据。而新增收货地址接口,需要传递省市区、省市区编码数据。

    这时候我们可以使用 腾讯位置服务 将返回的经度、纬度进行逆地址解析,转换成详细地址。

    腾讯位置服务专为小程序开发提供了 JavaScript SDK,方便开发者在小程序中可以使用腾讯地图服务。

    使用腾讯位置服务可以很方便的让开发者实现地址解析、逆地址解析等功能。

    在这里插入图片描述

    使用步骤:

    1. 申请开发者密钥(key):申请密钥
    2. 开通 webserviceAPI 服务:控制台 → 应用管理→我的应用 → 添加 key →勾选 WebServiceAPI →保存
    3. 下载微信小程序 JavaScriptSDK,微信小程序JavaScriptSDK v1.1 JavaScriptSDK v1.2
    4. 安全域名设置
      • 小程序管理后台 -> 开发 -> 开发管理 -> 开发设置 -> “服务器域名” 中设置 request 合法域名
      • 添加 https://apis.map.qq.com

    详细步骤:

    1. 申请密钥:密钥申请,微信扫码进行登录,选择绑定已有账号、或者注册新账号 (需要绑定手机、验证邮箱)

    2. 控制台 → 应用管理→我的应用 → 创建应用 → 添加 key → 创建完成

    在这里插入图片描述

    1. 下载微信小程序 JavaScriptSDK v1.2,下载将 .js 文件放到小程序的 libs 目录下

    2. 进行安全域名设置,或者点击微信开发者工具中的暂时不校验域名

    07. LBS 逆地址解析

    使用步骤:

    1. 在项目中引入 SDK 核心类
    2. onLoad 中实例化 API 核心类,同时配置创建的 key
    3. 使用实例方法 reverseGeocoder 方法进行逆地址解析,将提供的坐标转换为详细的地址位置信息

    官方文档-基础示例:Hello World

    官方文档-逆地址解析:reverseGeocoder

    落地代码:

    1. 引入 SDK 核心类

      // var QQMapWX = require('../../libs/qqmap-wx-jssdk.js');
      import QQMapWX from '../../../../../libs/qqmap-wx-jssdk.min'
      
      • 1
      • 2
    2. 实例化 API 核心类

      // 引入SDK核心类,js文件根据自己业务,位置可自行放置
      import QQMapWX from '../../../../../libs/qqmap-wx-jssdk.min'
      
      Page({
       
        onLoad: function () {
      
          // 实例化API核心类
          this.qqmapsdk = new QQMapWX({
            key: '申请的key'
          })
       
        }
          
        // coding...   
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
    3. 使用 reverseGeocoder 方法进行逆地址解析,将提供的坐标转换为所在位置的文字描述的转换

      // LBS 地址逆解析
      // 地理定位
      async onLocation() {
        // 获取 纬度 、精度
        // const { latitude, longitude } = await wx.getLocation()
        // console.log(location)
      
        // 获取经、纬度、位置名称
        let { latitude, longitude, name } = await wx.chooseLocation()
      
        // 使用 reverseGeocoder 方法进行逆地址解析
        this.qqmapsdk.reverseGeocoder({
          // 传入经、纬度
          location: {
            latitude,
            longitude
          },
      
          // 逆地址解析成功后执行
          success: (res) => {
            // 获取选择的
            const { street_number } = res.result.address_component
      
            // province 省  city 市  district 区
            const {
              province, // 省
              city, // 市
              district, // 区
              adcode, // 行政区划代码
              city_code, // 城市代码,由国家码+行政区划代码(提出城市级别)组合而来,总共为9位
              nation_code // 国家代码
            } = res.result.ad_info
      
            this.setData({
              // 省级: 前两位有值,后4位置0,如,河北省: 130000
              provinceCode: adcode.replace(adcode.substring(2, 6), '0000'),
              provinceName: province,
      
              // 市前面多个国家代码,需要进行截取
              cityCode: city_code.slice(nation_code.length),
              cityName: city,
      
              // 东莞市、中山市、修州市、嘉关市 因其下无区县级,
              districtCode: district && adcode,
              districtName: district,
      
              // 详细地址
              address: name,
              fullAddress: [province, city, district, address].join('')
            })
          }
        })
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53

    09. 新增收货地址表单验证

    思路分析:

    在点击新增收货地址的时候,我们需要对用户输入的值进行验证。产品需求如下:

    1. 收货人不能为空,且不能输入特殊字符
    2. 手机号不能为空,且输入的手机号必须合法
    3. 省市区不能为空
    4. 详细地址不能为空

    正则:

    // 验证收货人,是否只包含大小写字母、数字和中文字符
    const nameRegExp = '^[a-zA-Z\\d\\u4e00-\\u9fa5]+$'
    
    // 验证手机号,是否符合中国大陆手机号码的格式
    const phoneReg = '^1(?:3\\d|4[4-9]|5[0-35-9]|6[67]|7[0-8]|8\\d|9\\d)\\d{8}$'
    
    • 1
    • 2
    • 3
    • 4
    • 5

    实现步骤:

    1. 创建 validateForm 方法,使用 async-validator 对表单进行验证
    2. 在新增收货地址之前,调用 validateForm 方法,如果验证成功执行新增守护地址的逻辑

    落地代码:

    ➡️ /modules/settingModule/pages/address/add/index

    import Schema from 'async-validator'
    
    Page({
    
      // coding....
    
        // 保存收货地址
      async saveAddrssForm() {
        // 组织参数 (完整地址、是否设置为默认地址)
    
        const {
          provinceName,
          cityName,
          districtName,
          address,
          isDefault
        } = this.data
    
        // 最终需要发送的请求参数
        const params = {
          ...this.data,
          fullAddress: provinceName + cityName + districtName + address,
          isDefault: isDefault ? 1 : 0
        }
    
        // 调用方法对最终的请求参数进行验证
        const { valid } = await this.validateAddress(params)
    
        // 如果验证没有通过,不继续执行后续的逻辑
        if (!valid) return
        
        console.log(params)
      },
    
      // 验证新增收货地址请求参数
      // 形参 params 是需要验证的数据
      validateAddress(params) {
        // 验证收货人,是否只包含大小写字母、数字和中文字符
        const nameRegExp = '^[a-zA-Z\\d\\u4e00-\\u9fa5]+$'
    
        // 验证手机号
        const phoneReg = '^1(?:3\\d|4[4-9]|5[0-35-9]|6[67]|7[0-8]|8\\d|9\\d)\\d{8}$'
    
        // 创建验证规则,验证规则是一个对象
        // 每一项是一个验证规则,验证规则属性需要和验证的数据进行同名
        const rules = {
          name: [
            { required: true, message: '请输入收货人姓名' },
            { pattern: nameRegExp, message: '收货人姓名不合法' }
          ],
          phone: [
            { required: true, message: '请输入收货人手机号' },
            { pattern: phoneReg, message: '手机号不合法' }
          ],
          provinceName: { required: true, message: '请选择收货人所在地区' },
          address: { required: true, message: '请输入详细地址' }
        }
    
        // 创建验证实例,并传入验证规则
        const validator = new Schema(rules)
    
        // 调用实例方法对数据进行验证
        // 注意:我们希望将验证结果通过 Promsie 的形式返回给函数的调用者
        return new Promise((resolve) => {
          validator.validate(params, (errors, fields) => {
            if (errors) {
              // 如果验证失败,需要给用户进行提示
              wx.toast({
                title: errors[0].message
              })
    
              resolve({ valid: false })
            } else {
              resolve({ valid: true })
            }
          })
        })
      },
    
    
      // coding...
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82

    10. 实现新增收货地址

    思路分析:

    在实现了新增收货地址的数据收集、表单验证以后,我们需要实现新增收货地址的功能,将用户的收货地址到服务器。我们直接根据接口文档,封装接口 API,然后在表单验证以后,进行收货地址的添加即可。

    实现步骤:

    1. 在对新增收货地址请求参数验证以后,将封装好的新增收货地址的 API 函数调用

    2. 在新增收货地址成功以后,跳转到收货地址详情页面。

    落地代码:

    ➡️ /pages/address/add/index.js

    // 新增或修改地址
    async saveAddrssForm(event) {
      // 组织参数 (完整地址、是否设置为默认地址)
      const {
        provinceName,
        cityName,
        districtName,
        address,
        isDefault
      } = this.data
    
      // 最终需要发送的请求参数
      const params = {
        ...this.data,
        fullAddress: provinceName + cityName + districtName + address,
        isDefault: isDefault ? 1 : 0
      }
      
      // 如果验证没有通过,不进行后续处理
      if (!valid) return
    
      // 发送请求,保存收货地址
      const res = await reqAddAddress(params)
      
      if (res.code === 200) {
        wx.navigateBack({
          success() {
            wx.toast({ title: '新增收货地址成功' })
          }
        })
      }
        
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    11. 收货地址列表渲染

    思路分析:

    渲染收货地址需要收货地址的数据,需要调用接口获取收货地址数据,使用返回的数据进行结构的渲染。

    先熟悉接口文档:获取收货地址

    在熟悉了接口文档以后,根据接口文档封装接口 API 函数,然后在页面调用 API 函数获取收货地址的数据,在获取到数据以后,使用后端返回的数据对页面进行渲染。

    实现步骤:

    1. onShow 钩子函数中调用reqAddressList方法

    2. 在获取到数据以后,使用后端返回的数据对页面进行渲染

    落地代码:

    ➡️ /modules/settingModule/pages/address/list/index.js

    // pages/address/list/index.js
    + import { reqAddressList } from '../../../../../api/address'
    
    Page({
      // 页面的初始数据
      data: {
    +     addressList: [] // 收货地址列表
      },
    
    +   // 获取收货地址
    +   async getAddressList() {
    +     // 调用 API,获取收货地址
    +     const { data: addressList } = await reqAddressList()
    + 
    +     this.setData({
    +       addressList
    +     })
    +   },
    
      // 去编辑页面
      toEdit() {
        wx.navigateTo({
          url: '/modules/settingModule/pages/address/add/index'
        })
      },
    
    +   onLoad() {
    +     this.getAddressList()
    +   }
    })
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    ➡️ /modules/settingModule/pages/address/list/index.wxml

    <view class="list-warpper" wx:if="{{ addressList.length }}">
      <view wx:for="{{ addressList }}" wx:key="id" class="list-item">
        <van-swipe-cell right-width="{{ 65 }}">
          <view class="list-item-box">
            <view class="info">
              <view class="user-info">
    +             <text>{{ item.name }}text>
    +             <text>{{ item.phone }}text>
    +             <text wx:if="{{ item.isDefault }}" class="default-tag">默认text>
              view>
    
    +           <view class="address-info"> {{ item.fullAddress }} view>
            view>
    
            <view class="editBtn">
              <van-icon bindtap="toEdit" name="edit" size="22px" color="#999" />
            view>
          view>
          
          <view slot="right" class="van-swipe-cell__right">
            <text>删除text>
          view>
        van-swipe-cell>
      view>
    view>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    12. 实现更新收货地址

    思路分析:

    新增和编辑收货地址页面是同一个页面,我们需要在这个页面处理新增和编辑功能

    在收货地址列表页面,点击更新按钮时,需要跳转到新增/更新页面,同时需要将更新这一项的 id 传递给新增/更新页面。

    onLoad 中获取 id,并且使用 id 区分用户是进行新增还是编辑的操作。

    如果存在 id,在获取需要更新的收货地址的数据,并进行页面的回显用户的收货地址,并且需要更新导航栏标题

    因为我们之前直接是将数据放到 data 中的,所以我们直接将数据使用 setData 赋值即可

    首先熟悉接口文档:获取收货地址详情

    实现步骤:

    1. 在从收货地址列表页面跳转到更新页面的时候,需要携带 id
    2. onLoad 中判断是否存在 id,如果存在 id,在获取数据进行回显

    落地代码:

    ➡️ /modules/settingModule/pages/address/list/index.wxml

    
    <van-icon bindtap="toEdit" data-id="{{ item.id }}" name="edit" size="22px" color="#999" />
    
    • 1
    • 2

    ➡️ /modules/settingModule/pages/address/list/index.js

    // 去编辑页面
    toEdit(event) {
      // 需要编辑的收货地址
      const { id } = event.target.dataset
    
      wx.navigateTo({
        url: `/modules/settingModule/pages/address/add/index?id=${id}`
      })
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    ➡️ /modules/settingModule/pages/address/add/index.js

    Page({
       
      // coding...
        
      // 保存收货地址
      async saveAddrssForm() {
        // 组织参数 (完整地址、是否设置为默认地址)
        const {
          provinceName,
          cityName,
          districtName,
          address,
          isDefault
        } = this.data
    
        // 最终需要发送的请求参数
        const params = {
          ...this.data,
          fullAddress: provinceName + cityName + districtName + address,
          isDefault: isDefault ? 1 : 0
        }
    
        // 调用方法对最终的请求参数进行验证
        const { valid } = await this.validateAddress(params)
    
        // 如果验证没有通过,不继续执行后续的逻辑
        if (!valid) return
    
    +     // 发送请求,保存收货地址
    +     const res = this.addressId
    +       ? await reqUpdateAddress(params)
    +       : await reqAddAddress(params)
    
    +     if (res.code === 200) {
    +       // 提示用户更新状态
    +       wx.toast({
    +         title: this.addressId ? '编辑收货地址成功' : '新增收货地址成功'
    +       })
    + 
    +       // 返回到收货地址列表页面
    +       wx.navigateBack()
        }
      },
       
    +   // 回显收货地址的逻辑
    +   showAddressInfo(id) {
    +     // 判断是否存在 id,如果不存在 id,return 不执行后续的逻辑
    +     if (!id) return
    + 
    +     // 如果存在 id,将 id 挂载到 this 页面实例上
    +     this.addressId = id
    + 
    +     // 动态设置当前页面的标题
    +     wx.setNavigationBarTitle({
    +       title: '更新收货地址'
    +     })
    + 
    +     // 调用方法获取收货地址详细信息
    +     const { data } = await reqAddressInfo(this.addressId)
    +     // 将获取的数据进行赋值
    +     this.setData(data)
    +   },
    
      onLoad(options) {
        // 对核心类 QQMapWX 进行实例化
        this.qqmapwx = new QQMapWX({
          // key 要使用自己申请的 key
          // 在进行逆解析的时候,如果发现 key 只能使用一次,需要在腾讯位置服务后台配置额度
          key: 'S5CBZ-TQXCB-L73UJ-J6VJA-FXS53-JNBY3'
        })
    
    +     // 回显收货地址的逻辑
    +     this.showAddressInfo(options.id)
      }
        
      // coding...
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77

    13. 实现删除收货地址

    思路分析:

    点击删除按钮的时候,需要将对应的地址进行删除

    当点击删除按钮的时候,调用封装的接口 API 函数 ,同时传递需要删除的收货地址 id 即可

    实现步骤:

    1. 给删除按钮绑定点击事件 delAddress,同时通过 data-id 传递需要删除的商品 id
    2. delAddress 事件处理程序后面,调用 API 函数 reqDelAddress,并传递 id
    3. 在删除收货地址成功以后,给用户提示

    落地代码:

    ➡️ /modules/settingModule/pages/address/list/index.wxml

    <van-icon
    +   bindtap="delAddress"
    +   data-id="{{ item.id }}" 
      name="delete"
      size="22px"
      color="#999"
    />
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    ➡️ /modules/settingModule/pages/address/list/index.js

    // 删除收货地址
    async delAddress(e) {
      const { id } = e.target.dataset
    
      await reqDelAddress(id)
      this.getAddressList()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    优化:SwipeCell 自动收起删除滑块

    目前我们已经实现了滑块删除收货地址的功能,

    但是我们会发现点击页面空白区域或者点击其他收货地址时,删除的滑块不会自动收起。

    如果想实现点击空白区域自动收起滑块功能,需要在 点击空白区域 以及 其他收货地址时,获取要收起的滑块实例。

    调用对应滑块的实例方法 close 即可。

    在这里插入图片描述

    实现思路:

    1. 给滑块绑定 id
    2. 在打开滑块时,获取当前滑块的实例,然后将实例存储到 data 的数组中。
    3. 给页面最外层的 view 同时给滑块区域绑定点击事件,在事件处理函数中对数据遍历,每一项调用 close 方法关掉滑块
    4. 将关掉的逻辑抽取成 behavior 文件,方便在其他文件中进行复用。

    落地代码:

    ➡️ /behavior/swipeCellBahavior.js

    export const swipeCellBehavior = Behavior({
      data: {
        swipeCelQueue: [] // 实例存储队列
      },
    
      methods: {
        // 打开滑块时,将实例存储到队列中
        onSwipeCellOpen(event) {
          let instance = this.selectComponent(`#${event.target.id}`)
          this.data.swipeCelQueue.push(instance)
        },
    
        // 点击其他滑块时,关掉开启的滑块
        onSwipeCellClick() {
          this.onSwipeCellCommonClick()
        },
    
        // 点击页面空白区域时,关掉开启的滑块
        onSwipeCellPageTap() {
          this.onSwipeCellCommonClick()
        },
    
        // 关掉滑块的统一方法
        onSwipeCellCommonClick() {
          // 循环关闭开启的滑块
          this.data.swipeCelQueue.forEach(function (instance) {
            instance.close()
          })
            
          // 将滑块进行清空
          this.data.swipeCelQueue = []
        }
      }
    })
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    ➡️ /modules/settingModule/pages/address/list/index.wxml

    <view class="container address-list" bindtap="onSwipeCellPageTap">
    
      <van-swipe-cell
        right-width="{{ 65 }}"
    +     data-id="{{ item.id }}"
    +     bind:open="onSwipeCellOpen"
    +     bind:click="onSwipeCellClick"
      >
      
        
      
      van-swipe-cell>
    
    view>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
  • 相关阅读:
    链表(简单)
    Python进阶教学——装饰器与闭包
    【LeetCode题目详解】第九章 动态规划part06 完全背的讲解 518. 零钱兑换 II 377. 组合总和 Ⅳ (day44补)
    企业电子招标采购系统源码Spring Boot + Mybatis + Redis + Layui + 前后端分离 构建企业电子招采平台之立项流程图
    Qt-Advanced-Docking-System的学习
    设计师都有些常用的组件库?
    java案例24:模拟百度翻译
    WPF之Button组件
    kubernetes之crontab
    如何成为 10 倍软件工程师
  • 原文地址:https://blog.csdn.net/qq_63358859/article/details/136371911