【 uniapp - 黑马优购 | 购物车页面(2)】如何实现收货地址区域功能、常见问题解决方案

简介: 【 uniapp - 黑马优购 | 购物车页面(2)】如何实现收货地址区域功能、常见问题解决方案

🌴9.2 收货地址区域

☘️9.2.1 创建收货地址组件

  1. components 目录上鼠标右键,选择 新建组件,并填写组件相关的信息:
  2. 渲染收货地址组件的基本结构:
<view>
  <!-- 选择收货地址的盒子 -->
  <view class="address-choose-box">
    <button type="primary" size="mini" class="btnChooseAddress">请选择收货地址+</button>
  </view>
  <!-- 渲染收货信息的盒子 -->
  <view class="address-info-box">
    <view class="row1">
      <view class="row1-left">
        <view class="username">收货人:<text>escook</text></view>
      </view>
      <view class="row1-right">
        <view class="phone">电话:<text>158XXXX1234</text></view>
        <uni-icons type="arrowright" size="16"></uni-icons>
      </view>
    </view>
    <view class="row2">
      <view class="row2-left">收货地址:</view>
      <view class="row2-right">地址地址地址xxx xx省xx市xx区xxx xx
      省xx市xx区xxx xx省xx市xx区xxx </view>
    </view>
  </view>
  <!-- 底部的边框线 -->
  <image src="/static/cart_border@2x.png" class="address-border"></image>
</view>
  1. 美化收货地址组件的样式:
// 底部边框线的样式
.address-border {
  display: block;
  width: 100%;
  height: 5px;
}
// 选择收货地址的盒子
.address-choose-box {
  height: 90px;
  display: flex;
  align-items: center;
  justify-content: center;
}
// 渲染收货信息的盒子
.address-info-box {
  font-size: 12px;
  height: 90px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 0 5px;
  // 第一行
  .row1 {
    display: flex;
    justify-content: space-between;
    .row1-right {
      display: flex;
      align-items: center;
      .phone {
        margin-right: 5px;
      }
    }
  }
  // 第二行
  .row2 {
    display: flex;
    align-items: center;
    margin-top: 10px;
    .row2-left {
      white-space: nowrap;
    }
  }
}

☘️9.2.2 实现收货地址区域的按需展示

  1. data 中定义收货地址的信息对象:
export default {
  data() {
    return {
      // 收货地址
      address: {},
    }
  },
}
  1. 使用 v-ifv-else 实现按需展示:
<!-- 选择收货地址的盒子 -->
<view class="address-choose-box" v-if="JSON.stringify(address) === '{}'">
  <button type="primary" size="mini" class="btnChooseAddress">请选择收货地址+</button>
</view>
<!-- 渲染收货信息的盒子 -->
<view class="address-info-box" v-else>
  <!-- 省略其它代码 -->
</view>

☘️9.2.3 实现选择收货地址的功能

  1. 请选择收货地址+button 按钮绑定点击事件处理函数:
<!-- 选择收货地址的盒子 -->
<view class="address-choose-box" v-if="JSON.stringify(address) === '{}'">
  <button type="primary" size="mini" class="btnChooseAddress" @click="chooseAddress">请选择收货地址+</button>
</view>
  1. 定义 chooseAddress 事件处理函数,调用小程序提供的 chooseAddress()API 实现选择收货地址的功能:
methods: {
  // 选择收货地址
  async chooseAddress() {
    // 1. 调用小程序提供的 chooseAddress() 方法,即可使用选择收货地址的功能
    //    返回值是一个数组:第 1 项为错误对象;第 2 项为成功之后的收货地址对象
    const [err, succ] = await uni.chooseAddress().catch(err => err)
    // 2. 用户成功的选择了收货地址
    if (err === null && succ.errMsg === 'chooseAddress:ok') {
      // 为 data 里面的收货地址对象赋值
      this.address = succ
    }
  }
}
  1. 定义收货详细地址的计算属性:
