如何用vue开发水波纹点击效果组件
时间:2023-03-15 09:06:08
科技观察
@import"../styles/import.less";.mu-circle-ripple{position:absolute;width:100%;height:100%;left:0;top:0;pointer-events:none;user-select:none;border-radius:50%;background-color:currentColor;background-clip:padding-box;opacity:0.1;}.mu-ripple-enter-active,.mu-ripple-leave-active{transition:transform1s@easeOutFunction,opacity2s@easeOutFunction;}.mu-ripple-enter{transform:scale(0);}.mu-ripple-leave-active{opacity:0!important;}最近在用vue2做一个新的材质ui库。波纹点击效果在materialdesign中用过很多次,所以我决定把它封装成一个公共组件,直接调用就可以了。开发前的思考实现波纹点击效果的常用方法是监听元素的mousedown事件,在元素内部创建一个波纹元素,调整元素的transform:scale(0);totransform:scale(1);,通过计算点击位置来设置波纹元素的大小和位置,达到波纹扩散的效果。我把组件分为两部分,circleRipple.vue和TouchRipple.vue各自实现不同的功能circleRipple.vue波纹扩散组件,完成波纹扩散的效果TouchRipple.vue监听鼠标和触摸相关事件,控制显示和位置圈波纹。circleRipple.vuecircleRipple需要完成波纹展开的效果,它的大小和位置是可以从外部控制的,所以使用vue的过渡动画来完成这个效果,并提供mergeStyle、color、opacity参数来从外部控制它的样式。实现代码如下。
@import"../styles/import.less";.mu-circle-ripple{position:absolute;width:100%;height:100%;left:0;top:0;pointer-events:none;user-select:none;border-radius:50%;background-color:currentColor;background-clip:padding-box;opacity:0.1;}.mu-ripple-enter-active,.mu-ripple-leave-active{transition:transform1s@easeOutFunction,opacity2s@easeOutFunction;}.mu-ripple-enter{transform:scale(0);}.mu-ripple-leave-active{opacity:0!important;}vue2对动画方面做了比较大的修改,去掉了把指示更换成组件外,它还可以完成更复杂的动画效果,详见这里。vue2transitionTouchRipple.vueTouchRipple需要控制circleRipple的显示,完成如下:监听鼠标和触摸相关的事件,控制circleRipple的显示。通过单击事件对象计算circleRipple的大小和位置。如果频繁点击,可能会出现多个圆形涟漪。一、基础模板+数据模型 起止波纹效果只需要添加一个ripple元素即可一个objecttoripple,不同的是当你需要从点击展开的时候,你需要计算ripple元素的大小和位置{//isRippleTouchGenerated是touch事件的开始(event,isRippleTouchGenerated){//过滤touchstart和mousedown同时存在的情况if(this.ignoreNextMouseDown&&!isRippleTouchGenerated){this.ignoreNextMouseDown=falsereturn}//添加一个ripple元素组件this.ripples.push({key:this.nextKey++,color:this.color,opacity:this.opacity,style:this.centerRipple?{}:this.getRippleStyle(event)//不是必须的计算从中心位置展开的波纹元素})this.ignoreNextMouseDown=isRippleTouchGenerated},end(){if(this.ripples.length===0)returnthis.ripples.splice(0,1)//删除一个rippleelementthis.stopListeningForScrollAbort()//结束触摸滚动的处理}}因为vue2是基于VirtualDOM的,如果在添加一个元素的时候没有key,同时删除一个元素,dom树不会变化,不会有动画效果。监听mousedown和touchstartmousedown和touchstart的处理会有所不同,但都是用来启动涟漪效果的。触摸涉及多次点击。我们一般选择第一种。{handleMouseDown(event){//只监听鼠标左键点击if(event.button===0){this.start(event,false)}},handleTouchStart(event){event.stopPropagation()//防止多次波纹点击组件嵌套if(event.touches){this.startListeningForScrollAbort(event)//开始touchmove触发滚动处理this.startTime=Date.now()}this.start(event.touches[0],true)}}touchmovecontrol发生touchMove事件时,需要判断是否,移动的距离和时间,然后结束小波纹点击小谷{//touchmove结束波纹控制stopListeningForScrollAbort(){if(!this.handleMove)this.handleMove=this.handleTouchMove.bind(this)document.body.removeEventListener('touchmove',this.handleMove,false)},startListeningForScrollAbort(事件){this.firstTouchY=event.touches[0].clientYthis.firstTouchX=event.touches[0]。clientXdocument.body.addEventListener('touchmove',this.handleMove,false)},handleTouchMove(事件){consttimeSinceStart=Math.abs(Date.now()-this.startTime)if(timeSinceStart>300){this.stopListeningForScrollAbort()return}constdeltaY=Math.abs(event.touches[0].clientY-this.firstTouchY)constdeltaX=Math.abs(event.touches[0].clientX-this.firstTouchX)//滑动范围结束于>6px。if(deltaY>6||deltaX>6)this.end()}}计算波纹的位置和大小需要计算从点击开始扩散的波纹效果波纹元素的大小和位置{getRippleStyle(event){letholder=this.$refs.holder//该方法返回一个矩形对象,它包含四个属性:left,top,right,bottom分别代表元素的边和页面的顶边以及距离左边。letrect=holder.getBoundingClientRect()//获取点击点的位置letx=event.offsetXletyif(x!==undefined){y=event.offsetY}else{x=event.clientX-rect.lefty=event.clientY-rect.top}//获取***边长letmaxif(rect.width===rect.height){max=rect.width*1.412}else{max=Math.sqrt((rect.width*rect.width)+(rect.height*rect.height))}constdim=(max*2)+'px'return{width:dim,height:dim,//通过margin来控制波纹的中心点和点击点保持一致'margin-left':-max+x+'px','margin-top':-max+y+'px'}}}是因为touchRipple内部有position:absolute布局,使用时需要将position:relative//listItem添加到外部。vue
<divclass="mu-item-content">//...