溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

怎么使用vue開發(fā)波紋點(diǎn)擊特效組件

發(fā)布時(shí)間:2021-11-17 15:18:03 來源:億速云 閱讀:297 作者:iii 欄目:web開發(fā)

本篇內(nèi)容主要講解“怎么使用vue開發(fā)波紋點(diǎn)擊特效組件”,感興趣的朋友不妨來看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“怎么使用vue開發(fā)波紋點(diǎn)擊特效組件”吧!

開發(fā)之前的思考

常見的波紋點(diǎn)擊效果的實(shí)現(xiàn)方式是監(jiān)聽元素的 mousedown 事件,在元素內(nèi)部創(chuàng)建一個(gè) 波紋元素 ,并調(diào)整元素的 transform: scale(0);  到 transform: scale(1);, 通過計(jì)算點(diǎn)擊的位置來設(shè)置 波紋元素 的大小和位置,以達(dá)到波紋擴(kuò)散的效果。

我將組件分為兩個(gè)部分, circleRipple.vue 和 TouchRipple.vue 各自實(shí)現(xiàn)不同的功能

  1. circleRipple.vue 波紋擴(kuò)散組件,完成波紋擴(kuò)散的效果

  2. TouchRipple.vue 監(jiān)聽 mouse 和 touch 相關(guān)事件,控制 circleRipple 的顯示,位置。

circleRipple.vue

circleRipple 需要完成波紋擴(kuò)展的效果,而且可以從外部控制它的大小和位置, 所以利用 vue 的 transition 動(dòng)畫完成效果,  提供mergeStyle 、 color 、opacity 參數(shù)來從外部控制它的樣式。實(shí)現(xiàn)代碼如下。

<template>   <transition name="mu-ripple">     <div class="mu-circle-ripple" :style="styles"></div>   </transition> </template>  <script> import {merge} from '../utils' export default {   props: {     mergeStyle: {       type: Object,       default () {         return {}       }     },     color: {       type: String,       default: ''     },     opacity: {       type: Number     }   },   computed: {     styles () {       return merge({}, {color: this.color, opacity: this.opacity}, this.mergeStyle)     }   } } </script>  <style lang="less"> @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: transform 1s @easeOutFunction, opacity 2s @easeOutFunction; }  .mu-ripple-enter {   transform: scale(0); }  .mu-ripple-leave-active{   opacity: 0 !important; } </style>

vue2 對(duì)于動(dòng)畫方面做了比較大的修改,除了把指令換成組件外,它還可以完成更復(fù)雜的動(dòng)畫效果,具體可以看這里 vue2 transition

TouchRipple.vue

TouchRipple 需要控制 circleRipple 的顯示。完成以下內(nèi)容:

  1. 監(jiān)聽 mouse 和 touch 相關(guān)事件, 控制 circleRipple 的顯示。

  2. 通過點(diǎn)擊事件 event 對(duì)象, 計(jì)算出 circleRipple 的大小和位置

  3. 如果頻繁點(diǎn)擊可能出現(xiàn)多個(gè) circleRipple

首先,基本模板 + 數(shù)據(jù)模型