computed: {
  // 收货详细地址的计算属性
  addstr() {
    if (!this.address.provinceName) return ''
    // 拼接 省,市,区,详细地址 的字符串并返回给用户
    return this.address.provinceName + this.address.cityName + this.address.countyName + this.address.detailInfo
  }
}
  1. 渲染收货地址区域的数据:
<!-- 渲染收货信息的盒子 -->
<view class="address-info-box" v-else>
  <view class="row1">
    <view class="row1-left">
      <view class="username">收货人:<text>{{address.userName}}</text></view>
    </view>
    <view class="row1-right">
      <view class="phone">电话:<text>{{address.telNumber}}</text></view>
      <uni-icons type="arrowright" size="16"></uni-icons>
    </view>
  </view>
  <view class="row2">
    <view class="row2-left">收货地址:</view>
    <view class="row2-right">{{addstr}}</view>
  </view>
</view>

☘️9.2.4 将 address 信息存储到 vuex 中

  1. store 目录中,创建用户相关的 vuex 模块,命名为 user.js
export default {
  // 开启命名空间
  namespaced: true,
  // state 数据
  state: () => ({
    // 收货地址
    address: {},
  }),
  // 方法
  mutations: {
    // 更新收货地址
    updateAddress(state, address) {
      state.address = address
    },
  },
  // 数据包装器
  getters: {},
}
  1. store/store.js 模块中,导入并挂载 user.js 模块:
// 1. 导入 Vue 和 Vuex
import Vue from 'vue'
import Vuex from 'vuex'
// 导入购物车的 vuex 模块
import moduleCart from './cart.js'
// 导入用户的 vuex 模块
import moduleUser from './user.js'
// 2. 将 Vuex 安装为 Vue 的插件
Vue.use(Vuex)
// 3. 创建 Store 的实例对象
const store = new Vuex.Store({
  // TODO:挂载 store 模块
  modules: {
    // 挂载购物车的 vuex 模块,模块内成员的访问路径被调整为 m_cart,例如:
    // 购物车模块中 cart 数组的访问路径是 m_cart/cart
    m_cart: moduleCart,
    // 挂载用户的 vuex 模块,访问路径为 m_user
    m_user: moduleUser,
  },
})
// 4. 向外共享 Store 的实例对象
export default store
  1. 改造 address.vue 组件中的代码,使用 vuex 提供的 address 计算属性 替代 data 中定义的本地 address 对象:
// 1. 按需导入 mapState 和 mapMutations 这两个辅助函数
import { mapState, mapMutations } from 'vuex'
export default {
  data() {
    return {
      // 2.1 注释掉下面的 address 对象,使用 2.2 中的代码替代之
      // address: {}
    }
  },
  methods: {
    // 3.1 把 m_user 模块中的 updateAddress 函数映射到当前组件
    ...mapMutations('m_user', ['updateAddress']),
    // 选择收货地址
    async chooseAddress() {
      const [err, succ] = await uni.chooseAddress().catch((err) => err)
      // 用户成功的选择了收货地址
      if (err === null && succ.errMsg === 'chooseAddress:ok') {
        // 3.2 把下面这行代码注释掉,使用 3.3 中的代码替代之
        // this.address = succ
        // 3.3 调用 Store 中提供的 updateAddress 方法,将 address 保存到 Store 里面
        this.updateAddress(succ)
      }
    },
  },
  computed: {
    // 2.2 把 m_user 模块中的 address 对象映射当前组件中使用,代替 data 中 address 对象
    ...mapState('m_user', ['address']),
    // 收货详细地址的计算属性
    addstr() {
      if (!this.address.provinceName) return ''
      // 拼接 省,市,区,详细地址 的字符串并返回给用户
      return this.address.provinceName + this.address.cityName + this.address.countyName + this.address.detailInfo
    },
  },
}

☘️9.2.5 将 Store 中的 address 持久化存储到本地

  1. 修改 store/user.js 模块中的代码如下:
