uniapp——项目day04

news2024/11/20 10:20:50

购物车页面——商品列表区域

渲染购物车商品列表的标题区域

1. 定义如下的 UI 结构:

2.美化样式

渲染商品列表区域的基本结构

1. 通过 mapState 辅助函数,将 Store 中的 cart 数组映射到当前页面中使用:

  import badgeMix from '@/mixins/tabbar-badge.js'
  // 按需导入 mapState 这个辅助函数
  import {
    mapState
  } from 'vuex'
  export default {
    mixins: [badgeMix],
    computed: {
      // 将 m_cart 模块中的 cart 数组映射到当前页面中使用
      ...mapState('m_cart', ['cart']),
    },
    data() {
      return {}
    },
  }

2. 在 UI 结构中,通过 v-for 指令循环渲染自定义的 my-goods 组件:

    <!-- 商品列表区域 -->
    <block v-for="(goods, i) in cart" :key="i">
      <my-goods :goods="goods"></my-goods>
    </block>

为 my-goods 组件封装 radio 勾选状态

1. 打开 my-goods.vue 组件的源代码,为商品的左侧图片区域添加 radio 组件:

2. 给类名为 goods-item-left 的 view 组件添加样式,实现 radio 组件和 image 组件的左 右布局:

  .goods-item-left {
    margin-right: 5px;
    display: flex;
    justify-content: space-between;
    align-items: center;

    .goods-pic {
      width: 100px;
      height: 100px;
      display: block;
    }
  }

 3. 封装名称为 showRadio 的 props 属性,来控制当前组件中是否显示 radio 组件:

    // 定义 props 属性,用来接收外界传递到当前组件的数据
    props: {
      // 商品的信息对象
      goods: {
        type: Object,
        default: {},
      },
      // 是否展示图片左侧的 radio
      showRadio: {
        type: Boolean,
        // 如果外界没有指定 show-radio 属性的值,则默认不展示 radio 组件
        default: false,
      },
    },

4. 使用 v-if 指令控制 radio 组件的按需展示:

 5. 在 cart.vue 页面中的商品列表区域,指定 :show-radio="true" 属性,从而显示 radio 组 件:

6. 修改 my-goods.vue 组件,动态为 radio 绑定选中状态:

 为 my-goods 组件封装 radio-change 事件

1. 当用户点击 radio 组件,希望修改当前商品的勾选状态,此时用户可以为 my-goods 组件绑定 @radio-change 事件,从而获取当前商品的 goods_id 和 goods_state :

    <!-- 商品列表区域 -->
    <block v-for="(goods, i) in cart" :key="i">
      <!-- 在 radioChangeHandler 事件处理函数中,通过事件对象 e,得到商品的 goods_id
      和 goods_state -->
      <my-goods :goods="goods" :show-radio="true" @radiochange="radioChangeHandler"></my-goods>
    </block>

定义 radioChangeHandler 事件处理函数如下:

methods: {
// 商品的勾选状态发生了变化
radioChangeHandler(e) {
console.log(e) // 输出得到的数据 -> {goods_id: 395, goods_state: false}
}
}

 2. 在 my-goods.vue 组件中,为 radio 组件绑定 @click 事件处理函数如下:

3. 在 my-goods.vue 组件的 methods 节点中,定义 radioClickHandler 事件处理函数:

修改购物车中商品的勾选状态

1. 在 store/cart.js 模块中,声明如下的 mutations 方法,用来修改对应商品的勾选状态:

// 更新购物车中商品的勾选状态
    updateGoodsState(state, goods) {
      // 根据 goods_id 查询购物车中对应商品的信息对象
      const findResult = state.cart.find(x => x.goods_id === goods.goods_id)
      // 有对应的商品信息对象
      if (findResult) {
        // 更新对应商品的勾选状态
        findResult.goods_state = goods.goods_state
        // 持久化存储到本地
        this.commit('m_cart/saveToStorage')
      }
    }

