uni-app商城(九)购物车页面

1.收货地址组件my-address.vue

<template>
	<view>
		<view class="address-choose-box" v-if="JSON.stringify(address)==='{}'">
			<button type="primary" size="mini" @click="chooseAddress">请选择收货地址+</button>
		</view>
		<!-- 收获地址信息盒子 -->
		<view class="address-info-box" v-else @click="chooseAddress">
			<view class="row1">
				<view class="row1-left">
					<view class="username">
						收货人:{{address.userName}}
					</view>
				</view>
				<view class="row1-right">
					<view class="phone">
						电话:{{address.telNumber}}
						<uni-icons type="arrowright" size="16"></uni-icons>
					</view>
				</view>
			</view>
			<view class="row2">
				<view class="row2-left">收获地址:</view>
				<view class="row2-right">
					{{addstr}}
				</view>
			</view>
		</view>
		<!-- 底部边框线 -->
		<image src="../../static/cart/1.png" class="address-border"></image>
	</view>
</template>

<script>
	import {
		mapState,
		mapMutations,
		mapGetters
	} from 'vuex';
	export default {
		name: "my-address",
		data() {
			return {
				// address: {}
			};
		},
		methods: {
			...mapMutations('m_user', ['updateAddress']),
			chooseAddress() {
				let that=this;
				uni.chooseAddress({
					success(res) {
						// this.address = res;
						that.updateAddress(res);
					}
				})
			}
		},
		computed: {
			...mapState('m_user', ['address']),
			...mapGetters('m_user',['addstr'])
		}
	}
</script>

<style lang="scss">
	.address-border {
		display: block;
		width: 100%;
		height: 5px;
	}
	.address-choose-box {
		display: flex;
		height: 90px;
		justify-content: center;
		align-items: center;
	}
	.address-info-box {
		font-size: 13px;
		height: 90px;
		display: flex;
		flex-direction: column;
		justify-content: center;
		padding: 0 5px;
		.row1 {
			display: flex;
			justify-content: space-between;

			.row1-right {
				display: flex;
				justify-content: space-between;
			}
		}
		.row2 {
			display: flex;
			align-items: center;

			.row2-left {
				white-space: nowrap;
			}
		}
	}
</style>

2.全局数据共享store-user.js

export default {
	// 开启命名空间
	namespaced: true,
	// 数据
	state: () => ({
		address: JSON.parse(uni.getStorageSync('address') || '{}'),
		token:''
	}),
	// 方法
	mutations: {
		//更新收货地址
		updateAddress(state, address) {
			state.address = address
			this.commit('m_user/saveAddressToStorage')
		},
		saveAddressToStorage(state) {
			uni.setStorageSync('address', JSON.stringify(state.address))
		}
	},
	getters: {
		addstr(state) {
			if (!state.address.provinceName) return '';
			return state.address.provinceName + state.address.cityName + state.address.countyName + state.address
				.detailInfo
		}
	}
}

3.mixins-TabBarBadge.js更新购物车角标

	import {mapGetters} from 'vuex'
	export default {
		computed:{
			...mapGetters('m_cart',['total'])
		},
		watch:{
			//监听购物车总数更新角标
			total(){
				this.setBadge()
			}
		},
		//购物车角标
		onShow() {
			this.setBadge()
		},
		methods:{
			//购物车数量
			setBadge(){
				uni.setTabBarBadge({
					index:2,
					text:this.total+''
				})
			}
		}
	}

4.结算组件my-settle.vue

<template>
	<view class="my-settle-container">
		<!-- 全选 -->
		<label class="radio" @click="changeAllState">
			<radio :checked="isFullCheck" /><text>全选</text>
		</label>
		<!-- 合计 -->
		<view class="amount-box">
			合计:<text class="amount">{{checkedGoodsAmount}}</text>
		</view>
		<!-- 结算 -->
		<view class="btn-settle" @click="settlement">结算({{checkedCount}})</view>
	</view>
</template>

