微信小程序(黑马优购:购物车页面)

 1.渲染商品页面

<template>
  <view>
    <!-- 商品列表的标题区域 -->
    <view class="cart-title">
        <!-- 左侧的图标 -->
        <uni-icons type="shop" size="18"></uni-icons>
        <!-- 右侧的文本 -->
        <text class="cart-title-text">购物车</text>
    </view>
    
    <!-- 循环渲染购物车中的商品信息 -->
    <block v-for="(goods,i) in cart" :key="i">
      <my-goods :goods="goods"></my-goods>
    </block>

  </view>
</template>

<script>
  
  import badgeMix from '@/mixins/tabbar-badge.js'
  import { mapState } from 'vuex'  
  
  export default {
    mixins: [badgeMix],
    computed: {
        ...mapState('m_cart',['cart'])
    },
    data() {
      return {

      }
    }

  }
</script>

2.展示购物车选中状态

mygoods.vue中配置
 

  <view class="goods-item-left">
      <radio checked color="#C00000" v-if="showRadio"></radio>
      <image :src="goods.goods_small_logo || defaultPic" class="goods-pic"></image>
    </view>

引入showRadio组件,判断是否选中

 props: {
      goods: {
        type: Object,
        default: {}
      },
      showRadio: {
        type: Boolean,
        //默认情况下,不会展示radio组件
        default: false
      }
    },

1)动态修改
 

 <radio :checked="goods.goods_state" color="#C00000" v-if="showRadio"></radio>

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

  <!-- 循环渲染购物车中的商品信息 -->
    <block v-for="(goods,i) in cart" :key="i">
      <my-goods :goods="goods" :show-radio="true" @radio-change="radioChangeHandler"></my-goods>
    </block>

  <view class="goods-item-left">
      <radio :checked="goods.goods_state" color="#C00000" v-if="showRadio" @click="radioClickHandler"></radio>
      <image :src="goods.goods_small_logo || defaultPic" class="goods-pic"></image>
    </view>
methods:{
      //这是radio组件的点击事件处理函数
      radioClickHandler(){
        this.$emit('radio-change',{
           goods_id: this.goods.goods_id,
           goods_state: !this.goods.goods_state
        })
      }
    }

cart.js中配置

export default{
  namespaced: true,
  
  state: ()=> ({
    //购物车的数组,用来存储购物车中每个商品的信息对象
    //每个商品的信息对象,都包含如下6个属性
    //{goods_id,goods_name,goods_price,goods_count,goods_small_logo,goods_state}
    cart: JSON.parse(uni.getStorageSync('cart') || '[]')
  }),
  
  mutations: {
    addToCart(state,goods){
      //根据提交的商品的id,查询购物车中是否存在这件商品
      //如果不存在,则findResult为undefined;否则,为查找到的商品信息对象
      const findResult = state.cart.find(x => x.goods_id === goods.goods_id)
      
      if(!findResult){
        //如果购物车中没有这件商品,则直接push
        state.cart.push(goods)
      }else{
        //如果购物车中有这件商品,则只更新数量即可
        findResult.goods_count++
      }
      //通过commit方法,调用m_cart命名空间的saveToStorage方法
      this.commit('m_cart/saveToStorage')
      
    },
    
    saveToStorage(state){
        uni.setStorageSync('cart',JSON.stringify(state.cart))
    },
    
    //更新购物车中商品的勾选状态
    updateGoodsState(state,goods){
      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')
      }
      
      
    }
    
    
    
  },

  getters: {
    total(state){
      let c = 0
      state.cart.forEach(x => c += x.goods_count)
      return c
    }
  }
}

cart.vue中配置

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

3)渲染数字选择框

  <view class="goods-item-right">
      <!-- 商品的名字 -->
      <view class="goods-name">{{goods.goods_name}}</view>
      <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>
    </view>

3控制选择框按需展示/隐藏

cart.vue

  <!-- 循环渲染购物车中的商品信息 -->
    <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.vue

 <!-- 数字选择框 -->
        <uni-number-box :min="1" :value="goods.goods_count" v-if="showNum"></uni-number-box>

props: {
   
      showNum: {
        type: Boolean,
        default: false
      }

    },

引入NumberBox组件

my-goods.vue

 <!-- 数字选择框 -->
        <uni-number-box :min="1" :value="goods.goods_count" v-if="showNum" @change="numChangeHandler"></uni-number-box>

 //监听到了NumberBox组件数量变化的事件9
      numChangeHandler(val){
          this.$emit('num-change',{
            goods_id: this.goods.goods_id,
            goods_count: +val  ///或者val-0   (这是为了确保val是一个数值)
          })
      }

