自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

如何使用vue開發(fā)波紋點擊特效組件

開發(fā) 前端
最近在使用 vue2 做一個新的 material ui 庫,波紋點擊效果在 material design 中被多次使用到,于是決定把它封裝成一個公共的組件,使用時直接調(diào)用就好啦。

[[171739]]

最近在使用 vue2 做一個新的 material ui 庫,波紋點擊效果在 material design 中被多次使用到,于是決定把它封裝成一個公共的組件,使用時直接調(diào)用就好啦。

開發(fā)之前的思考

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

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

  1. circleRipple.vue 波紋擴(kuò)散組件,完成波紋擴(kuò)散的效果
  2. TouchRipple.vue 監(jiān)聽 mouse 和 touch 相關(guān)事件,控制 circleRipple 的顯示,位置。

circleRipple.vue

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

  1. <template> 
  2.   <transition name="mu-ripple"
  3.     <div class="mu-circle-ripple" :style="styles"></div> 
  4.   </transition> 
  5. </template> 
  6.  
  7. <script> 
  8. import {merge} from '../utils' 
  9. export default { 
  10.   props: { 
  11.     mergeStyle: { 
  12.       type: Object, 
  13.       default () { 
  14.         return {} 
  15.       } 
  16.     }, 
  17.     color: { 
  18.       type: String, 
  19.       default'' 
  20.     }, 
  21.     opacity: { 
  22.       type: Number 
  23.     } 
  24.   }, 
  25.   computed: { 
  26.     styles () { 
  27.       return merge({}, {color: this.color, opacity: this.opacity}, this.mergeStyle) 
  28.     } 
  29.   } 
  30. </script> 
  31.  
  32. <style lang="less"
  33. @import "../styles/import.less"
  34. .mu-circle-ripple{ 
  35.   position: absolute
  36.   width: 100%; 
  37.   height: 100%; 
  38.   left: 0; 
  39.   top: 0; 
  40.   pointer-events: none; 
  41.   user-select: none; 
  42.   border-radius: 50%; 
  43.   background-color: currentColor; 
  44.   background-clip: padding-box; 
  45.   opacity: 0.1; 
  46.  
  47. .mu-ripple-enter-active, .mu-ripple-leave-active{ 
  48.   transition: transform 1s @easeOutFunction, opacity 2s @easeOutFunction; 
  49.  
  50. .mu-ripple-enter { 
  51.   transform: scale(0); 
  52.  
  53. .mu-ripple-leave-active{ 
  54.   opacity: 0 !important; 
  55. </style> 

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

TouchRipple.vue

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

  1. 監(jiān)聽 mouse 和 touch 相關(guān)事件, 控制 circleRipple 的顯示。
  2. 通過點擊事件 event 對象, 計算出 circleRipple 的大小和位置
  3. 如果頻繁點擊可能出現(xiàn)多個 circleRipple

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

  1. <template> 
  2.   <!--最外層用div包裹--> 
  3.   <div @mousedown="handleMouseDown" @mouseup="end()" @mouseleave="end()" @touchstart="handleTouchStart"  @touchend="end()" @touchcancel="end()"> 
  4.     <!--外層包裹防止波紋溢出--> 
  5.     <div :style="style" ref="holder"> 
  6.       <!--多個波紋用 v-for 控制--> 
  7.       <circle-ripple :key="ripple.key" :color="ripple.color" :opacity="ripple.opacity" :merge-style="ripple.style" v-for="ripple in ripples"></circle-ripple> 
  8.     </div> 
  9.     <!--利用slot分發(fā)實際內(nèi)容--> 
  10.     <slot></slot> 
  11.   </div> 
  12. </template> 
  13.  
  14. <script> 
  15. import circleRipple from './circleRipple' 
  16. export default { 
  17.   props: { 
  18.     // 是否從中間擴(kuò)散,設(shè)為false會從點擊處擴(kuò)散 
  19.     centerRipple: { 
  20.       type: Boolean, 
  21.       default: true 
  22.     }, 
  23.     // 外層包裹的樣式 
  24.     style: { 
  25.       type: Object, 
  26.       default () { 
  27.         return { 
  28.           height: '100%', 
  29.           width: '100%', 
  30.           position: 'absolute', 
  31.           top: '0', 
  32.           left: '0', 
  33.           overflow: 'hidden' 
  34.         } 
  35.       } 
  36.     }, 
  37.     // 波紋顏色 
  38.     color: { 
  39.       type: String, 
  40.       default: '' 
  41.     }, 
  42.     // 波紋透明度 
  43.     opacity: { 
  44.       type: Number 
  45.     } 
  46.   }, 
  47.   data () { 
  48.     return { 
  49.       nextKey: 0, // 記錄下一個波紋元素的key值, 相當(dāng)于uuid,不設(shè)置的話會使動畫失效 
  50.       ripples: [] // 波紋元素參數(shù)數(shù)組 
  51.     } 
  52.   }, 
  53.   mounted () { 
  54.     this.ignoreNextMouseDown = false // 防止既有 touch 又有 mouse點擊的情況 
  55.   }, 
  56.   methods: { 
  57.     start (event, isRippleTouchGenerated) { 
  58.       // 開始波紋效果 
  59.     }, 
  60.     end () { 
  61.       // 結(jié)束波紋效果 
  62.     }, 
  63.     handleMouseDown (event) { 
  64.       // 監(jiān)聽 鼠標(biāo)單擊 
  65.     }, 
  66.     handleTouchStart (event) { 
  67.       // 監(jiān)聽 touchstart 方法 
  68.     } 
  69.   }, 
  70.   components: { 
  71.     'circle-ripple': circleRipple 
  72.   } 
  73. </script> 

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

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

  1.   // isRippleTouchGenerated 是否是touch 事件開始的 
  2.   start (event, isRippleTouchGenerated) { 
  3.     // 過濾 touchstart 和 mousedown 同時存在的情況 
  4.     if (this.ignoreNextMouseDown && !isRippleTouchGenerated) { 
  5.       this.ignoreNextMouseDown = false 
  6.       return 
  7.     } 
  8.      
  9.     // 添加一個 波紋元素組件 
  10.     this.ripples.push({ 
  11.       key: this.nextKey++,  
  12.       color: this.color, 
  13.       opacity: this.opacity, 
  14.       style: this.centerRipple ? {} : this.getRippleStyle(event) // 不是從中心擴(kuò)展的需要計算波紋元素的位置 
  15.     }) 
  16.     this.ignoreNextMouseDown = isRippleTouchGenerated 
  17.  }, 
  18.  end () { 
  19.    if (this.ripples.length === 0) return 
  20.    this.ripples.splice(0, 1) // 刪除一個波紋元素 
  21.    this.stopListeningForScrollAbort() // 結(jié)束 touch 滾動的處理 
  22.   } 

 因為 vue2 基于 Virtual DOM 的, 所以如果沒有 key 在增加一個元素又同時刪除一個元素的時候,dom tree并沒有發(fā)生變化,是不會產(chǎn)生動畫效果的。

監(jiān)聽 mousedown 和 touchstart

mousedown 和 touchstart 處理上會有所不同,但都是用來啟動波紋效果的, touch涉及到多點點擊的問題,我們一般取***個即可。 

  1.     handleMouseDown (event) { 
  2.       // 只監(jiān)聽鼠標(biāo)左鍵的點擊 
  3.       if (event.button === 0) { 
  4.         this.start(event, false
  5.       } 
  6.     }, 
  7.     handleTouchStart (event) { 
  8.       event.stopPropagation() // 防止多個波紋點擊組件嵌套 
  9.       if (event.touches) { 
  10.         this.startListeningForScrollAbort(event) // 啟動 touchmove 觸發(fā)滾動處理 
  11.         this.startTime = Date.now() 
  12.       } 
  13.       this.start(event.touches[0], true
  14.     } 

 touchmove控制

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

  1.   // touchmove 結(jié)束波紋控制 
  2.   stopListeningForScrollAbort () { 
  3.     if (!this.handleMove) this.handleMove = this.handleTouchMove.bind(this) 
  4.     document.body.removeEventListener('touchmove', this.handleMove, false
  5.   }, 
  6.   startListeningForScrollAbort (event) { 
  7.     this.firstTouchY = event.touches[0].clientY 
  8.     this.firstTouchX = event.touches[0].clientX 
  9.     document.body.addEventListener('touchmove', this.handleMove, false
  10.   }, 
  11.   handleTouchMove (event) { 
  12.     const timeSinceStart = Math.abs(Date.now() - this.startTime) 
  13.     if (timeSinceStart > 300) { 
  14.       this.stopListeningForScrollAbort() 
  15.       return 
  16.     } 
  17.     const deltaY = Math.abs(event.touches[0].clientY - this.firstTouchY) 
  18.     const deltaX = Math.abs(event.touches[0].clientX - this.firstTouchX) 
  19.     // 滑動范圍在 > 6px 結(jié)束波紋點擊效果 
  20.     if (deltaY > 6 || deltaX > 6) this.end() 
  21.   } 

 計算波紋的位置和大小

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

  1.   getRippleStyle (event) { 
  2.     let holder = this.$refs.holder 
  3.     //  這個方法返回一個矩形對象,包含四個屬性:left、top、right和bottom。分別表示元素各邊與頁面上邊和左邊的距離。 
  4.     let rect = holder.getBoundingClientRect()  
  5.     // 獲取點擊點的位置 
  6.     let x = event.offsetX 
  7.     let y 
  8.     if (x !== undefined) { 
  9.       y = event.offsetY 
  10.     } else { 
  11.       x = event.clientX - rect.left 
  12.       y = event.clientY - rect.top 
  13.     } 
  14.     // 獲取***邊長 
  15.     let max 
  16.     if (rect.width === rect.height) { 
  17.       max = rect.width * 1.412 
  18.     } else { 
  19.       max = Math.sqrt( 
  20.         (rect.width * rect.width) + (rect.height * rect.height) 
  21.       ) 
  22.     } 
  23.     const dim = (max * 2) + 'px' 
  24.     return { 
  25.       width: dim, 
  26.       height: dim, 
  27.       // 通過margin控制波紋中心點和點擊點一致 
  28.       'margin-left': -max + x + 'px', 
  29.       'margin-top': -max + y + 'px' 
  30.     } 
  31.   } 

 使用

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

  1. // listItem.vue 
  2. <a :href="href" @mouseenter="hover = true" @mouseleave="hover = false" @touchend="hover = false" 
  3.     @touchcancel="hover = false" class="mu-item-wrapper" :class="{'hover': hover}"
  4.     <touch-ripple class="mu-item" :class="{'mu-item-link': link}" :center-ripple="false"
  5.       <div class="mu-item-media"
  6.         <slot name="media"></slot> 
  7.       </div> 
  8.       <div class="mu-item-content"
  9.         // ... 
  10.       </div> 
  11.     </touch-ripple> 
  12. </a> 
  13. <style> 
  14.  
  15. .mu-item-wrapper { 
  16.     display: block; 
  17.     color: inherit; 
  18.     position: relative
  19. </style> 

 ***

到這點擊波紋組件就開發(fā)完了, 這些代碼借鑒了 keen-ui 和 material-ui 的實現(xiàn)方式。

責(zé)任編輯:龐桂玉 來源: segmentfault
相關(guān)推薦

2021-10-26 15:22:52

鴻蒙HarmonyOS應(yīng)用

2023-10-30 08:35:50

水波紋效果vue

2024-11-06 10:16:22

2023-12-20 17:28:48

水波紋ArkUI動畫開發(fā)

2015-07-16 15:20:58

DockerDjango

2010-07-30 13:52:17

Flex組件

2022-02-08 15:55:00

Vue組件庫Vue Demi

2010-08-05 09:54:56

Flex特效

2024-05-31 08:43:31

2021-08-01 07:58:58

Vue 加載組件

2010-08-03 15:44:08

FlexBuilder

2016-09-26 15:14:28

Javascript前端vue

2022-09-20 12:21:25

Vue2Vue3$attrs

2024-11-15 10:03:43

應(yīng)用模板Vue

2023-12-11 17:15:05

應(yīng)用開發(fā)波紋進(jìn)度條ArkUI

2020-02-21 11:08:24

瀏覽器HTML設(shè)計

2020-04-24 20:05:16

VueAxios前端

2010-08-12 13:39:46

Flex組件

2023-04-27 11:07:24

Setup語法糖Vue3

2023-03-29 08:52:58

視覺Vue組件庫
點贊
收藏

51CTO技術(shù)棧公眾號