Development of vue Drop down Refresh Component and Detailed Explanation of slot

  • 2021-10-15 09:51:47
  • OfStack

The functions of "pull-down refresh" and "slide-up load more" are very important in front-end projects, especially in mobile projects. Here, the author discusses the development of "pull-down refresh" components from the "blink" function in vue projects that have been done before:

Official opening

Create a new pullRefreshView folder under the components folder of the front-end project, where you create a new component index. vue: (which stands for "full screen" and triggers a drop-down refresh by inserting other contents of the page through slot instead of setting the traditional mask layer)

First, you need to write template for the drop-down refresh component, which is used here <slot> The code is as follows:


<template>
	<div class="pullRefreshView" @touchmove="touchmove" @touchstart="touchstart" @touchend="touchend">
		<div ref="circleIcon" class="circle-icon">
			<div ref="circleIconInner" class="circle-icon-inner"></div>
		</div>
		<slot></slot>
	</div>
</template>

In the above code, the outermost layer uses an div to wrap it as a container for event binding, and at the same time creates a new div. circleIcon with a round icon. We set this icon style outside the screen to achieve the hidden effect. The code is as follows:


<style>
	.circle-icon{
		position: absolute;
		left: 0.625rem;
		top: -1.875rem;
	}
	.circle-icon-inner{
		width: 1.5625rem;
		height: 1.5625rem;
		background-image: url(' Circle picture address ');
		background-size: cover;
	}
	.circle-rotate{
		animation: xuzhuan .8s linear infinite;
	}
	@keyframes xuzhuan{
		0%{}
		25%{}
		50%{}
		75%{}
		100%{}
	}
</style>

The UI of the drop-down refresh component is basically written, and then the event will be bound. Through the above analysis and the principle of developing the picture viewer in our previous chapter, we need to use the mobile touchstart, touchmove and touchend events to achieve the drop-down refresh effect.

First, listen for touchstart events:


touchstart(evt){
	this.pullRefresh.dragStart=evt.targetTouches[0].clientY
	this.$refs.circleIcon.style.webkitTransition='none'
},

In the touchstart event, what we mainly do is to record some initial values, including the position of the finger when it touches the screen for the first time, and then hide the animation effect of the circular icon first.

Then listen for touchmove events:


touchmove(evt){
	if(this.pullRefresh.dragStart===null){
		return
	}
	let target=evt.targetTouches[0]
	//  Sliding up is positive and pulling down is negative 
	this.pullRefresh.percentage=(this.pullRefresh.dragStart-target.clientY)/window.screen.height
	let scrollTop=document.documentElement.scrollTop || document.body.scrollTop
	if(scrollTop===0){
		//this.pullRefresh Refer to data In pullRefresh Object (below), and evt Events event Parameter 
		if(this.pullRefresh.percentage<0 && evt.cancelable){
			evt.preventDefault()
			this.pullRefresh.joinRefreshFlag=true
			let translateY=-this.pullRefresh.percentage*this.pullRefresh.moveCount
			if(Math.abs(this.pullRefresh.percentage)<=this.pullRefresh.dragThreshold){
				let rotate=translateY/30*360
				this.$refs.circleIcon.style.webkitTransform='translate3d(0'+translateY+'px,0) rotate('+rotate+'deg)'
			}
		}else{
			if(this.pullRefresh.joinRefreshFlag===null){
				this.pullRefresh.joinRefreshFlag=false
			}
		}
	}else{
		if(this.pullRefresh.joinRefreshFlag===null){
			this.pullRefresh.joinRefreshFlag=false
		}
	}
},

In the touchmove event, what we mainly do is to move and rotate the circular icon in real time according to the amount of finger movement. Here are a few points to be explained:

Our pull-down refresh is triggered when the page is at the top of the screen and the finger is dragged down. These two conditions are indispensable. In the code, we use scrollTop == 0 And this.pullRefresh.percentage < 0 To judge. When entering the pull-down refresh state, the finger keeps dragging down at this time. First, the circle icon. circleIcon will scroll down and rotate, and when scrolling to the critical value, it will only rotate in situ. If the finger is dragging upward, the circle icon. circleIcon will scroll upward and rotate. Until the finger leaves the screen, the pull-down refresh will not be triggered, but the circle icon. circleIcon keeps moving up and down.

Listen for touchend events:


touchend(evt){
	if(this.pullRefresh.percentage===0){
		return
	}
	if(Math.abs(this.pullRefresh.percentage)>this.pullRefresh.dragThreshold && this.pullRefresh.joinRefreshFlag){
		this.$emit('onRefresh')
		this.$refs.circleIconInner.classList.add('circle-rotate')
		setTimeout(()=>{
			this.$refs.circleIconInner.classList.remove('circle-rotate')
			this.$refs.circleIcon.style.webkitTransition='330ms'
			this.$refs.circleIcon.style.webkitTransform='translate3d(0,0,0) rotate(0deg)'
		},700)
	}else{
		if(this.pullRefresh.joinRefreshFlag){
			this.$refs.circleIcon.style.webkitTransition='330ms'
			this.$refs.circleIcon.style.webkitTransform='translate3d(0,0,0) rotate(0deg)'
		}
	}
	this.pullRefresh.joinRefreshFlag=null
	this.pullRefresh.dragStart=null
	this.pullRefresh.percentage=0
}

In the touchend event, we mainly do some animation operations. You can look at the comments in the code, which explains 1 below:

At this time, when the finger leaves the screen, the displacement reaches the critical value, and there is also a flag bit to enter the pull-down refresh, it indicates that the refresh is being triggered. At this time, the circular icon rotates in situ, triggers the pull-down refresh callback method, and delays 700ms and then retracts upwards. We use two div when we realize the rotation and bit shift picture in the circular icon. In touchmove, we mainly realize the displacement and rotation by div of the outer layer, that is, ref=circleIcon. In touchend, we mainly add animation animation to the inner div, that is, ref=circleIconInner. Because it is impossible to use displacement rotation and animation animation for an div at the same time, one skill here is to set displacement and rotation for the parent element, and its child elements will take effect with the parent element when no CSS animation style is set.

Finally, let's look at what's in "data":


data(){
	return{
		pullRefresh:{
			dragStart:null, // Start grabbing flag bits 
			percentage:0, // Drag quantity ( Percentage )
			dragThreshold:0.3, // Critical value 
			moveCount:200, // Displacement coefficient, which can adjust circular pictures icon Motion rate of 
			joinRefreshFlag:null, // The flag bit that enters the refresh state ( true ) 
		}
	}
},

Supplement: slot

<template> Why are there in <slot> ?

slot comes in three forms:

Ordinary slot Named slot Scope slot

Maybe we use the name slot more often, but the first one is also very easy to use-because it has no name, all the contents wrapped in the other component that references this component belong to this slot:

Assume the following template in the my-component component:


<div>
	<h2> I am a subcomponent </h2>
	<slot> This sentence will only appear if there is no content distribution </slot>
</div>

Parent component template:


<div>
	<h1> This is the parent assembly site </h1>
	<my-component>
		<p> This is 1 Some initial content </p>
		<p> This is more content </p>
	</my-component>
</div>

Finally, it will be rendered like this:


<div> 
	<h1> This is the parent assembly site </h1>
	<div> 
		<h2> I am a subcomponent </h2>
		<p> This is 1 Some initial content </p>
		<p> This is more content </p>
	</div> 
</div>

So this is done here to make the "drop-down animation" more natural when called in the "parent component", but it will not increase the burden of 1 file.


Related articles: