最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

vue實(shí)現(xiàn)水波漣漪效果的點(diǎn)擊反饋指令

 更新時(shí)間:2021年05月31日 17:20:51   作者:耗子君QAQ  
鼠標(biāo)移入時(shí)的小手、鼠標(biāo)點(diǎn)擊時(shí)按鈕下壓彈起的動(dòng)畫(huà)、觸屏應(yīng)用點(diǎn)擊時(shí)的屏幕震動(dòng),這些效果也被統(tǒng)稱為點(diǎn)擊反饋,雖然看似是應(yīng)用中的細(xì)枝末節(jié),但是只要稍微投入一點(diǎn)點(diǎn)心思,帶來(lái)的用戶體驗(yà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)力。

倉(cāng)庫(kù)地址
文檔地址

以上就是vue實(shí)現(xiàn)水波漣漪效果的點(diǎn)擊反饋指令的詳細(xì)內(nèi)容,更多關(guān)于vue 點(diǎn)擊反饋指令的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 安裝node.js以及搭建vue項(xiàng)目過(guò)程中遇到的問(wèn)題詳解

    安裝node.js以及搭建vue項(xiàng)目過(guò)程中遇到的問(wèn)題詳解

    為了讓一些不太清楚搭建前端項(xiàng)目的小白,更快上手,下面這篇文章主要給大家介紹了關(guān)于安裝node.js以及搭建vue項(xiàng)目過(guò)程中遇到問(wèn)題的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-06-06
  • vue3動(dòng)態(tài)添加路由

    vue3動(dòng)態(tài)添加路由

    這篇文章主要介紹了vue3動(dòng)態(tài)添加路由,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-06-06
  • 基于Vue實(shí)現(xiàn)自定義組件的方式引入圖標(biāo)

    基于Vue實(shí)現(xiàn)自定義組件的方式引入圖標(biāo)

    在vue項(xiàng)目中我們經(jīng)常遇到圖標(biāo),下面這篇文章主要給大家介紹了關(guān)于如何基于Vue實(shí)現(xiàn)自定義組件的方式引入圖標(biāo)的相關(guān)資料,文章通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2021-07-07
  • vue基于mint-ui的城市選擇3級(jí)聯(lián)動(dòng)的示例

    vue基于mint-ui的城市選擇3級(jí)聯(lián)動(dòng)的示例

    本篇文章主要介紹了vue基于mint-ui的城市選擇3級(jí)聯(lián)動(dòng)的示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-10-10
  • vue3緩存頁(yè)面keep-alive及路由統(tǒng)一處理詳解

    vue3緩存頁(yè)面keep-alive及路由統(tǒng)一處理詳解

    當(dāng)我們不想每次跳轉(zhuǎn)路由都會(huì)重新加載頁(yè)面時(shí)(重新加載頁(yè)面很耗時(shí)),就可以考慮使用keep-alive緩存頁(yè)面了,這篇文章主要給大家介紹了關(guān)于vue3緩存頁(yè)面keep-alive及路由統(tǒng)一處理的相關(guān)資料,需要的朋友可以參考下
    2021-10-10
  • element如何初始化組件功能詳解

    element如何初始化組件功能詳解

    Element UI是一套基于Vue的桌面端組件庫(kù),封裝好了很多常用的UI組件,下面這篇文章主要給大家介紹了關(guān)于element如何初始化組件功能的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-12-12
  • vue項(xiàng)目本地開(kāi)發(fā)完成后部署到服務(wù)器后報(bào)404錯(cuò)誤解決方案

    vue項(xiàng)目本地開(kāi)發(fā)完成后部署到服務(wù)器后報(bào)404錯(cuò)誤解決方案

    很多時(shí)候我們發(fā)現(xiàn)辛辛苦苦寫(xiě)的VueJs應(yīng)用經(jīng)過(guò)打包后在自己本地搭建的服務(wù)器上測(cè)試沒(méi)有什么問(wèn)題,但真正放在服務(wù)器上后會(huì)發(fā)現(xiàn)或多或少的問(wèn)題,這篇文章主要給大家介紹了關(guān)于vue項(xiàng)目本地開(kāi)發(fā)完成后部署到服務(wù)器后報(bào)404錯(cuò)誤的解決方案,需要的朋友可以參考下
    2024-01-01
  • 解決vue中數(shù)據(jù)更新視圖不更新問(wèn)題this.$set()方法

    解決vue中數(shù)據(jù)更新視圖不更新問(wèn)題this.$set()方法

    這篇文章主要介紹了解決vue中數(shù)據(jù)更新視圖不更新問(wèn)題this.$set()方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • 實(shí)用的 vue tags 創(chuàng)建緩存導(dǎo)航的過(guò)程實(shí)現(xiàn)

    實(shí)用的 vue tags 創(chuàng)建緩存導(dǎo)航的過(guò)程實(shí)現(xiàn)

    這篇文章主要介紹了實(shí)用的 vue tags 創(chuàng)建緩存導(dǎo)航的過(guò)程實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • Vue從TodoList中學(xué)父子組件通信

    Vue從TodoList中學(xué)父子組件通信

    這篇文章主要介紹了Vue從TodoList中學(xué)父子組件通信,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2019-02-02

最新評(píng)論

商水县| 尼玛县| 南京市| 德令哈市| 武穴市| 富平县| 宜昌市| 巴楚县| 丹巴县| 邛崃市| 清丰县| 荥经县| 夹江县| 山丹县| 德江县| 湟源县| 娄烦县| 黔南| 会理县| 济宁市| 卓资县| 都兰县| 井陉县| 大邑县| 德阳市| 广安市| 大田县| 延长县| 大邑县| 酒泉市| 凌源市| 普兰店市| 新干县| 呼图壁县| 樟树市| 云林县| 霸州市| 西吉县| 高陵县| 城口县| 胶州市|