uniapp applet—realize sliding down to close the drawer (including sliding up, down, left, and right)

Effect

insert image description here
Operation: When you click on the corresponding text, a pop-up box will appear from the bottom, if the slide exceeds a certain speed, the pop-up box will return to the bottom and hide;

Core points:

// 当按下去的时候
			fingerstart(e) {
    
    
				// 记录 距离可视区域左上角 左边距 和 上边距
				this.startData.clientX = e.changedTouches[0].clientX;
				this.startData.clientY = e.changedTouches[0].clientY;
				
			},
			// 当抬起来的时候
			fingerend(e) {
    
     
				// 当前位置 减去 按下位置 计算 距离
				const subX = e.changedTouches[0].clientX - this.startData.clientX;
				const subY = e.changedTouches[0].clientY - this.startData.clientY;
				if (subY > this.updDistance || subY < -this.updDistance) {
    
    
					if (subY > this.updDistance) {
    
    
						this.showMax = false;
						this.getDomTop()
					} else if (subY < -this.updDistance) {
    
    
						this.showMax = true;
						this.getDomTop()
					}
				} 
			},

use components

<btmPop :startShow="showPop" @closePop="closeWord">
	<template #detail>
	</template>
</btmPop>

all codes

<template>
	<view 
		class="detailBox" 
		:style="[
			{
    
    
			'height':minHeight+'px',
			'transform':`translateY(${
      
      isHide?99:0}rem)`,
			'backgroundColor':bgColor
			}, 
		]"  
		@touchstart="fingerstart"
		@touchend="fingerend"
	>
	
		<view v-if="showLine" class="popLine"></view>
		<view v-if="!showLine" class="popClose" @click="closePopBox">
			<u-icon name="close" :size="20"></u-icon>
		</view>
		<!-- 自定义内容插槽 -->
		<slot name="detail"></slot>
	</view>
</template>

<script>
	export default{
    
    
		props:{
    
    
			// 高度
			boxHeihgt:{
    
    
				type:Number,
				default:0
			},
			// 背景色
			bgColor:{
    
    
				type:String,
				default:"#FDFAF5"
			},
			// 控制初始是否显示
			startShow:{
    
    
				type:Boolean,
				default:false
			},
			// 是否显示线
			showLine:{
    
    
				type:Boolean,
				default:true
			},
			// 上下滑动 超过多少距离触发 updownDistance
			updDistance: {
    
     
				type: Number,
				default: 160
			},
		},
		watch:{
    
    
			'startShow':{
    
    
				handler(n,o){
    
    
					this.isHide =!n;
				},
				deep:true,
				immediate:true
			}
		},
		data(){
    
    
			return{
    
    
				minHeight:0,
				isHide:true,
				boxPadBottom:0,
				// 根据滑动设置位置
				changeTop:0,
				// 是否固定高度
				showMax:false,
				// 记录起始位置
				startData: {
    
    
					clientX: '',
					clientY: ''
				}
			}
		},
		methods:{
    
    
			
			// 当按下去的时候
			fingerstart(e) {
    
    
				// 记录 距离可视区域左上角 左边距 和 上边距
				this.startData.clientX = e.changedTouches[0].clientX;
				this.startData.clientY = e.changedTouches[0].clientY;
				
			},
			// 当抬起来的时候
			fingerend(e) {
    
     
				// 当前位置 减去 按下位置 计算 距离
				const subX = e.changedTouches[0].clientX - this.startData.clientX;
				const subY = e.changedTouches[0].clientY - this.startData.clientY;
				if (subY > this.updDistance || subY < -this.updDistance) {
    
    
					if (subY > this.updDistance) {
    
    
						// this.bottomscroll(subY);
						this.showMax = false;
						this.getDomTop()
					} else if (subY < -this.updDistance) {
    
    
						// this.topscroll(subY);
						this.showMax = true;
						this.getDomTop()
					}
				} 
			},
			// 获取元素的top值
			getDomTop(){
    
    
				const query = uni.createSelectorQuery().in(this);
				query.select('.detailBox').boundingClientRect(data => {
    
    
				  if(data){
    
    
					// 上滑
					if(this.showMax){
    
    
					}else{
    
    
					// 下滑
						this.closePopBox()
					}
				  }
				}).exec();
			},
			// 关闭弹框
			closePopBox(){
    
    
				this.isHide = true;
				this.$emit("closePop",true)
			}
		},
		onReady() {
    
    
			let windowHeight = uni.getSystemInfoSync().windowHeight;
			let NavbarHeight = this.$store.state.Layout.NavbarHeight;
			this.minHeight = windowHeight-NavbarHeight-20-this.boxHeihgt;
			
		},
	}
</script>

<style lang="scss" scoped>
	.detailBox {
    
    
		position: fixed;
		width: 100%;
		height: auto;
		bottom: 0;
		left: 0;
		border-top-left-radius: 40rpx;
		border-top-right-radius: 40rpx;
		overflow-y: auto;
		transition: all .5s;
		z-index: 99999;
	}
	.popLine{
    
    
		width: 115rpx;
		height: 10rpx;
		border-radius: 28rpx;
		background-color: #EEE2D6;
		margin: 20rpx auto 35rpx;
	}
	.popClose{
    
    
		width: calc(100% - 80rpx);
		display: flex;
		justify-content: flex-end;
		margin: 30rpx 40rpx 10rpx 40rpx;
	}
</style>

Summarize:

I didn't delete some redundant parts of this component, and I can expand it by myself. The following is attached with the up, down, left, and right slides on the mobile terminal, which can be used for reference to realize the left and right slides of the applet

Swipe up, down, left, and right on the mobile terminal

// 元素左右滑动
  const NavonTouchStart = (e) => {
    
    
    e.persist();
    state.firstX = e.targetTouches[0].clientX;
    state.firstY = e.targetTouches[0].clientY + 60;
  };
  const NavonTouchEnd = (e) => {
    
    
    e.persist();
    state.endX = e.targetTouches[0].clientX;
    state.endY = e.targetTouches[0].clientY + 60;
    let moveX = state.endX - state.firstX;
    let moveY = state.endY - state.firstY;
    if (Math.abs(moveX) > 130 || Math.abs(moveY) > 130) {
    
        // 130理解为滑动距离
      if (Math.abs(moveX) > Math.abs(moveY)) {
    
    
        let ele = moveX > 0 ? '向右' : '向左';

      } else {
    
    
        let ele = moveY > 0 ? '向下' : '向上';
       
      }
    }
  };

Guess you like

Origin blog.csdn.net/hzqzzz/article/details/128485009