首页 > 其他分享 >vue项目实录:下拉刷新组件的开发

vue项目实录:下拉刷新组件的开发

时间:2023-09-05 23:01:56浏览次数:40  
标签:vue 实录 pullRefresh 刷新 组件 percentage circleIcon icon

“下拉刷新”和“上滑加载更多”功能在前端、尤其是移动端项目中非常重要,这里笔者由曾经做过的vue项目中的“blink”功能和各位探讨下【下拉刷新】组件的开发:


正式开篇

在前端项目的 components 文件夹下新建 pullRefreshView 文件夹,在其中新建组件 index.vue:(它代表“整个屏幕”,通过slot插入页面其他内容而不是传统的设置遮罩层触发下拉刷新)

首先需要编写下拉刷新组件的 template,这里用到 <slot>,代码如下:

<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>

上面代码中,最外层使用了一个 div 用来包裹,作为事件绑定的容器,同时新建一个圆形 icon 的 div .circleIcon,我们将此 icon 样式设置在屏幕外,达到隐藏的效果,代码如下:

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

下拉刷新组件的 UI 基本编写完毕,接下来就要绑定事件了,通过上述分析,加上我们之前章节开发图片查看器的原理,我们需要用到移动端 touchstart,touchmove,touchend 事件,可以实现下拉刷新效果。

首先,监听 touchstart 事件:

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

在 touchstart 事件中,我们主要做的是记录一些初始值,包括手指第一次接触屏幕时的位置,然后将圆形 icon 的动画效果先隐藏。

然后,监听 touchmove 事件:

touchmove(evt){
	if(this.pullRefresh.dragStart===null){
		return
	}
	let target=evt.targetTouches[0]
	// 向上滑为正,向下拉为负
	this.pullRefresh.percentage=(this.pullRefresh.dragStart-target.clientY)/window.screen.height
	let scrollTop=document.documentElement.scrollTop || document.body.scrollTop
	if(scrollTop===0){
		//this.pullRefresh指data中的pullRefresh对象(下方有),而evt即事件event参数
		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
		}
	}
},

在 touchmove 事件里,我们主要做的是根据手指移动的量来实时将圆形 icon 移动并旋转,这里有几点确实要说明一下:

  • 我们的下拉刷新触发的时机是在页面处于屏幕顶部并且手指向下拖动,这两个条件,缺一不可,在代码中,我们利用 scrollTop == 0this.pullRefresh.percentage < 0 来判断。
  • 在进入下拉刷新状态时,此时手指不断向下拖动,首先圆形 icon.circleIcon 会向下滚动并旋转,当滚动到临界值时就只原地旋转。
  • 如果手指在向上拖动,圆形 icon.circleIcon 就会向上滚动并旋转。
  • 直到手指离开屏幕前,都不会触发下拉刷新,只是圆形 icon.circleIcon 在不停的上下移动。

监听 touchend 事件:

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
}

在 touchend 事件中,我们主要是做一些动画执行的操作,大家可以看看代码中的注释,这里说明一下:

  1. 此时手指离开屏幕,位移量达到临界值时,并且也有进入下拉刷新的标志位,就表明要触发正在刷新。此时圆形 icon原地旋转,并触发下拉刷新回调方法,延迟 700ms 后向上收起。
  2. 我们在实现圆形 icon 时的旋转和位移动画时,用了两个 div,在 touchmove 时,我们主要对外层的 div 也就是 ref=circleIcon,来实现位移和旋转。
  3. 在 touchend 时,我们主要给内层的 div 也就是 ref=circleIconInner 来加 animation 动画,因为无法给一个 div 同时使用位移旋转和 animation 动画,所以这里一个技巧就是给父元素设置位移和旋转,它的子元素在不设置任何 CSS 动画样式时,是会随着父元素而生效的。

最后,我们看下【data】中都有什么:

data(){
	return{
		pullRefresh:{
			dragStart:null,   //开始抓取标志位
			percentage:0,   //拖动量(百分比)
			dragThreshold:0.3,   //临界值
			moveCount:200,   //位移系数,可以调节圆形图片icon的运动速率
			joinRefreshFlag:null,   //进入刷新状态的标志位(true)
		}
	}
},

补充:slot

<template>中为什么有<slot>

slot有三种形式:

  1. 普通插槽
  2. 具名插槽
  3. 作用域插槽

可能我们一般用具名slot的时候比较多,但是第一种也格外好用——正因为它没有名字,所以引用这个组件的另一个组件中包裹其中的所有内容都归这个slot所有:

假定my-component组件中有如下模板:

<div>
	<h2>我是子组件</h2>
	<slot>只有在没有内容分发的情况下这句话才会出现</slot>
