当前位置: 首页 > article >正文

uniapp 购物弹窗组件 (微信小程序)

 效果图,暂时只适应单规格,居中弹出和下方弹出,如需求不满足,请自行修改代码

(更新于24/11/15)

居中显示效果

下方弹出效果

html 

<template>
	<view class="" v-if="show"
		:class="mode=='center'?(style_show?'specifications_show_center openAnimation':'specifications_show_center closeAnimation'):mode=='bottom'?(style_show?'specifications_show_bottom  openAnimation':'specifications_show_bottom  closeAnimation'):''"
		@tap.stop="()=>{}">


		<view class="specifications"
			:class="mode=='bottom'?(style_show?'specifications_bottom_open  ':'specifications_bottom_close  '):''"
			@tap.stop="()=>{}">
			<view class="specification">
				<view class="specification_title">请选择规格</view>
				<image class="colseIcon"
					:src="$publicfun.locaAndHttp()?'../../static/all/del.png':$publicfun.httpUrlImg('colse.png')"
					mode="aspectFit" @tap.stop="colosePopue"></image>
				<!-- 商品信息 -->
				<view class="modal-header flex ">
					<view class="header-left ss-m-r-30">
						<image class="sku-image" :src="component_goodsDetail.image" mode="aspectFill"
							@tap.stop="previewImages1(component_goodsDetail.image,1)">
						</image>
					</view>
					<view class="header-right   ">
						<view class="goods-title ss-line-2">{{component_goodsDetail.title||'商品名称' }}</view>
						<view class="header-right-bottom ss-flex ss-col-center ss-row-between">
							<view class="price-text">
								{{is_kongobj=='{}'? Number(component_goodsDetail.price*1).toFixed(2) :Number(chooseSpecificationObject.price*1).toFixed(2)}}
							</view>
							<view class="stock-text ss-m-l-20" v-if="is_kongobj!='{}'">
								库存{{ is_kongobj=='{}'?component_goodsDetail.goods_stock:chooseSpecificationObject.inventory}}件
							</view>
						</view>
					</view>
				</view>
				<view class="specification_title2">
					规格
				</view>
				<view class="specification_title_1">
					<scroll-view scroll-y="true" style="height: 100%;">
						<view>
							<height :hg='30'></height>
							<view class="flex flexwrap">
								<view v-for="(itemall,indexall) in component_goodsDetail.multiplejson" :key="indexall"
									@click.stop="setguigeindex(indexall,itemall)">
									<view
										:class="guigeindex==indexall?'specification_title_1_title specification_title_1_titlec':'specification_title_1_title'"
										v-if='itemall.title'>
										{{itemall.title}}
									</view>
								</view>
							</view>
							<!-- 单规格 -->
							<view class="mt30" v-if="false">
								<view class="specification_title_1_content">
									<view class="specification_title_1_content_flex flex jc ac"
										:class="guigeindex2==index?'specification_title_1_content_flex_activate':''"
										v-for="(item,index) in specification_list[guigeindex].item" :key="index"
										@tap.stop="selective_specification(item.guigechildren,item)">
										<!-- 可用于显示商品图片 -->
										<!-- <image class="image" :src="sheep.$url.cdn(type_return_img(item.id).url)"
											mode="aspectFill" v-if="type_return_img(item.id).url!=''">
										</image> -->
										<view>{{item.name}}</view>
									</view>
									<view class="nogoods" v-if="item.guigechildren.length==0" style="margin: auto;">
										<u-empty text='没有规格~' icon="">
										</u-empty>
									</view>
								</view>
							</view>
						</view>
					</scroll-view>
				</view>
				<view class="" v-if="mode=='center'">
					<view class="selected">
						<text>已选规格:</text>
						{{is_kongobj=='{}'?'未选择':chooseSpecificationObject.title}}
					</view>
				</view>
				<view class="buy-num-box flex jsb ac">
					<view class="label-text">购买数量</view>
					<view class="ShopCar flex jc ac">
						<image class="ShopCaricon"
							:src="$publicfun.locaAndHttp()?'../../static/all/del.png':$publicfun.httpUrlImg('del.png')"
							mode="aspectFit" @tap.stop="delnum(item)"></image>
						<input type="number" v-model="goodsNum" class="ShopCarInp" @blur="inpnum(item)" />
						<image class="ShopCaricon"
							:src="$publicfun.locaAndHttp()?'../../static/all/add.png':$publicfun.httpUrlImg('add.png')"
							mode="aspectFit" @tap.stop="addnum(item)"></image>
					</view>
				</view>
				<view class="sublist" v-if="mode=='center'">
					<view class="sublist_left">
						<view class="">
							<text>总计 </text>
							<text class="TotalPrices">
								<text>¥</text>
								{{is_kongobj=='{}'?'0.00':Number(chooseSpecificationObject.price*goodsNum).toFixed(2) }}
							</text>
						</view>
					</view>
					<view class="sublist_right" @tap.stop="goodsAddCar()">
						<text>+</text> <text>加入购物车</text>
					</view>
				</view>


				<view class="specification_bottombuts" v-if="mode=='bottom'">
					<view class="specification_bottombuts_but specification_bottombuts_ShoppingCart"
						@tap.stop="goodsAddCar()">
						加入购物车
					</view>
					<view class="specification_bottombuts_but specification_bottombuts_PayNow" @tap.stop="newPay()">
						立即购买
					</view>
				</view>
				<view class="" style="width: 100%;height: 30px;" v-if="mode=='bottom'">

				</view>
			</view>
		</view>
	</view>
