uniapp 自定义下拉框

uniapp 自定义下拉框

根据 https://gitee.com/kcren/uniapp-dropdown-filter/tree/master
自己加了一层封装 可以进行切换选择下拉内容

在这里插入图片描述

模板 在components下创建ren-dropdown-filter/ren-dropdown-filter.vue
图标的引用 和颜色 可以自己进行修改

<template>
	<view class="filter-wrapper"
		:style="{ height: height + 'rpx', top: top,'border-top':border?'1rpx solid #f2f2f2':'none' }"
		@touchmove.stop.prevent="discard">
		<view class="inner-wrapper">
			<view class="mask" :class="showMask ? 'show' : 'hide'" @tap="tapMask"></view>
			<view class="navs">
				<view class="c-flex-align" :class="{ 'c-flex-center': index > 0, actNav: index === actNav }"
					v-for="(item, index) in navData" :key="index" @click="navClick(index)">
					<view :title="child.text.length>numberSlit?child.text:''" v-for="(child, childx) in item.children"
						:key="childx" v-if="child.select">
						<text v-if="child.value" class="">
							{{ child.text.length>numberSlit?child.text.slice(0,numberSlit)+'...':child.text }}
						</text>
						<text v-else>
							{{ item.type.length>numberSlit? item.type.slice(0,numberSlit):item.type }}
						</text>
					</view>
					<image src="@/static/img/icons/icon-up.png" mode="" class="icon-triangle" v-if="index === actNav">
					</image>
					<image src="@/static/img/icons/icon-down.png" mode="" class="icon-triangle" v-else></image>
					</view>
					</view>
					<scroll-view scroll-y="true" class="popup" :class="popupShow ? 'popupShow' : ''">
				<view class="item-opt c-flex-align bgtype">
					请选择{{ navData[actNav?actNav:0].type }}
				</view>
				<view v-if="updata">
					<view class="item-opt c-flex-align" :class="item.select ? 'actOpt' : ''"
						v-for="(item, index) in navData[actNav?actNav:0].children" :key="index"
						@click="handleOpt(index)">
						{{ item.text }}
						</view>
				</view>
			</scroll-view>
		</view>
		</view>
</template>

<script>
export default {
		props: {
			height: {
				type: Number,
				default: 108
			},
			top: {
				type: String,
				default: 'calc(var(--window-statsu-bar) + 44px)'
			},
			border: {
				type: Boolean,
				default: false
			},
			filterData: {
				//必填
				type: Array,
				default: () => {
					return [];
				}},
			defaultIndex: {
				//默认选中条件索引,超出一类时必填
				type: Array,
				default: () => {
					return [];
				}
			}
		},
		data() {
			return {
				numberSlit:4,
				navData: [],
				// 强制刷新页面
				updata: true,
				popupShow: false,
				showMask: false,
				actNav: null,
				selDate: '选择日期',
				selIndex: [] //选中条件索引
			};
		},
		created() {
			this.navData = this.filterData;
			let arr =[]
			if(this.defaultIndex===undefined ||this.defaultIndex===null||this.defaultIndex.toString()==='[]' || this.defaultIndex.length===0){
				this.navData.forEach((item,index)=>{
					arr.push(0)
				})
				
			}else{
				arr=this.defaultIndex
			}
			this.selIndex = arr;
			this.keepStatus();
		},
		methods: {
			keepStatus() {
				this.navData.forEach(itemnavData => {
					// console.log(itemnavData.children)
					itemnavData.children.map(child => {
						child.select = false;
					});
					return itemnavDat
				});
				for (let i = 0; i < this.navData.length; i++) {
					let selindex = this.selIndex[i];
					this.navData.forEach(item => {
						this.navData[i].children[selindex].select = true;
					})
				}
				},
			navClick(index) {
				if (index === this.actNav) {
					this.tapMask();
					return;
				}
				this.popupShow = true;
				this.showMask = true;
				this.actNav = index;
			},
			handleOpt(index) {
				this.updata = false
				this.selIndex[this.actNav] = index;
				this.keepStatus();
				let data = [];
				let res = this.navData.forEach(item => {
					let obj = {}
					item.children.filter(child => {
						if (child.select) {
							obj = child
						}
					});
					data.push(obj)
				});
				this.keepStatus()
				this.updata = true
				this.$emit('onSelected', data);
			},
			dateClick() {
				this.tapMask();
			},
			tapMask() {
				this.showMask = false;
				this.popupShow = false;
				this.actNav = null;
			},
			handleDate(e) {
				let d = e.detail.value;
				this.selDate = d;
				this.$emit('dateChange', d);
			},
			discard() {}
		}
	};
