vue實(shí)現(xiàn)水波漣漪效果的點(diǎn)擊反饋指令
水波效果
當(dāng)用戶點(diǎn)擊時(shí),會(huì)以點(diǎn)擊中心為圓心產(chǎn)生一個(gè)水波擴(kuò)散的漣漪效果,適用各個(gè)場(chǎng)景,美觀又不浮夸,關(guān)鍵是可以給用戶帶來(lái)很直觀的反饋。
來(lái)看實(shí)現(xiàn)
首先這里基于Vue3自定義指令進(jìn)行封裝,Vue3的自定義指令跟Vue2相比變動(dòng)不是很大,。我們的目標(biāo)是完成一個(gè)水波指令的基本原型,這里循序漸進(jìn)展開(kāi)。
定制一個(gè)水波紋默認(rèn)樣式
水波紋實(shí)際上就是通過(guò)用戶點(diǎn)擊的位置生成一個(gè)小圓圈,并且尺寸逐漸擴(kuò)大到整個(gè)被點(diǎn)擊元素的一個(gè)過(guò)程,所以這里先制定一個(gè)水波基本的樣式,并設(shè)置好過(guò)度動(dòng)畫(huà),過(guò)度動(dòng)畫(huà)應(yīng)該是一個(gè)先慢后快的一個(gè)過(guò)程,這里使用貝塞爾曲線定制
.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; }
計(jì)算水波紋的位置和直徑
如果確定了水波的直徑、創(chuàng)建時(shí)的(x,y)、過(guò)度動(dòng)畫(huà)結(jié)束時(shí)的(x,y),我們就可以通過(guò)transition去渲染水波動(dòng)畫(huà)了,創(chuàng)建時(shí)的(x,y)就是用戶點(diǎn)擊的位置,但是水波的直徑和過(guò)度動(dòng)畫(huà)結(jié)束時(shí)的(x,y)怎么計(jì)算呢?我們的元素都是矩形,不論用戶從元素的任意坐標(biāo)進(jìn)行點(diǎn)擊,以矩形斜邊作為直徑的圓都可以完美的覆蓋整個(gè)元素,斜邊的計(jì)算我們利用小學(xué)數(shù)學(xué)知識(shí)求兩邊平方和進(jìn)行開(kāi)方得到,下面是過(guò)度動(dòng)畫(huà)結(jié)束時(shí)的水波推演圖。
第一個(gè)箭頭: 期望得到的水波
第二個(gè)箭頭: 元素(0,0)點(diǎn)創(chuàng)建的水波
第三個(gè)箭頭: 元素(0,0)點(diǎn)創(chuàng)建的水波, 不帶圓角效果
我們可以發(fā)現(xiàn)通過(guò)元素(0,0)點(diǎn)創(chuàng)建的水波進(jìn)行一定偏移就可以得到我們想要的水波,由此我們可以推斷出
動(dòng)畫(huà)結(jié)束時(shí)的水波的尺寸 = 圓的斜邊
創(chuàng)建時(shí)的(x,y) = 用戶點(diǎn)擊的位置
過(guò)度動(dòng)畫(huà)結(jié)束時(shí)的(x,y) = 元素(0,0)點(diǎn)創(chuàng)建的水波進(jìn)行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 } }
鼠標(biāo)按下時(shí)創(chuàng)建水波
然后我們需要在鼠標(biāo)按下時(shí)創(chuàng)建水波,監(jiān)聽(tīng)鼠標(biāo)按下的事件,這里以pc端為例子,剛創(chuàng)建水波時(shí)使用transform縮小到0.3,這是作者嘗試過(guò)相對(duì)合適的創(chuàng)建大小, 然后修改transform觸發(fā)過(guò)度水波擴(kuò)散動(dòng)畫(huà),這里還加入了透明度的過(guò)度,可以使水波漣漪更有質(zhì)感。
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` // 記錄水波的創(chuàng)建時(shí)間 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) } }
鼠標(biāo)抬起時(shí)銷毀水波
當(dāng)鼠標(biāo)抬起時(shí),只需要找到這個(gè)生成的水波節(jié)點(diǎn)修改透明度,再等到透明度修改動(dòng)畫(huà)結(jié)束之后將水波紋節(jié)點(diǎn)移除即可
function removeRipple() { const container = this const ripples = container.querySelectorAll('.my-ripple') if (!ripples.length) { return } const lastRipple = ripples[ripples.length - 1] // 通過(guò)水波的創(chuàng)建時(shí)間計(jì)算出擴(kuò)散動(dòng)畫(huà)還需要執(zhí)行多久,確保每一個(gè)水波都完整的執(zhí)行了擴(kuò)散動(dòng)畫(huà) 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) } }
通過(guò)指令binding去擴(kuò)展你的水波選項(xiàng)
你還可以通過(guò)binding去擴(kuò)展你的指令,比如可以提供修改顏色,禁用狀態(tài)等等選項(xiàng),這里就不詳細(xì)展開(kāi)了。我們來(lái)看一下成果。
寫(xiě)在最后
到此為止我們就實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的ripple指令,在我們的組件庫(kù)中也有這樣的指令,所以更完善的版本可以去看我們的源碼。 先要感謝一下掘金社區(qū),已經(jīng)有一部分小伙伴開(kāi)始pr一些代碼到我們的倉(cāng)庫(kù)中來(lái),我們也很高興能和社區(qū)的小伙伴們?nèi)ヒ黄鹱鲞@樣一件事情,另外我們的組件庫(kù)團(tuán)隊(duì)一直在募集愛(ài)好者來(lái)參與貢獻(xiàn),有興趣的小伙伴歡迎加入討論,加入方式就是直接去倉(cāng)庫(kù)提issue留郵箱,我們會(huì)第一時(shí)間處理,有沒(méi)有興趣都希望為我們點(diǎn)點(diǎn)star,關(guān)注一下我們,社區(qū)小伙伴的支持和興趣是我們最大的動(dòng)力。
以上就是vue實(shí)現(xiàn)水波漣漪效果的點(diǎn)擊反饋指令的詳細(xì)內(nèi)容,更多關(guān)于vue 點(diǎn)擊反饋指令的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
vue 路由頁(yè)面之間實(shí)現(xiàn)用手指進(jìn)行滑動(dòng)的方法
下面小編就為大家分享一篇vue 路由頁(yè)面之間實(shí)現(xiàn)用手指進(jìn)行滑動(dòng)的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨跟隨小編過(guò)來(lái)看看吧2018-02-02Vue全局使用less樣式,組件使用全局樣式文件中定義的變量操作
這篇文章主要介紹了Vue全局使用less樣式,組件使用全局樣式文件中定義的變量操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-10-10vue進(jìn)入頁(yè)面時(shí)不在頂部,檢測(cè)滾動(dòng)返回頂部按鈕問(wèn)題及解決方法
這篇文章主要介紹了vue進(jìn)入頁(yè)面時(shí)不在頂部,檢測(cè)滾動(dòng)返回頂部按鈕問(wèn)題及解決方法,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-10-10vue-cli點(diǎn)擊實(shí)現(xiàn)全屏功能
這篇文章主要為大家詳細(xì)介紹了vue-cli點(diǎn)擊實(shí)現(xiàn)全屏功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-03-03Vue3組合式函數(shù)Composable實(shí)戰(zhàn)ref和unref使用
這篇文章主要為大家介紹了Vue3組合式函數(shù)Composable實(shí)戰(zhàn)ref和unref使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06動(dòng)態(tài)加載權(quán)限管理模塊中的Vue組件
本篇文章給大家詳細(xì)講解了如何在權(quán)限管理模塊中動(dòng)態(tài)的加載VUE組件的過(guò)程,有這方面需求的朋友跟著學(xué)習(xí)下吧。2018-01-01