小程序使用uview中的u-popup弹窗组件

该文介绍了一个在小程序中使用uview的u-popup组件创建弹窗来选择优惠券的过程。用户点击选择优惠券后,会打开一个包含滚动列表的弹窗,列表项由coupon.vue组件构成。弹窗组件通过监听事件从父组件接收优惠券数据,并能将选定的优惠券信息回传给父组件。
摘要由CSDN通过智能技术生成

小程序封装弹窗组件(使用uview框架中的u-popup弹窗组件)

效果展示

在里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码结构

结构分析

最外层页面index.vue-可点击"选择优惠券",进入弹窗组件selector.vue进行内容选择,弹窗组件中包含滚动列表,每个列表项为一个coupon.vue组件

核心代码

index.vue
template:
<!-- 优惠券区域 -->
<view class="rescue-coupon">
	<view class="coupon-select">
		<view class="title">
			选择优惠券
		</view>
		<view class="piker" @click="open">
			选择优惠券
			<selector ref="saleArea" @getApplyCoupon="getApplyCoupon" /> // 设置自定义事件-方便子组件传递选择的优惠券过来
		</view>
	</view>
	<view class="apply-coupon">
		<coupon :item="applyCoupon" :imgShow="false" />
	</view>
</view>
js:
<script>
	import http from "@/js/api.js"  // 请求发送组件
	import selector from './selector.vue' // 弹窗组件
	import coupon from './coupon.vue' // 列表项组件
	import { cloneDeep } from "lodash" // 深拷贝
	export default {
		components: {
			selector,
			coupon
		},
		data() {
			return {
				// 使用的优惠券
				applyCoupon:{},
				// 优惠券列表
				couponList:[],
				show:false
				}
		},
		methods: {
			// 获取优惠券列表数据-可用优惠券
			getCouponList() {
				console.log('调用了优惠券列表查询方法')
				let opt = {
					url: url, // 接口地址
					data: data, // 请求参数
					method: 'GET'
				}
				http(opt).then(res => {
					console.log('优惠券列表响应数据',res)
					this.couponList = res.list
					if(this.couponList.length >= 1) { // 可用优惠券数量不小于1时 为每个优惠券对象动态添加check属性-为后续勾选提供便利
						for(let i = 0; i < this.couponList.length; i ++) {
							this.$set(this.couponList,'check',false) // 注意此处需要实现响应式-使用$set API实现(vue)
						}
						this.couponList[0].check = true  // 默认第一张优惠券状态为选中
					}
				}).catch(error => {
					uni.showToast({title: error.message || '网络超时', icon: 'none'});
				});
			},
			// 获取子组件传递过来的确定使用的优惠券
			getApplyCoupon(obj) {
				console.log('接收到的优惠券:',obj)
				this.applyCoupon = obj
				this.params.couponId = obj.id
			},
			// 展开优惠券选择弹窗
			open(){
			    this.$refs.saleArea.show = true
				this.$refs.saleArea.couponList = cloneDeep(this.couponList)
				if(this.applyCoupon.id) { // 存在已选择优惠券
					this.$refs.saleArea.filterCoupons(this.applyCoupon.id)
				}else { // 暂无已选优惠券
					this.$refs.saleArea.filterCoupons(999)
				}
		    }
	}
</script>

selector.vue
<template>
	<u-popup v-model="show" mode="bottom" border-radius="16"> // uview框架的弹出层组件
		<view class="box">
			<!-- 关闭 -->
			<view class="close" @click="close">
				<image src="../../../static/coupon/couponClose.png" mode=""></image>
			</view>
			<!-- 标题 -->
			<view class="title">
				选择优惠券
			</view>
			<!-- 优惠券列表 -->
			<scroll-view class="list" scroll-y="true" enhanced :show-scrollbar="false" v-if="couponList.length !== 0">
				<view v-for="item,i in couponList" :key="i" @click="handlerClick(item)">
					<coupon :item="item" />
				</view>
			</scroll-view>
			<emptyList title="暂无可用优惠券" v-else></emptyList>
			<!-- 底部按钮 -->
			<view class="bottom" @click="apply">
				立即使用
			</view>
		</view>
	</u-popup>
</template>
<script>
	import emptyList from './emptyList.vue'
	import coupon from './coupon.vue'
	export default {
		components:{
			coupon,
			emptyList
		},
		data() {
			return {
				couponList:[],
				applyCoupon:{}, // 确定使用的优惠券
				show: false
			}
		},
		methods: {
			// 已选优惠券情况下再次进入优惠券选择页面-设置已选优惠券状态为已勾选状态
			filterCoupons(id) {
				if(id === 999) { // 当前不存在已选优惠券-则默认第一张优惠券为勾选状态
					this.applyCoupon = this.couponList[0]
				}else {          // 当前存在已选优惠券-则筛选出该优惠券并将其设为勾选状态
					this.couponList.forEach(item=>{
						item.check = false
					})
					for(let i = 0; i < this.couponList.length; i++) {
						if(this.couponList[i].id === id) {
							this.couponList[i].check = true
						}
					}
				}
			},
			// 勾选
			handlerClick(data){
				console.log('选择的优惠券',data)
				this.applyCoupon = data
				this.couponList.forEach(item=>{
					item.check = false
				})
				for(let i = 0; i < this.couponList.length; i++) {
					if(this.couponList[i].id === data.id) {
						this.couponList[i].check = true
					}
				}
			},
			// 立即使用
			apply() {
				if(this.applyCoupon) {
					this.show = false
					this.$emit('getApplyCoupon',this.applyCoupon) // 将确定使用的优惠券传递给父组件
				}else {
					this.show = false
				}
			},
			// 关闭弹窗
			close() {
				this.show = false
			}
		}
	}
</script>

<style lang="scss" scoped>
	.box {
		width: 750rpx;
		max-height: 1361rpx;
		background: #FFFFFF;
		opacity: 1;
		padding: 32rpx;
		
		.close {
			text-align: right;
			image {
				width: 48rpx;
				height: 48rpx;
				margin-bottom: -10rpx;
			}
		}
		
		.title {
			font-size: 32rpx;
			font-family: PingFang SC-Semibold, PingFang SC;
			font-weight: 600;
			color: #1A1D24;
			margin-bottom: 26rpx;
			margin-left: 12rpx;
		}
		
		.list {
			max-height: 1000rpx;
		}
		
		.bottom {
			width: 686rpx;
			height: 72rpx;
			background: #2972FF;
			border-radius: 16rpx 16rpx 16rpx 16rpx;
			opacity: 1;
			margin-top: 40rpx;
			font-size: 28rpx;
			font-family: PingFang SC-Medium, PingFang SC;
			font-weight: 500;
			color: #FFFFFF;
			text-align: center;
			line-height: 72rpx;
		}
	}
</style>
coupon.vue
<template>
	<view>
		<!-- 金额优惠券 -->
		<view class="moneyItem" v-if="item.couponType === 1">
			<view class="left">
				<span><span class="unity">¥</span>{{ item.couponAmt }}</span>
				<span>可用金额¥{{ item.usedAmt }}</span>
			</view>
			<view class="right">
				<span :class="{ one:!imgShow }">可用车辆:{{ changeFormat(item.customerType) }}</span>
				<span>
					<image v-show="imgShow" class="two" :src="item.check ? selectUrl : unSelectUrl" mode=""></image>
				</span>
				<span class="three">{{ item.effectDate }}至{{ item.expireDate }}</span>
			</view>
		</view>
		<!-- 服务优惠券 -->
		<view class="serviceItem" v-if="item.couponType === 2">
			<view>
				<view class="left">
					<span>服务券</span>
				</view>
				<view class="right">
					<span :class="{ one:!imgShow }">可用车辆:{{ changeFormat(item.customerType) }}</span>
					<span>
						<span>{{ item.contentTitle }}</span>
						<image v-show="imgShow" class="two" :src="item.check === true ? selectUrl : unSelectUrl" mode=""></image>
					</span>
					<span class="three">{{item.effectDate}}至{{item.expireDate}}</span>
				</view>
			</view>
			<view @click="change">
				<span :style="[{overflow:(index === 1 ? 'hidden' : 'auto')},{whiteSpace:(index===1?'nowrap':'normal')},{textOverflow:(index===1?'ellipsis':'clip')}]">详情:{{item.couponDesc}}</span>
				<image :src="detailUrl" mode=""></image>
			</view>
		</view>
	</view>
</template>

<script>
	export default {
		name:'coupon',
		props:{
			item:{
				type:Object,
				default:{}
			},
			imgShow: {
				type:Boolean,
				default:true
			}
		},
		filters: {
			customerFilter(val) {
				if(val === 'PERSON') {
					return this.item.truckVin
				}else {
					return this.item.fleetName
				}
			}
		},
		data() {
			return {
				index:1,
				detailUrl:'../../../static/coupon/bottom.png',
				onUrl:'../../../static/coupon/top.png',
				offUrl:'../../../static/coupon/bottom.png',
				// 勾选
				chooseUrl:'../../../static/coupon/couponSelect.png',
				selectUrl:'../../../static/coupon/couponSelect.png',
				unSelectUrl:'../../../static/coupon/couponUnselect.png',
			}
		},
		watch: {
			detailUrl(val) {
				if(val === this.offUrl) {
					this.index = 1
				}else {
					this.index = 2
				}
			}
		},
		methods: {
			// 详情展开/关闭
			change() {
				if(this.detailUrl === this.offUrl) {
					this.detailUrl = this.onUrl
				}else {
					this.detailUrl = this.offUrl
				}
			},
			changeFormat(val) {
				if(val === 'PERSON') {
					return this.item.truckVin
				}else {
					return this.item.fleetName
				}
			}
		}
	}
</script>

<style scoped lang="scss">
	.moneyItem {
		display: flex;
		height: 202rpx;
		background: #F4F8FF;
		opacity: 1;
		background-image: url('../../../static/coupon/couponBac.png');
		background-size: 100%;
		margin-bottom: 20rpx;
		padding-top: 15rpx;
		padding-left: 15rpx;
		
		.left {
			display: flex;
			justify-content: center;
			align-items: center;
			flex-direction: column;
			width: 186rpx;
			height: 190rpx;
			&>span {
				&:first-child {
					font-size: 40rpx;
					font-family: PingFang SC-Medium, PingFang SC;
					font-weight: 500;
					color: #FFFFFF;
					margin-bottom: 10rpx;
					.unity {
						font-size: 22rpx;
					}
				}
				&:last-child {
					font-size: 24rpx;
					font-family: PingFang SC-Regular, PingFang SC;
					font-weight: 400;
					color: #FFFFFF;
				}
			}
		}
		
		.right {
			flex: 1;
			display: flex;
			flex-direction: column;
			justify-content: center;
			padding-left: 30rpx;
			.one {
				margin-bottom: 48rpx;
			}
			&>span {
				
				&:first-child {
					font-size: 32rpx;
					font-family: PingFang SC-Medium, PingFang SC;
					font-weight: 500;
					color: #1A1D24;
				}
				&:nth-child(2) {
					text-align: right;
					padding: 0;
					image {
						width: 48rpx;
						height: 48rpx;
						margin-right: 32rpx;
						margin-bottom: -10rpx;
					}
				}
				&:last-child {
					font-size: 28rpx;
					font-family: PingFang SC-Regular, PingFang SC;
					font-weight: 400;
					color: #76777C;
				}
			}
		}
	}
	.serviceItem {
		background: #F4F8FF;
		margin-bottom: 20rpx;
		&>view {
			&:first-child {
				opacity: 1;
				height: 202rpx;
				padding-top: 15rpx;
				padding-left: 15rpx;
				display: flex;
				background-image: url('../../../static/coupon/couponBac.png');
				background-size: 100%;
				.left {
					display: flex;
					justify-content: center;
					align-items: center;
					flex-direction: column;
					width: 186rpx;
					height: 190rpx;
					span {
						font-size: 48rpx;
						font-family: PingFang SC-Medium, PingFang SC;
						font-weight: 500;
						color: #FFFFFF;
					}
				}
				.right {
					flex: 1;
					display: flex;
					flex-direction: column;
					justify-content: center;
					padding-left: 30rpx;
					&>span {
						&:first-child {
							font-size: 32rpx;
							font-family: PingFang SC-Medium, PingFang SC;
							font-weight: 500;
							color: #1A1D24;
						}
						&:nth-child(2) {
							display: flex;
							justify-content: space-between;
							padding: 0;
							font-size: 28rpx;
							font-family: PingFang SC-Regular, PingFang SC;
							font-weight: 400;
							color: #46484E;
							margin-top: 8rpx;
							image {
								width: 48rpx;
								height: 48rpx;
								margin-right: 32rpx;
								margin-bottom: -10rpx;
							}
						}
						&:last-child {
							margin-top: 30rpx;
							font-size: 28rpx;
							font-family: PingFang SC-Regular, PingFang SC;
							font-weight: 400;
							color: #76777C;
						}
					}
				}
			}
			&:last-child {
				width: 100%;
				padding: 15rpx 22rpx;
				font-family: PingFang SC-Regular, PingFang SC;
				font-weight: 400;
				color: #76777C;
				background: #FAFAFA;
				border-radius: 0 0 16rpx 16rpx;
				opacity: 1;
				display: flex;
				justify-content: space-between;
				span {
					flex: 1;
				}
				image {
					margin-left: 16rpx;
					width: 32rpx;
					height: 32rpx;
				}
			}
		}
	}
</style>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值