</template>

js


	export default {
		name: "specification",
		//style_show  主要控制动画效果
		//mode   设置方向弹出
		//show   控制显示不显示
		//goodsDetail  传入的商品信息
		props: ['show', 'style_show', 'goodsDetail', 'mode'],
		data() {
			return {
				orderprive: '',
				style: [], //规格动态样式
				// goodsDetail: { //模拟商品信息
				// 	goods_name: '番茄鸡蛋面',
				// 	goods_price: '9.90',
				// 	goods_stock: 999,
				// 	specification: [{
				// 		goods_name: '规格1',
				// 		goods_price: '9.90',
				// 		goods_stock: 999,
				// 		children: [{
				// 			goods_name: '11',
				// 			goods_price: '6.60',
				// 			goods_stock: 999,
				// 		}]
				// 	}]
				// },
				chooseSpecificationObject: {}, //选中的规格
				guigeindex: 0, //一级规格
				guigeindex2: 0, //二级规格
				component_goodsDetail: {}, //请求接口的商品数据
				goodsNum: 1,


			
			};
		},
		onLoad() {
			
		},
		watch: {
//监听是否有商品id传入进来
			goodsDetail: {
				handler(newName, oldName) {
                    //获取商品信息的接口
					GoodsDetail({
						id: newName.id
					}).then(res => {
						this.component_goodsDetail = res.data;
						this.chooseSpecificationObject = res.data ? res.data.multiplejson[0] : {};
						this.guigeindex = 0;
						console.log(res, '商品详情');
					})
					this.goodsNum = 1;
				},
				immediate: true,
				deep: true
			}
		},
		onShow() {
		
		},
		computed: {
			//判断是否选中规格
			is_kongobj() {
				console.log(this.chooseSpecificationObject);
				return JSON.stringify(this.chooseSpecificationObject); 
			}
		},

		methods: {
			newPay() {
				if (!this.style_show) {
					return
				}
				let that = this;
				//可用于显示弹窗不默认选中规格的判断
				// if (JSON.stringify(this.choose_specification) == '{}') {
				// 	uni.showToast({
				// 		title: "请选择规格",
				// 		icon: "none"
				// 	})
				// 	return
				// }
				// console.log(that.goodsNum);
				// return
                // 直接购买将需要的信息提交到vuex缓存中,用于渲染页面
				this.$store.commit('set_is_immediately', {
					type: 'goodsDetail',
					id: that.component_goodsDetail.id, //id
					item: that.chooseSpecificationObject, //规格名称
					count: that.goodsNum,
					goodsDetail: [that.component_goodsDetail] //商品列表数组
				})
                //跳转到提交订单页面
				this.$publicfun.navigateTo('/pagesA/SubmitOrder/SubmitOrder')
				this.colosePopue()
			},
			//选中规格
			setguigeindex(index, item) {
				if (!this.style_show) {
					return
				}
				this.chooseSpecificationObject = item;
				this.guigeindex = index;
				if (this.goodsNum > this.chooseSpecificationObject.inventory) {
					this.goodsNum = this.chooseSpecificationObject.inventory;
				}

			},
			//删除购物车数量
			delnum() {
				if (!this.style_show) {
					return
				}
				if (this.goodsNum > 1) {
					this.goodsNum--;
				} else {
					//数量少于1 关闭弹窗
					this.colosePopue()
				}
			},
			//添加购物车数量
			addnum() {
				if (!this.style_show) {
					return
				}
				if (this.goodsNum < this.chooseSpecificationObject.inventory) {
					this.goodsNum++;
				} else {
					uni.showToast({
						title: '超出购买数量~',
						icon: "none"
					})
				}
			},
			//手动输入购买数量
			inpnum() {
				if (!this.style_show) {
					return
				}
				if (this.goodsNum > this.chooseSpecificationObject.inventory) {
					this.goodsNum = this.chooseSpecificationObject.inventory;
				}
				if (this.goodsNum == '') {
					// this.colosePopue()
					this.goodsNum = 1;
					this.$publicfun.showToast('购买数量不得少于1~')
				}
				if (this.goodsNum <= 0) {
					// this.colosePopue()
					this.goodsNum = 1;
					this.$publicfun.showToast('购买数量不得少于1~')
				}
			},
			//预览商品图片
			previewImages1(url, index) {
//因为动画效果是 用透明度为0,再消失,透明度改变的时候还可以点击,加这个判断是很必要的
				if (!this.style_show) {
					return
				}
                //预览图片
				this.$publicfun.previewImage({
					url: url,
					index: index
				})
			},
			//关闭弹窗
			colosePopue() {
				if (!this.style_show) {
					return
				}
				this.$emit('closeCar')
				// this.component_goodsDetail={};
			},
			//添加购物车
			goodsAddCar() {
				if (!this.style_show) {
					return
				}
				let that = this;
                //这是添加到购物车
				carAddAndDel({
					id: this.goodsDetail.id,
					count: this.goodsNum,
					item_name: this.chooseSpecificationObject.title,
					type: 'add'
				}).then(res => {
					if (res.code == 1) {
                        //通过vuex更新数据
						this.$store.dispatch('fun_set_shopCar');
						// console.log(res);
						that.colosePopue();
						uni.showToast({
							title: '已添加到购物车~',
							icon: "none"
						})
					} else {
						uni.showToast({
							title: res.msg,
							icon: "none"
						})
					}
				})
			},
			
		}
	}