</div>

父组件模板:

<div>
	<h1>这是父组件地盘</h1>
	<my-component>
		<p>这是一些初始内容</p>
		<p>这是更多的内容</p>
	</my-component>
</div>

最后就会被渲染成这样:

<div> 
	<h1>这是父组件地盘</h1>
	<div> 
		<h2>我是子组件</h2>
		<p>这是一些初始内容</p>
		<p>这是更多的内容</p>
	</div> 
</div>

所以这里这样做,就是为了在“父组件”中调用时让“下拉的动画”更自然,但又不会增加一个文件的负担。

标签:vue,实录,pullRefresh,刷新,组件,percentage,circleIcon,icon
From: https://blog.51cto.com/u_15296224/7380641

相关文章

  • vue3探索——使用ref与$parent实现父子组件间通信
    在vue3中,可以使用vue3的APIdefineExpose()函数结合ref或者$parent,实现父子组件数据的传递。子组件向父组件传递数据defineExpose()和ref子组件:通过defineExpose()函数,向外暴露响应式数据或者方法//src/components/son.vue<template><div><h1>儿子有${{so......
  • uniapp项目实践总结(十)自定义滑动触摸组件
    在APP的日常开放过程中,我们经常可以看到上拉刷新、下拉刷新、左滑、右滑、触底加载等效果,那其中的原理是如何呢,又是如何实现的呢,下面就一探究竟。这篇文章主要是讲述自定义滑动触摸组件的方放,兼容网页H5端、微信小程序端和App端。目录准备工作原理分析组件实现实战......
  • 使用 vue 渲染静态模板
    最近再一次需要做纯静态页面(无任何脚本语言,只保留css和html),以往我直接使用ejs生成,但是工作中一直使用jsx和vue来组装页面,就突发奇想,难道react、vue不能只渲染纯静态页面吗?有了这个想法,我就想验证下可行性,万能百度开始,找了一圈,发现基本都是需要脚本依赖的,这就意味着必......
  • 如何在Vue项目中引入富文本编辑器(wang-enduit)
    介绍官网https://www.wangeditor.com/安装yarnadd@wangeditor/editornpminstall@wangeditor/editor--saveyarnadd@wangeditor/editor-for-vue@nextnpminstall@wangeditor/editor-for-vue@next--save使用自定义上传图片,先转base64,转blob,上传服务器<divid="wa......
  • 【坑】VUE中动态数据使用 wow.js 没效果的问题
    一般来说正常使用都是在mounted函数中mounted(){this.$nextTick(()=>{this.$wow.init()})}这样如果是死数据是可以正常出现效果的但是如果是请求回来的数据是没有效果的需要改一下生成时机  此处的newList即为请求的数据watch:{newsl......
  • [MSSQL]开启/关闭Ad Hoc Distributed Queries组件
    SQLServer阻止了对组件“AdHocDistributedQueries”的STATEMENT“OpenRowset/OpenDatasource”的访问开启组件:execsp_configure'showadvancedoptions',1reconfigureexecsp_configure'AdHocDistributedQueries',1reconfigure关闭组件:execsp_configur......
  • Vue3实现批量打印二维码与条形码
    (二维码与条形码在vue3中的使用)欢迎阅览本篇文章这篇文章是我在工作途中对批量生成二维码的一些见解,例如vue-qr(二维码)与jsbarcode(条形码)在vxe-table表格中的使用,二维码与条形码的批量生成与打印(打印时一页一个码)等。注意!本篇文章的所有代码均使用setup语法糖与TypeScript,请确保......
  • vue3如何监听 props 的变化?
    背景实际开发过程中,当需要通过watch 监听传入的props的某个值的变化,来动态改变组件内部的样式,实现方式如下:exportdefault{name:'countdown',props:{showBox:{type:Boolean,required:true,default:false},},setup(prop......
  • vue语言中的keep-alive的作用
    在前端Vue语言中,keep-alive是一个抽象组件,用于在Vue组件树中缓存动态组件。它可以有效地保留组件的状态,以避免在组件之间切换时重复渲染和销毁组件,从而提高性能。使用keep-alive包裹动态组件后,当动态组件被切换时,它将会被缓存,而不是被销毁。这样,组件的状态、DOM以及所有的子组件......
  • vue项目新建 端口更改
    vue项目新建步骤vite创建vue3项目(最简单):在需要的文件目录中输入cmd命令,打开命令窗口,在当前文件目录下创建项目(直接打开命令窗口,默认C盘创建项目)第一步:npminitvite-appvue-code//code为项目名第二步:cd./vue-code//进入项目第三步:npminstall//安装依赖包第四......