2. 在 cart.vue 页面中,导入 mapMutations 这个辅助函数,从而将需要的 mutations 方法映 射到当前页面中使用:

  import badgeMix from '@/mixins/tabbar-badge.js'
  import {
    mapState,
    mapMutations
  } from 'vuex'
  export default {
    mixins: [badgeMix],
    computed: {
      ...mapState('m_cart', ['cart']),
    },
    data() {
      return {}
    },
    methods: {
      ...mapMutations('m_cart', ['updateGoodsState']),
      // 商品的勾选状态发生了变化
      radioChangeHandler(e) {
        this.updateGoodsState(e)
      },
    },
  }

为 my-goods 组件封装 NumberBox

注意:NumberBox 组件是 uni-ui 提供的

1. 修改 my-goods.vue 组件的源代码,在类名为 goods-info-box 的 view 组件内部渲染 NumberBox 组件的基本结构:

2. 美化页面的结构:

 .goods-item-right {
      display: flex;
      flex: 1;
      flex-direction: column;
      justify-content: space-between;

      .goods-name {
        font-size: 13px;
      }

      .goods-info-box {
        display: flex;
        align-items: center;
        justify-content: space-between;
      }

      .goods-price {
        font-size: 16px;
        color: #c00000;
      }
    }

3. 在 my-goods.vue 组件中,动态为 NumberBox 组件绑定商品的数量值:

      <view class="goods-info-box">
        <!-- 商品价格 -->
        <view class="goods-price">¥{{goods.goods_price | tofixed}}</view>
        <!-- 商品数量 -->
        <uni-number-box :min="1" :value="goods.goods_count"></uni-number-box>
      </view>

4. 在 my-goods.vue 组件中,封装名称为 showNum 的 props 属性,来控制当前组件中是否显 示 NumberBox 组件:

 // 是否展示价格右侧的 NumberBox 组件
      showNum: {
        type: Boolean,
        default: false,
      },

 5. 在 my-goods.vue 组件中,使用 v-if 指令控制 NumberBox 组件的按需展示:

      <view class="goods-info-box">
        <!-- 商品价格 -->
        <view class="goods-price">¥{{goods.goods_price | tofixed}}</view>
        <!-- 商品数量 -->
        <uni-number-box :min="1" :value="goods.goods_count" @change="numChangeHandler" v-if="showNum"></uni-number-box>
      </view>

6. 在 cart.vue 页面中的商品列表区域,指定 :show-num="true" 属性,从而显示 NumberBox 组件:

    <!-- 商品列表区域 -->
    <block v-for="(goods, i) in cart" :key="i">
      <my-goods :goods="goods" :show-radio="true" :show-num="true" @radio-change="radioChangeHandler"></my-goods>
    </block>

为 my-goods 组件封装 num-change 事件

1. 当用户修改了 NumberBox 的值以后,希望将最新的商品数量更新到购物车中,此时用户可以为 my-goods 组件绑定 @num-change 事件,从而获取当前商品的 goods_id 和 goods_count:

    <!-- 商品列表区域 -->
    <block v-for="(goods, i) in cart" :key="i">
      <my-goods :goods="goods" :show-radio="true" :show-num="true" @radiochange="radioChangeHandler"
        @num-change="numberChangeHandler"></my-goods>
    </block>

定义 numberChangeHandler 事件处理函数如下:

// 商品的数量发生了变化
numberChangeHandler(e) {
console.log(e)
}

2. 在 my-goods.vue 组件中,为 uni-number-box 组件绑定 @change 事件处理函数如下:

      <view class="goods-info-box">
        <!-- 商品价格 -->
        <view class="goods-price">¥{{goods.goods_price | tofixed}}</view>
        <!-- 商品数量 -->
        <uni-number-box :min="1" :value="goods.goods_count" @change="numChangeHandler"></uni-number-box>
      </view>

3. 在 my-goods.vue 组件的 methods 节点中,定义 numChangeHandler 事件处理函数:

// NumberBox 组件的 change 事件处理函数
      numChangeHandler(val) {
        // 通过 this.$emit() 触发外界通过 @ 绑定的 num-change 事件
        this.$emit('num-change', {
          // 商品的 Id
          goods_id: this.goods.goods_id,
          // 商品的最新数量
          goods_count: +val
        })
      }

解决 NumberBox 数据不合法的问题

问题说明:当用户在 NumberBox 中输入字母等非法字符之后,会导致 NumberBox 数据紊乱的问 题