<script>
	import {
		mapGetters,
		mapMutations,
		mapState
	} from 'vuex';
	export default {
		name: "my-settle",
		data() {
			return {

			};
		},
		computed: {
			...mapGetters('m_cart', ['checkedCount', 'total','checkedGoodsAmount']),
			...mapGetters('m_user', ['addstr']),
			...mapState('m_user',['token']),
			isFullCheck() {
				return this.total === this.checkedCount
			}
		},
		methods:{
			//使用 mapMutations 辅助函数,把 m_cart 模块提供的 updateAllGoodsState 方法映射到当前组件中使用
			...mapMutations('m_cart',['updateAllGoodsState']),
			changeAllState(){
				// 修改购物车中所有商品的选中状态
				// !this.isFullcheck 表示:当前全选按钮的状态取反之后,就是最新的勾选状态
				this.updateAllGoodsState(!this.isFullCheck)
			},
			//点击结算按钮
			settlement(){
				if(!this.checkedCount) return uni.$showMsg('请选择要结算的商品');
				
				if(!this.addstr) return uni.$showMsg('请选择收货地址');
				
				if(!this.token) return uni.$showMsg('请先登录')
			}
		}
	}
</script>

<style lang="scss">
	.my-settle-container {
		position: fixed;
		// bottom: 0;
		left: 0;
		width: 100%;
		height: 50px;
		display: flex;
		justify-content: space-between;
		align-items: center;
		font-size: 14px;
		padding-left: 5px;

	}
	.radio {
		display: flex;
		align-items: center;
	}
	.amount-box {
		.amount {
			color: #c00000;
			font-weight: bold;
		}
	}
	.btn-settle {
		background-color: #c00000;
		height: 50px;
		color: white;
		line-height: 50px;
		padding: 0 5px;
		width: 100px;
		text-align: center;
	}
</style>

5.store-cart.js

export default {
	//为当前模块开启命名空间
	namespaced: true,
	state: () => ({
		// 购物车存储的数据,每个商品的数据对象
		cart: JSON.parse(uni.getStorageSync('cart') || '[]')
	}),
	//模块mutations方法
	mutations: {
		addToCart(state, goods) {
			const findRes = state.cart.find(x => x.id === goods.id);

			if (!findRes) {
				//如果购物车没有这个商品,直接push
				state.cart.push(goods);
			} else {
				//否则更新数量
				findRes.count++;
			}
			this.commit('m_cart/saveToStorage')
		},
		//游客保存购物车到本地
		saveToStorage(state) {
			uni.setStorageSync('cart', JSON.stringify(state.cart))
		},
		//更新购物车中商品的选中状态
		updateGoodsState(state, goods) {
			const findRes = state.cart.find(x => x.id === goods.id)
			if (findRes) {
				findRes.state = goods.state;
				this.commit('m_cart/saveToStorage');
			}
		},
		//更新商品的数量
		updateGoodsCount(state, goods) {
			const findRes = state.cart.find(x => x.id === goods.id)
			if (findRes) {
				findRes.count = goods.count;
				this.commit('m_cart/saveToStorage');
			}
		},
		//根据id删除商品
		removeGoodsById(state, id) {
			state.cart = state.cart.filter(x => x.id !== id);
			this.commit('m_cart/saveToStorage');
		},
		//更新购物车中所有商品的勾选状态
		updateAllGoodsState(state, newState) {
			state.cart.forEach(x => x.state = newState)
			this.commit('m_cart/saveToStorage')
		}
	},
	//模块getters属性
	getters: {
		//购物车中所有商品的数量
		total(state) {
			// let c = 0;
			// state.cart.forEach(goods => c += goods.count)
			// return c
			return state.cart.reduce((total, item) => total += item.count, 0)
		},
		//购物车中已勾选的商品数量
		checkedCount(state) {
			// 先使用 filter 方法,从购物车中过滤器已勾选的商品
			// 再使用 reduce 方法,将已勾选的商品总数量进行累加
			// reduce() 的返回值就是已勾选的商品的总数量
			return state.cart.filter(x => x.state).reduce((total, item) =>
				total += item.count, 0)
		},
		// 已勾选商品的总价格
		checkedGoodsAmount(state) {
			// 先使用 filter 方法,从购物车中过滤器已勾选的商品
			// 再使用 reduce 方法,将已勾选的商品数量 * 单价之后,进行累加
			// reduce() 的返回值就是已勾选的商品的总价
			// 最后调用 toFixed(2) 方法,保留两位小数
			return state.cart.filter(x => x.state).reduce((total, item) => total += item.count * item.price, 0).toFixed(
				2)
		}
	}
}