css部分

//居中显示
	.specifications_show_center {
		width: 100vw;
		height: 100vh;
		position: fixed;
		top: 0;
		left: 0;
		z-index: 999999999;
		background: rgba(0, 0, 0, 0.6);
		display: flex;
		justify-content: center;
		align-items: center;
		opacity: 1;
		border-radius: 18rpx;
	}

	.openAnimation {
		animation: slow_show 0.3s linear;
	}

	.closeAnimation {
		opacity: 0 !important;
		animation: close_slow_show 0.3s linear;
	}

	@keyframes slow_show {
		0% {
			opacity: 0;
		}

		100% {
			opacity: 1;
		}
	}

	@keyframes close_slow_show {
		0% {
			opacity: 1;
		}

		100% {
			opacity: 0;
		}
	}

	//从下方弹出显示
	.specifications_show_bottom {
		width: 100vw;
		height: 100vh;
		position: fixed;
		bottom: 0;
		left: 0;
		z-index: 999999999;
		background: rgba(0, 0, 0, 0.6);
		display: flex;
		justify-content: center;
		align-items: flex-end;
		opacity: 1;
		border-radius: 18rpx;

		.specifications {
			width: 100% !important;
			position: absolute;
			bottom: 0;
			left: 0;
			padding: 30rpx 50rpx !important;
		}

		.specifications_bottom_open {
			animation: From_bottom_to_top 0.22s linear;
		}

		.specifications_bottom_close {
			animation: From_top_to_bottom 0.3s linear;
		}
	}


	@keyframes From_bottom_to_top {
		0% {
			bottom: -100%;
		}

		100% {
			bottom: 0;
		}
	}

	@keyframes From_top_to_bottom {
		0% {
			bottom: 0;
		}

		100% {
			bottom: -100%;
		}
	}