现在那个组件已经修复了这个问题了,所以不需要再修改源代码。

完善 NumberBox 的 inputValue 侦听器

问题说明:在用户每次输入内容之后,都会触发 inputValue 侦听器,从而调用 this.$emit("change", newVal) 方法。这种做法可能会把不合法的内容传递出去!

现在这个问题也修复了,输入带小数的数字也会四舍五入。

修改购物车中商品的数量

1. 在 store/cart.js 模块中,声明如下的 mutations 方法,用来修改对应商品的数量:

    // 更新购物车中商品的数量
    updateGoodsCount(state, goods) {
      // 根据 goods_id 查询购物车中对应商品的信息对象
      const findResult = state.cart.find(x => x.goods_id === goods.goods_id)
      if (findResult) {
        // 更新对应商品的数量
        findResult.goods_count = goods.goods_count
        // 持久化存储到本地
        this.commit('m_cart/saveToStorage')
      }
    }

2. 在 cart.vue 页面中,通过 mapMutations 这个辅助函数,将需要的 mutations 方法映射 到当前页面中使用:

  import badgeMix from '@/mixins/tabbar-badge.js'
  import {
    mapState,
    mapMutations
  } from 'vuex'
  export default {
    mixins: [badgeMix],
    computed: {
      ...mapState('m_cart', ['cart']),
    },
    data() {
      return {}
    },
    methods: {
      ...mapMutations('m_cart', ['updateGoodsState', 'updateGoodsCount']),
      // 商品的勾选状态发生了变化
      radioChangeHandler(e) {
        this.updateGoodsState(e)
      },
      // 商品的数量发生了变化
      numberChangeHandler(e) {
        this.updateGoodsCount(e)

      },
    },
  }

渲染滑动删除的 UI 效果

滑动删除需要用到 uni-ui 的 uni-swipe-action 组件和 uni-swipe-action-item。详细的官方文档请参 考SwipeAction 滑动操作。

1. 改造 cart.vue 页面的 UI 结构,将商品列表区域的结构修改如下(可以使用 uSwipeAction 代 码块快速生成基本的 UI 结构):

    <!-- 商品列表区域 -->
    <!-- uni-swipe-action 是最外层包裹性质的容器 -->
    <uni-swipe-action>
      <block v-for="(goods, i) in cart" :key="i">
        <!-- uni-swipe-action-item 可以为其子节点提供滑动操作的效果。需要通过
options 属性来指定操作按钮的配置信息 -->
        <uni-swipe-action-item :right-options="options" @click="swipeActionClickHandler(goods)">
          <my-goods :goods="goods" :show-radio="true" :show-num="true" @radio-change="radioChangeHandler"
            @num-change="numberChangeHandler"></my-goods>
        </uni-swipe-action-item>
      </block>
    </uni-swipe-action>

2. 在 data 节点中声明 options 数组,用来定义操作按钮的配置信息:

        options: [{
          text: '删除', // 显示的文本内容
          style: {
            backgroundColor: '#C00000' // 按钮的背景颜色
          }
        }]

3. 在 methods 中声明 uni-swipe-action-item 组件的 @click 事件处理函数:

// 点击了滑动操作按钮
swipeActionClickHandler(goods) {
console.log(goods)
}

4. 美化 my-goods.vue 组件的样式: 

.goods-item {
// 让 goods-item 项占满整个屏幕的宽度
width: 750rpx;
// 设置盒模型为 border-box
box-sizing: border-box;
display: flex;
padding: 10px 5px;
border-bottom: 1px solid #f0f0f0;
}

实现滑动删除的功能

1. 在 store/cart.js 模块的 mutations 节点中声明如下的方法,从而根据商品的 Id 从购物车 中移除对应的商品:

// 根据 Id 从购物车中删除对应的商品信息
removeGoodsById(state, goods_id) {
// 调用数组的 filter 方法进行过滤
state.cart = state.cart.filter(x => x.goods_id !== goods_id)
// 持久化存储到本地
this.commit('m_cart/saveToStorage')
}

2. 在 cart.vue 页面中,使用 mapMutations 辅助函数,把需要的方法映射到当前页面中使 用:

购物车页面——收货地址区域

