uniapp 自定义下拉组件

需求:类似于淘宝京东的分类栏,以及价格排序等等

原理:利用自定义的弹窗+css显示隐藏动画效果+slot来实现

1、先编写好自己需要的模板样式,并将各种传值类的东西定义好

特别注意:app端的slot名称无法动态改变

<template>
	<!-- 条件选择器 -->
	<view class="screens-box">
		<view class="screen-item" v-for="(item,index) in list" :key="index" @click="changeScreen(index,item)">
			<view class="font-size-26" :class="[item.isSelect?'font-color-3':'font-color-646464']">{{item.label}}</view>
			<image :src="item.isSelect?triangle_02:triangle_01" class="triangle"
				:class="[triangleIndex==index?'triangle-180':'triangle-0']"></image>
		</view>
		<!-- 弹窗 -->
		<view class="pop-up flex axle" :style="{height:popHeight,opacity:popOpacity,zIndex:zIndex}" @click="close">
			<view class="contain-box" :style="{transform:'translateY('+translateY+')'}" @click.stop="()=>{}">
				<!-- #ifdef H5  -->
				<slot :name="screenName"></slot>
				<!-- #endif -->
				
				<!-- #ifdef MP -->
				<slot name="{{screenName}}"></slot>
				<!-- #endif -->

				<!-- #ifdef APP-PLUS -->
				<!-- app端无法动态改变名称 -->
				<slot v-if="screenName==='comprehensive'" name="comprehensive"></slot>
				<slot v-if="screenName==='price'" name="price"></slot>
				<!-- #endif -->
			</view>
		</view>
	</view>
</template>

<script>
	import triangle_01 from '@/static/images/triangle_01.png'
	import triangle_02 from '@/static/images/triangle_02.png'
	export default {
		data() {
			return {
				triangle_01,
				triangle_02,
				popHeight: 0,
				popOpacity: 0,
				changeSwitch: false, //切换开关
				translateY: '',
				triangleIndex: null,//选中的分类
				screenName: '',
				zIndex: -1
			}
		},
		mounted() {
			this.getPopHeight()
		},
		props: {
			list: {
				type: Array,
				default () {
					return []
				}
			}
		},
		methods: {
			// 关闭
			close() {
				this.changeSwitch = false
				this.popOpacity = 0
				this.translateY = '-100%'
				this.triangleIndex = null
				this.zIndex = -1
			},
			// 切换
			changeScreen(index, item) {
				// console.log('点击', index, item)
				this.screenName = item.name
				// 如果点击相同的tab
				if (this.triangleIndex == index) {
					this.triangleIndex = null
					this.changeSwitch = !this.changeSwitch
				} else {
					this.triangleIndex = index
					this.changeSwitch = true
				}
				// console.log('点击2', this.changeSwitch);
				if (this.changeSwitch) {
					this.popOpacity = 1
					this.translateY = '0'
					this.zIndex = 10
				} else {
					this.popOpacity = 0
					this.translateY = '-100%'
					this.zIndex = -1
				}
				this.$emit('changeScreen', index)
			},
			// 获取遮罩层高度
			getPopHeight() {
				const res = uni.getSystemInfoSync();
				const query = uni.createSelectorQuery().in(this)
				query.select('.pop-up').boundingClientRect(data => {
					this.popHeight = res.windowHeight - data.top + 'px'
				}).exec();
			},
		}
	}
</script>

<style lang="scss" scoped>
	.screens-box {
		height: 90rpx;
		display: flex;
		padding: 0 40rpx;
		position: relative;

		.screen-item {
			display: flex;
			align-items: center;

			&:not(:first-child) {
				margin-left: 60rpx;
			}

			.triangle {
				width: 14rpx;
				height: 8rpx;
				margin-left: 10rpx;
				transition: transform 0.3s;
			}

			.triangle-180 {
				transform: rotate(-180deg);
			}

			.triangle-0 {
				transform: rotate(0deg);
			}
		}

		.pop-up {
			position: absolute;
			width: 100%;
			left: 0;
			right: 0;
			bottom: 0;
			top: 90rpx;
			background: rgba(0, 0, 0, 0.2);
			overflow: hidden;
			transition: opacity 0.3s, z-index 0.3s;
			// border: 1px solid red;

			.contain-box {
				background-color: #fff;
				border-radius: 0px 0px 10rpx 10rpx;
				overflow: hidden;
				transition: transform 0.3s;
				// border: 1px solid red;
			}
		}
	}