//以上是动画效果


	.specifications {
		width: 690rpx;
		padding: 30rpx;
		box-sizing: border-box;
		background: #fff;
		border-radius: 18rpx;




		.buy-num-box {
			height: 100rpx;
			// padding-left: 20rpx;
			// box-sizing: border-box;

			.ShopCar {
				.ShopCaricon {
					width: 46rpx;
					height: 46rpx;
				}

				.ShopCarInp {
					width: 100rpx;
					height: 46rpx;
					text-align: center;
				}
			}
		}

		.modal-header {
			// position: relative;
			padding: 20rpx 0;
			margin-top: 20rpx;

			.sku-image {
				width: 160rpx;
				height: 160rpx;
				border-radius: 10rpx;
				background: darkslategray;
			}

			.header-right {
				width: calc(100% - 160rpx - 20rpx);
				height: 160rpx;
				display: flex;
				flex-direction: column;
				justify-content: space-between;
				margin-left: 20rpx;
			}

			.close-icon {
				position: absolute;
				top: 10rpx;
				right: 20rpx;
				font-size: 46rpx;
				opacity: 0.2;
			}

			.goods-title {
				font-size: 28rpx;
				font-weight: bold;
				line-height: 42rpx;
				position: relative;
				overflow: hidden;
				text-overflow: ellipsis;
				display: -webkit-box;
				-webkit-box-orient: vertical;
				-webkit-line-clamp: 2;


				.tig {
					border: 2rpx solid #ff6000;
					border-radius: 4rpx;
					width: 126rpx;
					height: 38rpx;
					position: absolute;
					left: 0;
					top: 0;

					.tig-icon {
						width: 40rpx;
						height: 40rpx;
						background: #ff6000;
						margin-left: -2rpx;
						border-radius: 4rpx 0 0 4rpx;

						.groupon-tag {
							width: 32rpx;
							height: 32rpx;
						}
					}

					.tig-title {
						font-size: 24rpx;
						font-weight: 500;
						line-height: normal;
						color: #ff6000;
						width: 86rpx;
						display: flex;
						justify-content: center;
						align-items: center;
					}
				}

				.info-title {
					text-indent: 132rpx;
				}
			}

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

			.price-text {
				font-size: 30rpx;
				font-weight: 500;
				color: red;
				font-family: OPPOSANS;

				&::before {
					content: '¥';
					font-size: 24rpx;
				}
			}

			.stock-text {
				font-size: 26rpx;
				color: #999999;
			}
		}

		.d_box {
			.d_box_item {
				font-size: 34rpx;
				color: #3d3d3d;
				width: 45%;
				margin-bottom: 20rpx;
			}
		}

		.specification {

			background: #FFFFFF;
			border-radius: 12rpx;
			position: relative;
			z-index: 10074;

			.specification_title {
				text-align: center;
				font-size: 38rpx;
				font-weight: 600;
				color: #353535;
				margin: 0 auto;
			}

			.colseIcon {
				width: 40rpx;
				height: 40rpx;
				position: absolute;
				right: 0rpx;
				top: 0rpx;
			}

			.specification_title2 {
				font-size: 38rpx;
				font-weight: 600;
				color: #353535;
				margin: 0 auto;
				margin-bottom: 30rpx;
			}

			.specification_goods_title {
				font-size: 38rpx;
				font-weight: 600;
			}

			.specification_title_1 {
				width: 100%;
				max-height: 400rpx !important;
				margin: 0 auto;

				.specification_title_1_title {
					font-size: 32rpx;
					font-weight: 600;
					color: #676767;
					// color: $AccentColor;
					display: inline-block;
					padding: 10rpx 20rpx;
					text-align: center;
					background: #fff;
					border-radius: 18rpx;
					white-space: nowrap;
					// border: 1rpx solid $AccentColor !important;
					border: 1rpx solid #676767 !important;
					margin-right: 10rpx;
					margin-bottom: 10rpx;
				}



				.specification_title_1_titlec {
					color: $AccentColor !important;
					// background: $AccentColor !important;
					border: 1rpx solid $AccentColor !important;
				}




				.specification_title_1_content {
					display: flex;
					flex-wrap: wrap;
					// overflow-x: auto;
					display: -webkit-box;
					-webkit-overflow-scrolling: touch;

					.specification_title_1_content_flex_activate {
						background: $AccentColor !important;
						border: 1rpx solid $AccentColor !important;
						color: #fff !important;
					}

					.font_sizi_1 {
						color: $AccentColor;
					}

					.font_sizi_2 {
						border-left: 1rpx solid $AccentColor;
					}

					.specification_title_1_content_flex {
						// height: 63rpx;
						background: #FFFFFF;
						border-radius: 14rpx;
						border: 1rpx solid #999;
						margin-right: 20rpx;
						text-align: center;
						// line-height: 63rpx;
						font-size: 28rpx;
						font-weight: 400;
						color: #343434;
						padding: 10rpx 20rpx;
						margin-bottom: 20rpx;

						.image {
							width: 60rpx;
							height: 60rpx;
							margin-right: 20rpx;
							border-radius: 12rpx;
						}
					}
				}
			}

			.close {
				position: absolute;
				bottom: -150rpx;
				left: 50%;
				transform: translateX(-50%);
			}
		}

		.selected {
			width: 100%;
			padding: 20rpx 0;
			background: #F5F5F5;
			margin-top: 60rpx;

			text {
				font-size: 24rpx;
				font-weight: 400;
				color: #363636;
			}

			text:nth-child(1) {
				font-size: 24rpx;
				font-weight: 400;
				color: #676767;
				padding: 0 20rpx;
				margin-left: 10rpx;
			}
		}

		.sublist {
			display: flex;
			align-items: center;
			justify-content: space-between;
			margin-top: 30rpx;
			// padding: 30rpx 40rpx;

			.sublist_left {
				.TotalPrices {
					margin-left: 10rpx;
				}

				text:nth-child(1) {
					font-size: 28rpx;
					font-weight: 600;
					color: #363636;
				}

				text:nth-child(2) {
					font-size: 28rpx;
					font-weight: 600;
					color: #FF0000;

					text:nth-child(1) {
						font-size: 28rpx;
						font-weight: 600;
						color: #FF0000;
						font-size: 24rpx;
					}
				}
			}

			.sublist_right {
				width: 234rpx;
				height: 62rpx;
				background: $AccentColor;
				border-radius: 12rpx;
				font-size: 32rpx;
				font-weight: 500;
				color: #F3FCFF;
				line-height: 62rpx;
				text-align: center;
			}
		}


		//从下方弹出的弹窗按钮
		.specification_bottombuts {
			width: 100%;
			margin: auto;
			display: flex;
			justify-content: space-between;
			align-items: center;
			margin-top: 20rpx;

			.specification_bottombuts_but {
				width: 50%;
				padding: 25rpx 20rpx;
				font-size: 28rpx;
				font-weight: bold;
				color: #fff;
				text-align: center;
			}

			.specification_bottombuts_ShoppingCart {
				background: #9dceff;
				border-radius: 99px 0 0 99px;
			}

			.specification_bottombuts_PayNow {
				background: #0a84ff;
				border-radius: 0px 99px 99px 0px;
			}
		}


		.minus {
			width: 25px;
			height: 25px;
			border-width: 1px;
			border-color: #E6E6E6;
			border-style: solid;
			border-top-left-radius: 100px;
			border-top-right-radius: 100px;
			border-bottom-left-radius: 100px;
			border-bottom-right-radius: 100px;
			@include flex;
			justify-content: center;
			align-items: center;
		}

		.input {
			padding: 0 10px;
		}

		.plus {
			width: 25px;
			height: 25px;
			border-width: 1px;
			background-color: #00B8FB;
			border-color: #00B8FB;
			border-style: solid;
			border-top-left-radius: 100px;
			border-top-right-radius: 100px;
			border-bottom-left-radius: 100px;
			border-bottom-right-radius: 100px;
			@include flex;
			justify-content: center;
			align-items: center;
		}
	}