创建收货地址组件

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>138XXXX5555</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 河北省邯郸市肥乡区xxx 河北
          省邯郸市肥乡区xxx 河北省邯郸市肥乡区xxx </view>
      </view>
    </view>
    <!-- 底部的边框线 -->
    <image src="/static/cart_border@2x.png" class="address-border"></image>
  </view>

3. 美化收货地址组件的样式:

  // 底部边框线的样式
  .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;
      }
    }
  }

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

1. 在 data 中定义收货地址的信息对象:

        // 收货地址
        address: {},

2. 使用 v-if 和 v-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>

实现选择收货地址的功能

避坑:

小程序提供的chooseAddress()方法显示张三地址页面,在manifest.json文件中,找到mp-weixin节点,添加上:

 "requiredPrivateInfos": [

         "chooseLocation",

         "getLocation", 

         "chooseAddress"

         ]

然后才能看见这个页面,不然会一直报错

1. 为 请选择收货地址+ 的 button 按钮绑定点击事件处理函数:

<!-- 选择收货地址的盒子 -->
<view class="address-choose-box" v-if="JSON.stringify(address) === '{}'">
<button type="primary" size="mini" class="btnChooseAddress"
@click="chooseAddress">请选择收货地址+</button>
</view>

2. 定义 chooseAddress 事件处理函数,调用小程序提供的 chooseAddress() API 实现选择收 货地址的功能:

 // 选择收货地址
      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
        }

3. 定义收货详细地址的计算属性:

computed: {
        // 收货详细地址的计算属性
        addstr() {
          if (!this.address.provinceName) return ''
          // 拼接 省,市,区,详细地址 的字符串并返回给用户
          return this.address.provinceName + this.address.cityName +
            this.address.countyName + this.address.detailInfo
        }
      }

4. 渲染收货地址区域的数据:

    <!-- 渲染收货信息的盒子 -->
    <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>

将 address 信息存储到 vuex 中

这里好像要真机调试才可以获取到地址。

1. 在 store 目录中,创建用户相关的 vuex 模块,命名为 user.js :

export default {
  // 开启命名空间
  namespaced: true,
  // state 数据
  state: () => ({
    // 收货地址
    address: {},
  }),
  // 方法
  mutations: {
    // 更新收货地址
    updateAddress(state, address) {
      state.address = address
    },
  },
  // 数据包装器
  getters: {},
}

2. 在 store/store.js 模块中,导入并挂载 user.js 模块:

这个是vue3的做法

// 1. 导入 Vue 和 Vuex
import {
  createStore
} from 'vuex'
import moduleCart from './cart.js'
// 导入用户的 vuex 模块
import moduleUser from './user.js'
// 2. 创建 Store 的实例对象
const store = createStore({
  modules: {
    m_cart: moduleCart,
    // 挂载用户的 vuex 模块,访问路径为 m_user
    m_user: moduleUser,
  },
})

// 3. 向外共享 Store 的实例对象
export default store

3. 改造 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
      },
    },
  }

将 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: {},
}

将 addstr 抽离为 getters

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

1. 剪切 my-address.vue 组件中的 addstr 计算属性的代码,粘贴到 user.js 模块中,作为 一个 getters 节点:

    // 收货详细地址的计算属性
    addstr(state) {
      if (!state.address.provinceName) return ''
      // 拼接 省,市,区,详细地址 的字符串并返回给用户
      return state.address.provinceName + state.address.cityName +
        state.address.countyName + state.address.detailInfo
    }

2. 改造 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']),
},
}

重新选择收货地址

1. 为 class 类名为 address-info-box 的盒子绑定 click 事件处理函数如下:

<!-- 渲染收货信息的盒子 -->
<view class="address-info-box" v-else @click="chooseAddress">
<!-- 省略其它代码 -->
</view>

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

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

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() 方法,向用户重新发起授权申请
        }
      }

2. 在 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('您取消了地址授权!')
          }
        })
      }

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

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

      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()
        }
      }

 BUG修改

在选择收货地址方法里面

        const [err, succ] = await uni.chooseAddress().catch(err => err)
这条语句会报错不能执行,需要改成如下语句

