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)點創建的水波, 不帶圓角效果
我們可以發現通過元素(0,0)點創建的水波進行一定偏移就可以得到我們想要的水波,由此我們可以推斷出
動畫結束時的水波的尺寸 = 圓的斜邊
創建時的(x,y) = 用戶點擊的位置
過度動畫結束時的(x,y) = 元素(0,0)點創建的水波進行x和y的偏移得到
function computeRippleStyles(element, event) { const { top, left } = element.getBoundingClientRect() 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, y, centerX, centerY, 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.position = 'relative') container.appendChild(ripple) window.setTimeout(() => { ripple.style.transform = `translate(${centerX}px, ${centerY}px) scale3d(1, 1, 1)` ripple.style.opacity = `.25` }) } const VRipple = { mounted(el) { el.addEventListener('mousedown', createRipple) } }
鼠標抬起時銷毀水波
當鼠標抬起時,隻需要找到這個生成的水波節點修改透明度,再等到透明度修改動畫結束之後將水波紋節點移除即可
function removeRipple() { const container = this const ripples = container.querySelectorAll('.my-ripple') if (!ripples.length) { return } const lastRipple = ripples[ripples.length - 1] // 通過水波的創建時間計算出擴散動畫還需要執行多久,確保每一個水波都完整的執行瞭擴散動畫 const 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去擴展你的指令,比如可以提供修改顏色,禁用狀態等等選項,這裡就不詳細展開瞭。我們來看一下成果。
寫在最後
到此為止我們就實現瞭一個簡單的ripple指令,在我們的組件庫中也有這樣的指令,所以更完善的版本可以去看我們的源碼。 先要感謝一下掘金社區,已經有一部分小夥伴開始pr一些代碼到我們的倉庫中來,我們也很高興能和社區的小夥伴們去一起做這樣一件事情,另外我們的組件庫團隊一直在募集愛好者來參與貢獻,有興趣的小夥伴歡迎加入討論,加入方式就是直接去倉庫提issue留郵箱,我們會第一時間處理,有沒有興趣都希望為我們點點star,關註一下我們,社區小夥伴的支持和興趣是我們最大的動力。
倉庫地址
文檔地址
以上就是vue實現水波漣漪效果的點擊反饋指令的詳細內容,更多關於vue 點擊反饋指令的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- JavaScript 實現頁面滾動動畫
- vue實現移動端div拖動效果
- vue實現拖拽小圖標
- vue中引入mousewheel事件及兼容性處理方式
- JS屬性scrollTop clientHeight scrollHeight理解學習