cart.vue

 <my-goods :goods="goods" :show-radio="true" :show-num="true" @radio-change="radioChangeHandler"
              @num-change="numberChangeHandler"
      ></my-goods>

numberChangeHandler(e){
        console.log(e);
      }

4.修改购物车商品数量

cart.js中新增函数

 //更新商品的数量
    updateGoodsCount(state,goods){
      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')
      }
    }

cart.vue中配置

 methods:{
      ...mapMutations('m_cart',['updateGoodsState','updateGoodsCount']),
      radioChangeHandler(e){
        this.updateGoodsState(e)
      },
      numberChangeHandler(e){
          this.updateGoodsCount(e)
      }
    }
 

5.购物车滑动删除UI效果

 

  <!-- 滑动删除效果 -->
    <uni-swipe-action>
      <block v-for="(goods,i) in cart" :key="i">
         <uni-swipe-action-item :right-options="options">
             <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>

  data() {
      return {
        options: [{
          text: '删除',
          style: {
            backgroundColor: '#C00000'
          }
        }]
      }
    },

6.商品列表实现滑动删除

cart.js配置

 //根据id删除对应的商品
    removeGoodsById(state,goods_id){
      state.cart =  state.cart.filter(x => x.goods_id !== goods_id)
      this.commit('m_cart/saveToStorage')
    }v

cart.vue

   swipeItemClickHandler(goods){
        this.removeGoodsById(goods.goods_id)
      }

7.收货地址

1)微信小程序中点击跳转到选择地址

manifest.json中配置

  /* 快应用特有相关 */
    "mp-weixin" : {
        /* 小程序特有相关 */
        "appid" : "",
        "setting" : {
          // 取消黄色警告
            "urlCheck" : true,
            "checkSiteMap": false
        },
        "usingComponents" : true,
         "permissions": {
            "chooseAddress": {
              "desc": "你的文字描述" // 这里是对权限的描述,可以自定义
            }

          },
        "requiredPrivateInfos":["chooseAddress"]
    },

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

2)渲染收货人信息

<!-- 渲染收货信息的盒子 -->
    <view class="address-info-box" v-else>
        <view class="row1">
          <view class="row1-left">
            <view class="username">收货人: {{address.userName}}</view>
          </view>
          <view class="row1-right">
            <view class="phone">电话: {{address.telNumber}}</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>

 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

            console.log(succ);
          }

        }
    },
    //计算属性
    computed:{
      addstr(){
        if(!this.address.provinceName) {
          return ''
        } 
        return this.address.provinceName + this.address.cityName + this.address.countyName + this.address.detailInfo
      }
    }

3)改造收货地址方法

创建user.js

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

挂载到store.js中


import moduleUser from '@/store/user.js'

Vue.use(Vuex)

const store = new Vuex.Store({
  modules:{
    //挂载购物车的vuex模块,模块内成员的访问路径被调整为m_cart,例如:
    //购物车模块中cart 数组的访问路径是 m_cart/cart
    'm_cart': moduleCart,
    'm_user': moduleUser
  }
})

export default store

在my-address.vue调用

  import { mapState, mapMutations, mapGetters } from 'vuex'

 ...mapMutations('m_user',['updateAddress']),
       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
            this.updateAddress(succ)
          }

        }

  //计算属性
    computed:{
      ...mapState('m_user',['address']),
      addstr(){
        if(!this.address.provinceName) {
          return ''
        } 
        return this.address.provinceName + this.address.cityName + this.address.countyName + this.address.detailInfo
      }
    }

4)将Store中的address持久化存储到本地

user.js中配置

export default{
  //开启命名空间
  namespaced: true,
  //数据
  state: () =>({
    // address: {}
    address: JSON.parse(uni.getStorageSync('address') || '{}')
  }),
  //方法
  mutations: {
    //更改收货地址
    updateAddress(state,address){
      state.address = address
      this.commit('m_user/saveAddressToStorage')
    },

    //持久化存储 address
    saveAddressToStorage(state){
      uni.setStorageSync('address',JSON.stringify(state.address))
    }

  },
  getters: {}
}

5)将addstr抽离为getters

user.js

 getters: {
    addstr(state){
      if(!state.address.provinceName) {
        return ''
      } 
      return state.address.provinceName + state.address.cityName + state.address.countyName + state.address.detailInfo
    }
  }

 my-address.vue

  import { mapState, mapMutations, mapGetters } from 'vuex'