// 选择收货地址
      async chooseAddress() {
        // 1. 调用小程序提供的 chooseAddress() 方法,即可使用选择收货地址的功能
        // 返回值是一个数组:第1项为错误对象;第2项为成功之后的收货地址对象
        let succ = null;
        let err = null;
        try {
          const res = await uni.chooseAddress();
           err = null;
           succ = res;
          console.log(res)
        } catch (error) {
           err = error;
           succ = null;
          // 处理错误的逻辑
          console.error(error);
        }
        
        // 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()
        }
      }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1204091.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023年【建筑电工(建筑特殊工种)】找解析及建筑电工(建筑特殊工种)复审考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 建筑电工(建筑特殊工种)找解析是安全生产模拟考试一点通生成的&#xff0c;建筑电工(建筑特殊工种)证模拟考试题库是根据建筑电工(建筑特殊工种)最新版教材汇编出建筑电工(建筑特殊工种)仿真模拟考试。2023年【建筑电…

1 Supervised Machine Learning Regression and Classification

文章目录 Week1OverViewSupervised LearningUnsupervised LearningLinear Regression ModelCost functionGradient Descent Week2Muliple FeatureVectorizationGradient Descent for Multiple RegressionFeature ScalingGradient DescentFeature EngineeringPolynomial Regress…

数据结构线性表——栈

前言&#xff1a;哈喽小伙伴们&#xff0c;今天我们将一起进入数据结构线性表的第四篇章——栈的讲解&#xff0c;栈还是比较简单的哦&#xff0c;跟紧博主的思路&#xff0c;不要掉队哦。 目录 一.什么是栈 二.如何实现栈 三.栈的实现 栈的初始化 四.栈的操作 1.数据入栈…

CTFhub-RCE-读取源代码

源代码&#xff1a; <?php error_reporting(E_ALL); if (isset($_GET[file])) { if ( substr($_GET["file"], 0, 6) "php://" ) { include($_GET["file"]); } else { echo "Hacker!!!"; } } else {…

重磅!2024QS亚洲大学排名出炉!北大蝉联榜首,港大反超新国立、清华!

2023年11月8日&#xff0c;全球高等教育分析机构QS Quacquarelli Symonds发布了2024年QS世界大学排名&#xff1a;亚洲大学排名。 本次排名全方位评估了来自亚洲25个国家和地区的856所大学在全球认可度、研究实力、教学资源和国际化等方面的表现&#xff0c;有148所院校首次跻…

绝望了,软件测试的行业基本盘,崩了......

不得不承认&#xff0c;现在工作不好找 去年很多人都觉得今年的就业环境会好很多&#xff0c;但是到了现在都发现之前想错了&#xff0c;实际上是一塌糊涂… 于是有了很多年轻人焦虑日常的灵魂一问&#xff1a;“快半年了&#xff0c;找不到工作&#xff0c;我好焦虑&#xf…

Git的GUI图形化工具ssh协议IDEA集成Git

一、GIT的GUI图形化工具 1、介绍 Git自带的GUI工具&#xff0c;主界面中各个按钮的意思基本与界面文字一致&#xff0c;与git的命令差别不大。在了解自己所做的操作情况下&#xff0c;各个功能点开看下就知道是怎么操作的。即使不了解&#xff0c;只要不做push操作&#xff0c…

LeetCode-剑指 Offer 22. 链表中倒数第k个节点(C语言 )

目录捏 一、题目描述二、示例与提示三、思路四、代码 一、题目描述 给定一个头节点为 head 的链表用于记录一系列核心肌群训练项目编号&#xff0c;请查找并返回倒数第 cnt 个训练项目编号。 二、示例与提示 示例 1&#xff1a; 输入&#xff1a; head [2,4,7,8], cnt 1 输…

Linux 源码包安装

SRPM 包&#xff0c;比 RPM 包多了一个“S”&#xff0c;是“Source”的首字母&#xff0c;所以 SRPM 可直译为“源代码形式的 RPM 包”。也就是说&#xff0c;SRPM 包中不再是经过编译的二进制文件&#xff0c;都是源代码文件。可以这样理解&#xff0c;SRPM 包是软件以源码形…

新生儿母乳过敏:原因、科普和注意事项