export default {
  // 开启命名空间
  namespaced: true,
  // state 数据
  state: () => ({
    // 3. 读取本地的收货地址数据,初始化 address 对象
    address: JSON.parse(uni.getStorageSync('address') || '{}'),
  }),
  // 方法
  mutations: {
    // 更新收货地址
    updateAddress(state, address) {
      state.address = address
      // 2. 通过 this.commit() 方法,调用 m_user 模块下的 saveAddressToStorage 方法将 address 对象持久化存储到本地
      this.commit('m_user/saveAddressToStorage')
    },
    // 1. 定义将 address 持久化存储到本地 mutations 方法
    saveAddressToStorage(state) {
      uni.setStorageSync('address', JSON.stringify(state.address))
    },
  },
  // 数据包装器
  getters: {},
}

☘️9.2.6 将 addstr 抽离为 getters

目的:为了提高代码的复用性,可以把收货的详细地址抽离为 getters,方便在多个页面和组件之间实现复用。

  1. 剪切 my-address.vue 组件中的 addstr 计算属性的代码,粘贴到 user.js 模块中,作为一个 getters 节点:
// 数据包装器
getters: {
  // 收货详细地址的计算属性
  addstr(state) {
    if (!state.address.provinceName) return ''
    // 拼接 省,市,区,详细地址 的字符串并返回给用户
    return state.address.provinceName + state.address.cityName + state.address.countyName + state.address.detailInfo
  }
}
  1. 改造 my-address.vue 组件中的代码,通过 mapGetters 辅助函数,将 m_user 模块中的 addstr 映射到当前组件中使用:
// 按需导入 mapGetters 辅助函数
import { mapState, mapMutations, mapGetters } from 'vuex'
export default {
  // 省略其它代码
  computed: {
    ...mapState('m_user', ['address']),
    // 将 m_user 模块中的 addstr 映射到当前组件中使用
    ...mapGetters('m_user', ['addstr']),
  },
}

☘️9.2.7 重新选择收货地址

  1. class 类名为 address-info-box 的盒子绑定 click 事件处理函数如下:
<!-- 渲染收货信息的盒子 -->
<view class="address-info-box" v-else @click="chooseAddress">
  <!-- 省略其它代码 -->
</view>

☘️9.2.8 解决收货地址授权失败的问题

如果在选择收货地址的时候,用户点击了取消授权,则需要进行特殊的处理,否则用户将无法再次选择收货地址!

  1. 改造 chooseAddress 方法如下:
// 选择收货地址
async chooseAddress() {
  // 1. 调用小程序提供的 chooseAddress() 方法,即可使用选择收货地址的功能
  //    返回值是一个数组:第1项为错误对象;第2项为成功之后的收货地址对象
  const [err, succ] = await uni.chooseAddress().catch(err => err)
  // 2. 用户成功的选择了收货地址
  if (succ && succ.errMsg === 'chooseAddress:ok') {
    // 更新 vuex 中的收货地址
    this.updateAddress(succ)
  }
  // 3. 用户没有授权
  if (err && err.errMsg === 'chooseAddress:fail auth deny') {
    this.reAuth() // 调用 this.reAuth() 方法,向用户重新发起授权申请
  }
}
  1. methods 节点中声明 reAuth 方法如下:
// 调用此方法,重新发起收货地址的授权
async reAuth() {
  // 3.1 提示用户对地址进行授权
  const [err2, confirmResult] = await uni.showModal({
    content: '检测到您没打开地址权限,是否去设置打开?',
    confirmText: "确认",
    cancelText: "取消",
  })
  // 3.2 如果弹框异常,则直接退出
  if (err2) return
  // 3.3 如果用户点击了 “取消” 按钮,则提示用户 “您取消了地址授权!”
  if (confirmResult.cancel) return uni.$showMsg('您取消了地址授权!')
  // 3.4 如果用户点击了 “确认” 按钮,则调用 uni.openSetting() 方法进入授权页面,让用户重新进行授权
  if (confirmResult.confirm) return uni.openSetting({
    // 3.4.1 授权结束,需要对授权的结果做进一步判断
    success: (settingResult) => {
      // 3.4.2 地址授权的值等于 true,提示用户 “授权成功”
      if (settingResult.authSetting['scope.address']) return uni.$showMsg('授权成功!请选择地址')
      // 3.4.3 地址授权的值等于 false,提示用户 “您取消了地址授权”
      if (!settingResult.authSetting['scope.address']) return uni.$showMsg('您取消了地址授权!')
    }
  })
}