http://www.kler.cn/a/403522.html

相关文章:

  • Flutter之使用mqtt进行连接和信息传输的使用案例
  • 006-自定义枚举注解
  • Java LinkedList 详解
  • 4.langchain中的prompt模板 (partially format prompt templates)
  • python成长技能之正则表达式
  • 虚拟机上搭建达梦DSC简略步骤
  • Jenkins下载安装、构建部署到linux远程启动运行
  • [免费]SpringBoot+Vue毕业设计论文管理系统【论文+源码+SQL脚本】
  • 【LLM训练系列02】如何找到一个大模型Lora的target_modules
  • 数据库笔记1
  • Java 正则表达式详解及实用案例
  • 容器运行时 AND Docker
  • 白嫖网络建设与运维文档,视频,加入知识星球和博客地址
  • 什么是 C++ 中的初始化列表?它的作用是什么?初始化列表和在构造函数体内赋值有什么区别?
  • 【Lucene】详解倒排表的结构,如何实现词典与文档的映射关系
  • 数据结构概述及线性结构
  • IL-AD
  • 付费会员数量统计错误修复
  • RabbitMQ 高级特性——延迟队列
  • vitess使用:从部署到go客户端连接查询
  • 深入解析PostgreSQL中的PL/pgSQL语法
  • React Native 全栈开发实战班 - 用户界面之手势系统应用
  • Android ConstraintLayout 基础
  • Day03_AJAX原理 (黑马笔记)
  • Python从0到100(七十三):Python OpenCV-OpenCV实现手势虚拟拖拽
  • 2025年软考初级【信息处理技术员】考试大纲