1. 程式人生 > 程式設計 >vue實現水波漣漪效果的點選反饋指令

vue實現水波漣漪效果的點選反饋指令

水波效果

當用戶點選時,會以點選中心為圓心產生一個水波擴散的漣漪效果,適用各個場景,美觀又不浮誇,關鍵是可以給使用者帶來很直觀的反饋。

vue實現水波漣漪效果的點選反饋指令

來看實現

首先這裡基於vue3自定義指令進行封裝,Vue3的自定義指令跟Vue2相比變動不是很大,。我們的目標是完成一個水波指令的基本原型,這裡循序漸進展開。

定製一個水波紋預設樣式

水波紋實際上就是通過使用者點選的位置生成一個小圓圈,並且尺寸逐漸擴大到整個被點選元素的一個過程,所以這裡先制定一個水波基本的樣式,並設定好過度動畫,過度動畫應該是一個先慢後快的一個過程,這裡使用貝塞爾曲線定製

.my-ripple {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 100;
  border-radius: 50%;
  background-color: currentColor;
  opacity: 0;
  transition: transform 0.2s cubic-bezier(0.68,0.01,0.62,0.6),opacity 0.08s linear;
  will-change: transform,opacity;
  pointer-events: none;
}

計算水波紋的位置和直徑

如果確定了水波的直徑、建立時的(x,y)、過度動畫結束時的(x,y),我們就可以通過transition去渲染水波動畫了,建立時的(x,y)就是使用者點選的位置,但是水波的直徑和過度動畫結束時的(x,y)怎麼計算呢?我們的元素都是矩形,不論使用者從元素的任意座標進行點選,以矩形斜邊作為直徑的圓都可以完美的覆蓋整個元素,斜邊的計算我們利用小學數學知識求兩邊平方和進行開方得到,下面是過度動畫結束時的水波推演圖。

第一個箭頭: 期望得到的水波
第二個箭頭: 元素(0,0)點建立的水波
第三個箭頭: 元素(0,0)點建立的水波,不帶圓角效果

vue實現水波漣漪效果的點選反饋指令

我們可以發現通過元素(0,0)點建立的水波進行一定偏移就可以得到我們想要的水波,由此我們可以推斷出

動畫結束時的水波的尺寸 = 圓的斜邊
建立時的(x,y) = 使用者點選的位置
過度動畫結束時的(x,y) = 元素(0,0)點建立的水波進行x和y的偏移得到

function computeRippleStyles(element,event) {
  const { top,left } = element.getBoundingChttp://www.cppcns.comlientRect()
  const { clientWidth,clientHeight } = element
  
  const radius = Math.sqrt(clientWidth ** 2 + clientHeight ** 2) / 2
  const size = radius * 2
  
  const localX = event.clientX - left
  const localY = event.clientY - top

  const centerX = (clientWidth - radius * 2) / 2
  const centerY = (clientHeight - radius * 2) / 2

  const x = localX - radius
  const y = localY - radius

  return { x,y,centerX,centerY,size }
}

滑鼠按下時建立水波

然後我們需要在滑鼠按下時建立水波,監聽滑鼠按下的事件,這裡以pc端為例子,剛建立水波時使用transform縮小到0.3,這是作者嘗試過相對合適的建立大小,然後修改transform觸發過度水波擴散動畫,這裡還加入了透明度的過度,可以使水波漣漪更有質感。

function createRipple(event) {
  const container = this
  const { x,size } = computeRippleStyles(container,event)
  const ripple = document.createElement('div')
  ripple.classList.add('my-ripple')
  ripple.style.opacity = `0`
  ripple.style.transform = `translate(${x}px,${y}px) scale3d(.3,.3,.3)`
  ripple.style.width = `${size}px`
  ripple.style.height = `${size}px`
  // 記錄水波的建立時間
  ripple.dataset.createdAt = String(performance.now())

  const { position } = window.getComputedStyle(container)
  container.style.overflow = 'hidden'
  position === 'static' && (this.style.positio程式設計客棧n = 'relative')

  container.appendChild(ripple)

  window.setTimeout(() => {
    ripple.style.transform = `程式設計客棧translate(${centerX}px,${centerY}px) scale3d(1,1,1)`
    ripple.style.opacity = `.25`
  })
}

const VRipplhttp://www.cppcns.come = {
  mounted(el) {
    el.addEventListener('mousedown',createRipple)
  }
}

vue實現水波漣漪效果的點選反饋指令

滑鼠抬起時銷燬水波

當滑鼠抬起時,只需要找到這個生成的水波節點修改透明度,再等到透明度修改動畫結束之後將水波紋節點移除即可

function removeRipple() {
  const container = this
  const ripples = container.querySelectorAll('.my-ripple')
  if (!ripples.length) {
    return
  }

  const lastRipple = ripples[ripples.length - 1]
  // 通過水波的建立時間計算出擴散動畫還需要執行多久,確保每一個水波都完整的執行了擴散動畫
  consthttp://www.cppcns.com delay = 300 - performance.now() + Number(lastRipple.dataset.createdAt)

  setTimeout(() => {
    lastRipple.style.opacity = `0`
    
    setTimeout(() => lastRipple.parentNode?.removeChild(lastRipple),300)
  },delay)
}

const VRipple = {
  mounted(el) {
    el.addEventListener('mousedown',createRipple)
    document.addEventListener('mouseup',removeRipple)
  },unmounted(el) {
    el.removeEventListener('mousedown',createRipple)
    document.removeEventListener('mouseup',removeRipple)
  }
}

通過指令binding去擴充套件你的水波選項

你還可以通過binding去擴充套件你的指令,比如可以提供修改顏色,禁用狀態等等選項,這裡就不詳細展開了。我們來看一下成果。

vue實現水波漣漪效果的點選反饋指令

寫在最後

到此為止我們就實現了一個簡單的ripple指令,在我們的元件庫中也有這樣的指令,所以更完善的版本可以去看我們的原始碼。 先要感謝一下掘金社群,已經有一部分小夥伴開始pr一些程式碼到我們的倉庫中來,我們也很高興能和社群的小夥伴們去一起做這樣一件事情,另外我們的元件庫團隊一直在募集愛好者來參與貢獻,有興趣的小夥伴歡迎加入討論,加入方式就是直接去倉庫提issue留郵箱,我們會第一時間處理,有沒有興趣都希望為我們點點star,關注一下我們,社群小夥伴的支援和興趣是我們最大的動力。

倉庫地址
文件地址

以上就是vue實現水波漣漪效果的點選反饋指令的詳細內容,更多關於vue 點選反饋指令的資料請關注我們其它相關文章!