☘️9.2.9 解决 iPhone 真机上无法重新授权的问题

问题说明:在 iPhone 设备上,当用户取消授权之后,再次点击选择收货地址按钮的时候,无法弹出授权的提示框!

  1. 导致问题的原因 - 用户取消授权后,再次点击“选择收货地址”按钮的时候:
  • 在模拟器和安卓真机上,错误消息 err.errMsg 的值为 chooseAddress:fail authdeny
  • iPhone 真机上,错误消息 err.errMsg 的值为 chooseAddress:fail authorizeno response
  1. 解决问题的方案 - 修改 chooseAddress 方法中的代码,进一步完善用户没有授权时的 if 判断条件即可:
async chooseAddress() {
  // 1. 调用小程序提供的 chooseAddress() 方法,即可使用选择收货地址的功能
  //    返回值是一个数组:第1项为错误对象;第2项为成功之后的收货地址对象
  const [err, succ] = await uni.chooseAddress().catch(err => err)
  // 2. 用户成功的选择了收货地址
  if (succ && succ.errMsg === 'chooseAddress:ok') {
    this.updateAddress(succ)
  }
  // 3. 用户没有授权
  if (err && (err.errMsg === 'chooseAddress:fail auth deny' || err.errMsg === 'chooseAddress:fail authorize no response')) {
    this.reAuth()
  }
}



目录
相关文章
|
2月前
|
数据可视化 API
低代码可视化-uniapp购物车页面-代码生成器
低代码可视化-uniapp购物车页面-代码生成器
40 1
|
2月前
|
JavaScript 数据安全/隐私保护
uniapp功能权限判断$auth.auth $auth.role显示判断生成源码
uniapp功能权限判断$auth.auth $auth.role显示判断生成源码
27 0
|
4月前
|
开发框架 移动开发 前端开发
基于SqlSugar的开发框架循序渐进介绍(19)-- 基于UniApp+Vue的移动前端的功能介绍
基于SqlSugar的开发框架循序渐进介绍(19)-- 基于UniApp+Vue的移动前端的功能介绍
|
5月前
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp的多功能智能手机阅读APP的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue+uniapp的多功能智能手机阅读APP的详细设计和实现(源码+lw+部署文档+讲解等)
|
5月前
|
移动开发 前端开发 小程序
uniapp内置组件uni.navigateTo跳转后页面空白问题解决
【7月更文挑战第1天】uniapp内置组件uni.navigateTo跳转后页面空白问题解决
125 4
|
5月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的多功能智能手机阅读APP附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的多功能智能手机阅读APP附带文章源码部署视频讲解等
79 1
|
5月前
|
小程序 UED
uniapp 添加分包页面,配置分包预下载
uniapp 添加分包页面,配置分包预下载
96 2
|
6月前
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp的多功能智能手机阅读APP的详细设计和实现
基于SpringBoot+Vue+uniapp的多功能智能手机阅读APP的详细设计和实现
83 12
|
5月前
|
前端开发 JavaScript 索引
uniapp的u-album组件自定义删除功能
这样,你就可以在u-album组件中实现自定义的删除功能了。需要注意的是,这个删除操作只是在前端删除了图片项,并没有在后端删除对应的图片文件,如果你需要在后端也删除对应的图片文件,你还需要在删除操作后发送一个请求到后端,让后端删除对应的图片文件。
120 0
|
5月前
|
小程序
uniapp如何隐藏默认的页面头部导航栏,uniapp开发小程序如何隐藏默认的页面头部导航栏
uniapp如何隐藏默认的页面头部导航栏,uniapp开发小程序如何隐藏默认的页面头部导航栏
608 0