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

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>

相关推荐
风等雨归期35 分钟前
【python】【绘制小程序】动态爱心绘制
开发语言·python·小程序
李宥小哥2 小时前
微信小程序07-开发进阶
微信小程序·小程序·notepad++
艾小逗3 小时前
uniapp快速入门教程,内容来源于官方文档,仅仅记录快速入门需要了解到的知识点
小程序·uni-app·app·es6
程序员阿龙3 小时前
【2025】儿童疫苗接种预约小程序(源码+文档+解答)
小程序·毕业设计·小程序开发·预约小程序·疫苗管理小程序·出勤数据分析·智能考勤
818源码资源站3 小时前
表情包创作、取图小程序端(带流量主)
小程序
2401_8459375313 小时前
PHP一键约课高效健身智能健身管理系统小程序源码
微信·微信小程序·小程序·微信公众平台·微信开放平台
程序员入门进阶15 小时前
基于微信小程序的科创微应用平台设计与实现+ssm(lw+演示+源码+运行)
微信小程序·小程序
计算机源码社1 天前
分享一个基于微信小程序的居家养老服务小程序 养老服务预约安卓app uniapp(源码、调试、LW、开题、PPT)
android·微信小程序·uni-app·毕业设计项目·毕业设计源码·计算机课程设计·计算机毕业设计开题
DreamByte1 天前
Python Tkinter小程序
开发语言·python·小程序
说私域1 天前
开源 AI 智能名片小程序:开启内容营销新境界
人工智能·小程序