</script>
<style lang="scss" scoped>
	page {
		font-size: 28rpx;
	}

	.c-flex-align {
		display: flex;
		align-items: center;
	}
	.bgtype{
	background-color: $bg-c36;
}
	.c-flex-center {
		display: flex;
		align-items: center;
		justify-content: center;
		flex-direction: column;
	}
	.filter-wrapper {
		position: fixed;
		left: 0;
		width: 100%;
		z-index: 999;

		.inner-wrapper {
		.navs {
				position: relative;
				height: 110rpx;
				padding: 0 40rpx;
				display: flex;
				align-items: center;
				justify-content: space-between;
				background-color: #fff;
				border-bottom: 2rpx solid  #f5f6f9;
				color: #8b9aae;
				z-index: 999;
				box-sizing: border-box;

				&>view {
					flex: 1;
					height: 100%;
					flex-direction: row;
					z-index: 999;
				}
				.date {
					justify-content: flex-end;
				}

				.actNav {
					color: #4d7df9;
					font-weight: bold;
				}
				}

			.mask {
				z-index: 666;
				position: fixed;
				top: calc(var(--status-bar-height) + 44px);
				left: 0;
				right: 0;
				bottom: 0;
				background-color: rgba(0, 0, 0, 0);
				transition: background-color 0.15s linear;

				&.show {
					background-color: rgba(0, 0, 0, 0.4);
				}
				&.hide {
					display: none;
				}
			}
			.popup {
				position: relative;
				max-height: 500rpx;
				background-color: #fff;
				border-bottom-left-radius: 20rpx;
				border-bottom-right-radius: 20rpx;
				overflow: scroll;
				z-index: 999;
				transition: all 1s linear;
				opacity: 0;
				display: none;
				.item-opt {
					height: 100rpx;
					padding: 0 40rpx;
					color: #8b9aae;
					border-bottom: 2rpx solid #f5f6f9;
				}
				.actOpt {
					color: #4d7df9;
					font-weight: bold;
					position: relative;

					&::after {
						content: '✓';
						font-weight: bold;
						font-size: 36rpx;
						position: absolute;
						right: 40rpx
						}
				}
			}
			.popupShow {
				display: block;
				opacity: 1;
			}
		}
		.icon-triangle {
			width: 16rpx;
			height: 16rpx;
			margin-left: 10rpx;
		}
	}
	</style>
<template>
	<view class="check-page">
		<view class="root">
			<ren-dropdown-filter :filterData='filterData' @onSelected='onSelected'
				@dateChange='dateChange'></ren-dropdown-filter>
		</view>
	</view>
</templa

在页面中引用

import RenDropdownFilter from '@/components/ren-dropdown-filter/ren-dropdown-filter.vue'
components: {
			comboxSearchfrom
		},

定义数据格式

		data(){
		return {
filterData: [{
						type: '检查类型',
						children: [{
								text: '全部',
								value: ''
							}, {
								text: '状态1',
								value: 1
							}, {
								text: '状态2',
								value: 2
							}, {
								text: '状态3',
								value: 3
							},
							{
								text: '检查类型22222',
								value: 4
							}, {
								text: '状态112',
								value: 5
							}, {
								text: '状态2222',
								value: 6
							}, {
								text: '状态3333',
								value: 7
							}
						]
					},{
						type: '业态',
						children: [{
							text: '全部',
							value: ''
						}, {
							text: '状态1',
							value: 1
						}, {
							text: '状态2',
							value: 2
						}, {
							text: '状态3',
							value: 3
						}]
					},
					{
						type: '状态',
						children: [{
							text: '全部',
							value: ''
						}, {
							text: '状态1',
							value: 1
						}, {
							text: '状态2',
							value: 2
						}, {
							text: '状态3',
							value: 3
						}]
					}
				],				
}
		}

用到的俩个方法

onSelected(res) {
				console.log(res)
			},
			dateChange(d) {
				uni.showToast({
					icon: 'none',
					title: d
				})
			},

自己定义的一些样式

<style lang="scss" scoped>
	.check-page::v-deep {
		.root {
			.navs {
				color: $value-color;
			}

			.actNav,
			.actOpt {
				color: $base-color !important;
				background-color: $bg-e533;
			}
		}
		.navs {
			padding: 0 !important;
		}
		.navs>uni-view {
			// padding:0  40rpx;
			padding: 0 20rpx 0 40rpx;
			justify-content: space-between;
		}
	}
</style>
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值