//计算属性
    computed:{
      ...mapState('m_user',['address']),
      ...mapGetters('m_user',['addstr'])
    }
    

6)重新选择收货地址

<!-- 渲染收货信息的盒子 -->
    <view class="address-info-box" v-else  @click="chooseAddress">

8.结算组件

my-settle.vue

1)渲染

  <view class="my-settle-container">
    <!-- 全选 -->
    <label class="radio">
      <radio color="#C00000" /><text></text>
    </label>
    
    <!-- 合计 -->
    <view class="amount-box">
        合计:<text class="amount">¥123.00</text>
    </view>
    
    <!-- 结算按钮 -->
    <view class="btn-settle">结算(0)</view>
  </view>

2)动态渲染已勾选商品的总数量

cart.js中配置

 getters: {
    total(state){
      let c = 0
      state.cart.forEach(x => c += x.goods_count)
      return c
    },
    checkedCount(state){
      return  state.cart.filter(x => x.goods_state).reduce((total,item) =>  total += item.goods_count ,0)
    }

  }

my-settle.vue

<!-- 结算按钮 -->
    <view class="btn-settle">结算({{checkedCount}})</view>

import { mapGetters } from 'vuex'
  export default {
  
    computed: {
      ...mapGetters('m_cart',['checkedCount'])
    }
  }

3)动态渲染全选按钮的选中状态

my-settle.vue

 computed: {
      ...mapGetters('m_cart',['checkedCount','total']),
      isFullCheck(){
        return this.total === this.checkedCount
      }

4)使用数组的reduce方法改造total

cart.js

 //购物车中所有商品的总数量
    total(state){
      // let c = 0
      // state.cart.forEach(x => c += x.goods_count)
      // return c
     return state.cart.reduce((total,item) => total += item.goods_count,0)
    },

5)实现全选和反选功能

cart.js

//更新购物车中所有商品的勾选状态
    updateAllGoodsState(state,newState){
      state.cart.forEach(x => x.goods_state = newState)
      this.commit('m_cart/saveToStorage')
    }

my-settle.vue

<label class="radio" @click="changeAllState">

import { mapGetters,mapMutations } from 'vuex'

 methods:{
      ...mapMutations('m_cart',['updateAllGoodsState']),
      changeAllState(){
        this.updateAllGoodsState(!this.isFullCheck)
      }
    }

 6)动态渲染价格

cart.js

 //已勾选商品的总价格
    checkedGoodsAmount(state){
      return state.cart.filter(x => x.goods_state).reduce((total,item) => total += item.goods_count * item.goods_price,0).toFixed(2)
    }
    

my-settle.vue

    <!-- 合计 -->
    <view class="amount-box">
        合计:<text class="amount">¥{{checkedGoodsAmount}}</text>
    </view>

 computed: {
      ...mapGetters('m_cart',['checkedCount','total','checkedGoodsAmount']),
      isFullCheck(){
        return this.total === this.checkedCount
      }
    },

7)让购物车图标正确显示物品数量

tabbar-badge.js

 //计算属性
    computed: {
        ...mapGetters('m_cart',['total'])
    },
    watch:{
      total(){
        this.setBadge()
      }

    },

9.渲染购物车为空时的页面

 <view class="cart-container" v-if="cart.length !== 0">

<!-- 空白购物车的区域 -->
 <view class="empty-cart" v-else
      <image src="/static/cart_empty@2x.png" class="empty-img"></image>
      <text class="tip-text">空空如也~</text>
      
  </view>

相关推荐

  1. 程序(黑马:商品列表)

    2024-04-01 15:12:02       16 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-04-01 15:12:02       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-01 15:12:02       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-01 15:12:02       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-01 15:12:02       20 阅读

热门阅读

  1. 缓存的常见问题及其解法

    2024-04-01 15:12:02       10 阅读
  2. 巧克力(蓝桥杯)

    2024-04-01 15:12:02       19 阅读
  3. 本学期学习计划

    2024-04-01 15:12:02       22 阅读
  4. 【Docker笔记06】【容器编排】

    2024-04-01 15:12:02       15 阅读
  5. Qt 中 :deleteLater 总结

    2024-04-01 15:12:02       17 阅读
  6. VLAN配置及原理

    2024-04-01 15:12:02       14 阅读
  7. 网络常见的端口号

    2024-04-01 15:12:02       16 阅读
  8. 计算机填空知识点(3)完

    2024-04-01 15:12:02       15 阅读