</style>

 2、在页面中调用

<!-- 监测仪条件筛选 -->
		<screen :list="screenList" @changeScreen="changeScreen" ref="screen" v-show="tabIndex==0">
			<!-- 综合排序 -->
			<template v-slot:comprehensive>
				<view v-for="(item,index) in comprehensiveList" :key="index" @click="selectComprehensive(item,index)"
					hover-class="hover-class">
					<view class="flex level-between vertical-center state-item">
						<view class="">{{item.label}}</view>
						<icon type="success_no_circle" size="14" color="#42c2a4" v-show="item.isSelect" />
					</view>
					<view class="cut-off"></view>
				</view>
			</template>
			
			<!-- 价格排序 -->
			<template v-slot:price>
				<view v-for="(item,index) in priceList" :key="index" @click="selectPrice(item,index)"
					hover-class="hover-class">
					<view class="flex level-between vertical-center state-item">
						<view class="">{{item.label}}</view>
						<icon type="success_no_circle" size="14" color="#42c2a4" v-show="item.isSelect" />
					</view>
					<view class="cut-off"></view>
				</view>
			</template>
		</screen>
screenList: [{
					label: '综合排序', //综合排序
					isRotate: false,
					isSelect: false,
					name: 'comprehensive'
				}, {
					label: '价格排序', //价格排序
					isRotate: false,
					isSelect: false,
					name: 'price'
				}],
				comprehensiveList: [{
					id: 1,
					label: '综合', //综合
					isSelect: false
				}, {
					id: 2,
					label: '信用', //信用
					isSelect: false
				}, {
					id: 3,
					label: '新品推荐', //新品推荐
					isSelect: false
				}],
				priceList: [{
					id: 1,
					label: '价格升序', //价格升序
					isSelect: false
				}, {
					id: 2,
					label: '价格降序', //价格降序
					isSelect: false
				}],
				tabIndex: 0,
				form: {
					comprehensive: '',
					price:''
				}

3、注意需要设置监听函数

watch: {
			// 监听参数改变,将筛选后的tab状态变成蓝色
			form: {
				handler(newName) {
					// console.log('监听',newName);
					this.screenList.forEach((item, index) => {
						item.isSelect = false
						if (newName[item.name]) {
							item.isSelect = true
							this.$set(this.screenList, index, item)
						}
					})
				},
				deep: true
			},
		},

4、定义的方法

changeScreen(e) {
				this.screenList[e].isRotate = true
			},
			// 选择综合
			selectComprehensive(item, index) {
				// 清空
				this.comprehensiveList.forEach(item => {
					item.isSelect = false
				})
				this.priceList.forEach(item => {
					item.isSelect = false
				})
				item.isSelect = !item.isSelect
				this.$set(this.comprehensiveList, index, item)
				// 赋值监听
				this.form.price=''
				this.form.comprehensive = item.id
				this.confirm()
			},
			//选择价格
			selectPrice(item, index){
				// 清空
				this.priceList.forEach(item => {
					item.isSelect = false
				})
				this.comprehensiveList.forEach(item => {
					item.isSelect = false
				})
				item.isSelect = !item.isSelect
				this.$set(this.priceList, index, item)
				// 赋值监听
				this.form.comprehensive=''
				this.form.price= item.id
				this.confirm()
			},
			// 确定
			confirm() {
				this.$refs.screen.close()
			},

5、最后自己设置的样式

	.cut-off {
		width: 750rpx;
		height: 1rpx;
		border-radius: 0px 0px 1rpx 1rpx;
		background-color: #EBEFF5;
	}

	.state-item {
		padding: 32rpx 30rpx;
		font-size: 28rpx;
		color: #646464;
	}

	.hover-class {
		background: $uni-bg-color-hover;
	}

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值