<template>   <!--最外層用div包裹-->   <div @mousedown="handleMouseDown" @mouseup="end()" @mouseleave="end()" @touchstart="handleTouchStart"  @touchend="end()" @touchcancel="end()">     <!--外層包裹防止波紋溢出-->     <div :style="style" ref="holder">       <!--多個(gè)波紋用 v-for 控制-->       <circle-ripple :key="ripple.key" :color="ripple.color" :opacity="ripple.opacity" :merge-style="ripple.style" v-for="ripple in ripples"></circle-ripple>     </div>     <!--利用slot分發(fā)實(shí)際內(nèi)容-->     <slot></slot>   </div> </template>  <script> import circleRipple from './circleRipple' export default {   props: {     // 是否從中間擴(kuò)散,設(shè)為false會(huì)從點(diǎn)擊處擴(kuò)散     centerRipple: {       type: Boolean,       default: true     },     // 外層包裹的樣式     style: {       type: Object,       default () {         return {           height: '100%',           width: '100%',           position: 'absolute',           top: '0',           left: '0',           overflow: 'hidden'         }       }     },     // 波紋顏色     color: {       type: String,       default: ''     },     // 波紋透明度     opacity: {       type: Number     }   },   data () {     return {       nextKey: 0, // 記錄下一個(gè)波紋元素的key值, 相當(dāng)于uuid,不設(shè)置的話會(huì)使動(dòng)畫失效       ripples: [] // 波紋元素參數(shù)數(shù)組     }   },   mounted () {     this.ignoreNextMouseDown = false // 防止既有 touch 又有 mouse點(diǎn)擊的情況   },   methods: {     start (event, isRippleTouchGenerated) {       // 開始波紋效果     },     end () {       // 結(jié)束波紋效果     },     handleMouseDown (event) {       // 監(jiān)聽 鼠標(biāo)單擊     },     handleTouchStart (event) {       // 監(jiān)聽 touchstart 方法     }   },   components: {     'circle-ripple': circleRipple   } } </script>

開始和結(jié)束波紋效果

增加一個(gè)波紋元素只需要在 ripple 增加一個(gè) object 即可,不同的是當(dāng)需要從點(diǎn)擊處擴(kuò)展時(shí),需要計(jì)算一下波紋元素的大小和位置。

{   // isRippleTouchGenerated 是否是touch 事件開始的   start (event, isRippleTouchGenerated) {     // 過濾 touchstart 和 mousedown 同時(shí)存在的情況     if (this.ignoreNextMouseDown && !isRippleTouchGenerated) {       this.ignoreNextMouseDown = false       return     }          // 添加一個(gè) 波紋元素組件     this.ripples.push({       key: this.nextKey++,        color: this.color,       opacity: this.opacity,       style: this.centerRipple ? {} : this.getRippleStyle(event) // 不是從中心擴(kuò)展的需要計(jì)算波紋元素的位置     })     this.ignoreNextMouseDown = isRippleTouchGenerated  },  end () {    if (this.ripples.length === 0) return    this.ripples.splice(0, 1) // 刪除一個(gè)波紋元素    this.stopListeningForScrollAbort() // 結(jié)束 touch 滾動(dòng)的處理   } }

因?yàn)?vue2 基于 Virtual DOM 的, 所以如果沒有 key 在增加一個(gè)元素又同時(shí)刪除一個(gè)元素的時(shí)候,dom  tree并沒有發(fā)生變化,是不會(huì)產(chǎn)生動(dòng)畫效果的。

監(jiān)聽 mousedown 和 touchstart

mousedown 和 touchstart 處理上會(huì)有所不同,但都是用來啟動(dòng)波紋效果的, touch涉及到多點(diǎn)點(diǎn)擊的問題,我們一般取***個(gè)即可。

{     handleMouseDown (event) {       // 只監(jiān)聽鼠標(biāo)左鍵的點(diǎn)擊       if (event.button === 0) {         this.start(event, false)       }     },     handleTouchStart (event) {       event.stopPropagation() // 防止多個(gè)波紋點(diǎn)擊組件嵌套       if (event.touches) {         this.startListeningForScrollAbort(event) // 啟動(dòng) touchmove 觸發(fā)滾動(dòng)處理         this.startTime = Date.now()       }       this.start(event.touches[0], true)     } }

touchmove控制

當(dāng)發(fā)生touchMove事件是需要判斷是否,移動(dòng)的距離和時(shí)間,然后結(jié)束小波紋點(diǎn)擊小姑

{   // touchmove 結(jié)束波紋控制   stopListeningForScrollAbort () {     if (!this.handleMove) this.handleMove = this.handleTouchMove.bind(this)     document.body.removeEventListener('touchmove', this.handleMove, false)   },   startListeningForScrollAbort (event) {     this.firstTouchY = event.touches[0].clientY     this.firstTouchX = event.touches[0].clientX     document.body.addEventListener('touchmove', this.handleMove, false)   },   handleTouchMove (event) {     const timeSinceStart = Math.abs(Date.now() - this.startTime)     if (timeSinceStart > 300) {       this.stopListeningForScrollAbort()       return     }     const deltaY = Math.abs(event.touches[0].clientY - this.firstTouchY)     const deltaX = Math.abs(event.touches[0].clientX - this.firstTouchX)     // 滑動(dòng)范圍在 > 6px 結(jié)束波紋點(diǎn)擊效果     if (deltaY > 6 || deltaX > 6) this.end()   } }

計(jì)算波紋的位置和大小

需要從點(diǎn)擊處擴(kuò)散的波紋效果,需要計(jì)算波紋元素的大小和位置

{   getRippleStyle (event) {     let holder = this.$refs.holder     //  這個(gè)方法返回一個(gè)矩形對(duì)象,包含四個(gè)屬性:left、top、right和bottom。分別表示元素各邊與頁面上邊和左邊的距離。     let rect = holder.getBoundingClientRect()      // 獲取點(diǎn)擊點(diǎn)的位置     let x = event.offsetX     let y     if (x !== undefined) {       y = event.offsetY     } else {       x = event.clientX - rect.left       y = event.clientY - rect.top     }     // 獲取***邊長(zhǎng)     let max     if (rect.width === rect.height) {       max = rect.width * 1.412     } else {       max = Math.sqrt(         (rect.width * rect.width) + (rect.height * rect.height)       )     }     const dim = (max * 2) + 'px'     return {       width: dim,       height: dim,       // 通過margin控制波紋中心點(diǎn)和點(diǎn)擊點(diǎn)一致       'margin-left': -max + x + 'px',       'margin-top': -max + y + 'px'     }   } }

使用

由于 touchRipple 內(nèi)部都是 position:absolute 布局,使用時(shí),需要在外部加上 position:relative

// listItem.vue <a :href="href" @mouseenter="hover = true" @mouseleave="hover = false" @touchend="hover = false"     @touchcancel="hover = false" class="mu-item-wrapper" :class="{'hover': hover}">     <touch-ripple class="mu-item" :class="{'mu-item-link': link}" :center-ripple="false">       <div class="mu-item-media">         <slot name="media"></slot>       </div>       <div class="mu-item-content">         // ...       </div>     </touch-ripple> </a> <style>  .mu-item-wrapper {     display: block;     color: inherit;     position: relative; } </style>

到此,相信大家對(duì)“怎么使用vue開發(fā)波紋點(diǎn)擊特效組件”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

vue
AI