引言&#xff1a; 母乳过敏是一种较为罕见但可能令家长担忧的现象。母亲通常认为母乳是新生儿最安全、最适合的食物&#xff0c;然而有时候宝宝可能对母乳中的某些成分产生过敏反应。本文将科普新生儿母乳过敏的原因&#xff0c;提供相关信息&#xff0c;并为父母和监护人提供…

轻量封装WebGPU渲染系统示例<27>- 浮点RTT纹理(源码)

当前示例源码github地址: https://github.com/vilyLei/voxwebgpu/blob/feature/rendering/src/voxgpu/sample/FloatRTT.ts 当前示例运行效果: 此示例基于此渲染系统实现&#xff0c;当前示例TypeScript源码如下: const floatRTT { diffuse: { uuid: "rtt0", rttTe…

SPC on-line 应用探讨

中国是制造业大国&#xff0c;大部分工厂主要重点是将原料经由加工制造过程&#xff08;或流程&#xff09;转变为最终可销售的产品或服务。”产品”是经过被定义的规格下&#xff08;定义规格者包含客户、制造商本身、供应商…等&#xff09;&#xff0c;在经过”受控制”的人…

Linux C 进程编程

进程编程 进程介绍进程的定义进程和线程以及程序的区别进程块PCB进程的状态相关指令 进程调度算法先来先服务调度算法 FCFS短作业(进程)优先调度算法 SJF优先权调度算法 FPF优先权调度算法的类型非抢占式优先权算法抢占式优先权算法 优先权类型静态优先权动态优先权 高响应比优…

RT-DETR算法优化改进:Backbone改进 | HGBlock完美结合PPHGNetV2 GhostConv

💡💡💡本文独家改进: GhostConv助力RT-DETR ,HGBlock与PPHGNetV2 GhostConv完美结合 推荐指数:五星 HGBlock_GhostConv | 亲测在多个数据集能够实现涨点 RT-DETR魔术师专栏介绍: https://blog.csdn.net/m0_63774211/category_12497375.html ✨✨✨魔改创新RT-…

202311.13 windows通过vscode ssh远程连接到Ubuntu 连接失败 waiting for server log

关闭VScode时没有关闭终端的Ubuntu进程&#xff1f; 导致重启后不能正常连接到Ubuntu了 Windows 系统自带的cmd终端通过ssh 可以连接 应该是vscode里对Ubuntu 的服务器端配置出了问题 参考&#xff1a;记录 VSCode ssh 连接远程服务器时出错及解决方法 在Windows 的vscode里面执…

jumpserver任意密码重置漏洞-CVE-2023-42820

目录 jumpserver 环境搭建 这里用的是vulhub靶场 进入 jumpserver 的目录 修改配置文件 config.env 里面的 DOMAINS 参数为kali的地址 运行环境&#xff0c;第一次运行的话会拉取文件&#xff0c;要耐心等待。 命令&#xff1a; 查看docker容器 命令&#xff1a; 用浏…

【兔子王赠书第7期】机器学习与人工智能实战:基于业务场景的工程应用

文章目录 写在前面机器学习推荐图书写给读者前言本书面向的读者我为什么要写这本书运行本书的示例代码本书导航本书采用的约定使用代码示例 推荐理由粉丝福利写在后面 写在前面 新的一周开始啦&#xff0c;本周博主给大家带来《机器学习与人工智能实战&#xff1a;基于业务场景…

C语言ZZULIOJ1149:组合三位数之二

题目描述 把1&#xff0c;2&#xff0c;3&#xff0c;4&#xff0c;5&#xff0c;6&#xff0c;7&#xff0c;8&#xff0c;9&#xff0c;组成三个三位数&#xff08;每个数只能用一次&#xff09;,第二个数是第一个数的2倍&#xff0c;第三个数是第一个数的3倍&#xff0c;这三…

Autosar模块介绍:Memory_5(FEE-Flash模拟EE)

上一篇 | 返回主目录 | 下一篇 Autosar模块介绍&#xff1a;Memory_5(FEE-Flash模拟EE 1 基本术语解释2 Fee组成结构图3 Fee基本操作3.1 寻址方式和段划分3.2 地址计算3.3 擦除循环限制3.4 处理立即数据3.5 管理块的正确信息 4 Fee常用操作时序4.1 Fee_Init4.2 Fee_SetMode4.…