6.购物车页面cart.vue

<template>
	<view class="cart-container" v-if="cart.length!==0">
		<!-- 收获地址组件 -->
		<my-address></my-address>
		<!-- 商品的列表标题 -->
		<view class="cart-title">
			<!-- 左侧图表 -->
			<uni-icons type="shop"></uni-icons>
			<!-- 右侧文本 -->
			<text class="cart-title-text">购物车</text>
		</view>
		<!-- 循环渲染购物车商品 -->
		<!-- 滑动删除组件容器 -->
		<uni-swipe-action>
			<block v-for="(goods,i) in cart" :key="i">
				<uni-swipe-action-item :right-options="options" @click="swipeItemClickHandler(goods)">
					<my-goods :goods="goods" :showRadio="true" :showNum="true" @radio-change="radioChangeHandler"
						@num-change="numChangeHandler"></my-goods>
				</uni-swipe-action-item>
			</block>
		</uni-swipe-action>
		<!-- 使用自定义结算组件 -->
		<my-settle></my-settle>
	</view>
	<!-- 空白购物车的区域 -->
	<view class="empty-cart" v-else>
		<image src="/static/cart/2.png" class="empty-img"></image>
		<text class="tip-text">空空如也~</text>
	</view>
</template>

<script>
	import badgeMix from '@/mixins/tabbar-badge.js'
	import {
		mapState,
		mapMutations
	} from 'vuex'
	export default {
		mixins: [badgeMix],
		computed: {
			...mapState('m_cart', ['cart'])
		},
		data() {
			return {
				options: [{
					text: '删除',
					style: {
						backgroundColor: '#c00000'
					}
				}]
			};
		},
		methods: {
			...mapMutations('m_cart', ['updateGoodsState', 'updateGoodsCount', 'removeGoodsById']),
			radioChangeHandler(e) {
				this.updateGoodsState(e)
			},
			//商品数量的变化
			numChangeHandler(e) {
				this.updateGoodsCount(e)
			},
			swipeItemClickHandler(e) {
				this.removeGoodsById(e.id)
			}
		}
	}
</script>

<style lang="scss">
	.cart-container {
		padding-bottom: 50px;
	}
	.cart-title {
		height: 40px;
		display: flex;
		align-items: center;
		font-size: 14px;
		padding-left: 5px;
		border-bottom: 1px solid #efefef;
		.cart-title-text {
			margin-left: 10px;
		}
	}
	.empty-cart {
		display: flex;
		flex-direction: column;
		align-items: center;
		padding-top: 150px;
		.empty-img {
			width: 100px;
			height: 100px;
		}
		.tip-text {
			font-size: 12px;
			color: gray;
			margin-top: 15px;
		}
	}
</style>

7.效果示例

—1—
在这里插入图片描述
—2—
在这里插入图片描述

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于uni-app购物界面的实现,可以参考以下步骤: 1. 在store目录下创建一个名为cart.js的文件,用于管理购物相关的vuex模块。 2. 在cart.js文件中,定义state来存储购物的数据,比如购物中的商品列表和总价。 3. 创建mutations来更新购物的状态,比如添加商品到购物、删除购物中的商品、更新商品数量等。 4. 可以创建getters来获取购物的状态,比如获取购物中的商品数量、计算购物中的总价等。 5. 在store.js文件中,导入并挂载cart.js模块,将其命名为m_cart。 6. 在购物页面的Vue组件中,通过mapState、mapMutations和mapGetters辅助函数来获取state、mutations和getters中的数据和方法。 7. 在购物页面中,可以使用v-for指令遍历购物中的商品列表,展示商品信息。 8. 根据需求,可以添加一些交互功能,比如点击添加按钮增加商品数量、点击删除按钮删除商品等。 通过以上步骤,你可以实现一个基本的uni-app购物界面。请根据你的具体需求和项目结构进行相应的调整。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [uni-app:购物页面--收货地址区域](https://blog.csdn.net/weixin_64612659/article/details/129585714)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值