摘要:最近在使用做一個(gè)新的庫(kù),波紋點(diǎn)擊效果在中被多次使用到,于是決定把它封裝成一個(gè)公共的組件,使用時(shí)直接調(diào)用就好啦。
最近在使用 vue2 做一個(gè)新的 material ui 庫(kù),波紋點(diǎn)擊效果在 material design 中被多次使用到,于是決定把它封裝成一個(gè)公共的組件,使用時(shí)直接調(diào)用就好啦。
開(kāi)發(fā)之前的思考常見(jiàn)的波紋點(diǎn)擊效果的實(shí)現(xiàn)方式是監(jiān)聽(tīng)元素的 mousedown 事件,在元素內(nèi)部創(chuàng)建一個(gè) 波紋元素 ,并調(diào)整元素的 transform: scale(0); 到 transform: scale(1);, 通過(guò)計(jì)算點(diǎn)擊的位置來(lái)設(shè)置 波紋元素 的大小和位置,以達(dá)到波紋擴(kuò)散的效果。
我將組件分為兩個(gè)部分, circleRipple.vue 和 TouchRipple.vue 各自實(shí)現(xiàn)不同的功能
circleRipple.vue 波紋擴(kuò)散組件,完成波紋擴(kuò)散的效果
TouchRipple.vue 監(jiān)聽(tīng) mouse 和 touch 相關(guān)事件,控制 circleRipple 的顯示,位置。
circleRipple.vuecircleRipple 需要完成波紋擴(kuò)展的效果,而且可以從外部控制它的大小和位置, 所以利用 vue 的 transition 動(dòng)畫(huà)完成效果, 提供 mergeStyle 、 color 、opacity 參數(shù)來(lái)從外部控制它的樣式。實(shí)現(xiàn)代碼如下。
TouchRipple.vuevue2 對(duì)于動(dòng)畫(huà)方面做了比較大的修改,除了把指令換成組件外,它還可以完成更復(fù)雜的動(dòng)畫(huà)效果,具體可以看這里 vue2 transition
TouchRipple 需要控制 circleRipple 的顯示。完成以下內(nèi)容:
監(jiān)聽(tīng) mouse 和 touch 相關(guān)事件, 控制 circleRipple 的顯示。
通過(guò)點(diǎn)擊事件 event 對(duì)象, 計(jì)算出 circleRipple 的大小和位置
如果頻繁點(diǎn)擊可能出現(xiàn)多個(gè) circleRipple
首先,基本模板 + 數(shù)據(jù)模型開(kāi)始和結(jié)束波紋效果
增加一個(gè)波紋元素只需要在 ripple 增加一個(gè) object 即可,不同的是當(dāng)需要從點(diǎn)擊處擴(kuò)展時(shí),需要計(jì)算一下波紋元素的大小和位置。
{ // isRippleTouchGenerated 是否是touch 事件開(kāi)始的 start (event, isRippleTouchGenerated) { // 過(guò)濾 touchstart 和 mousedown 同時(shí)存在的情況 if (this.ignoreNextMouseDown && !isRippleTouchGenerated) { this.ignoreNextMouseDown = false return } // 添加一個(gè) 波紋元素組件 this.ripples.push({ key: this.nextKey++, color: this.color, opacity: this.opacity, style: this.centerRipple ? {} : this.getRippleStyle(event) // 不是從中心擴(kuò)展的需要計(jì)算波紋元素的位置 }) this.ignoreNextMouseDown = isRippleTouchGenerated }, end () { if (this.ripples.length === 0) return this.ripples.splice(0, 1) // 刪除一個(gè)波紋元素 this.stopListeningForScrollAbort() // 結(jié)束 touch 滾動(dòng)的處理 } }
因?yàn)?vue2 基于 Virtual DOM 的, 所以如果沒(méi)有 key 在增加一個(gè)元素又同時(shí)刪除一個(gè)元素的時(shí)候,dom tree并沒(méi)有發(fā)生變化,是不會(huì)產(chǎn)生動(dòng)畫(huà)效果的。
監(jiān)聽(tīng) mousedown 和 touchstartmousedown 和 touchstart 處理上會(huì)有所不同,但都是用來(lái)啟動(dòng)波紋效果的, touch涉及到多點(diǎn)點(diǎn)擊的問(wèn)題,我們一般取第一個(gè)即可。
{ handleMouseDown (event) { // 只監(jiān)聽(tīng)鼠標(biāo)左鍵的點(diǎn)擊 if (event.button === 0) { this.start(event, false) } }, handleTouchStart (event) { event.stopPropagation() // 防止多個(gè)波紋點(diǎn)擊組件嵌套 if (event.touches) { this.startListeningForScrollAbort(event) // 啟動(dòng) touchmove 觸發(fā)滾動(dòng)處理 this.startTime = Date.now() } this.start(event.touches[0], true) } }touchmove控制
當(dāng)發(fā)生touchMove事件是需要判斷是否,移動(dòng)的距離和時(shí)間,然后結(jié)束小波紋點(diǎn)擊小姑
{ // touchmove 結(jié)束波紋控制 stopListeningForScrollAbort () { if (!this.handleMove) this.handleMove = this.handleTouchMove.bind(this) document.body.removeEventListener("touchmove", this.handleMove, false) }, startListeningForScrollAbort (event) { this.firstTouchY = event.touches[0].clientY this.firstTouchX = event.touches[0].clientX document.body.addEventListener("touchmove", this.handleMove, false) }, handleTouchMove (event) { const timeSinceStart = Math.abs(Date.now() - this.startTime) if (timeSinceStart > 300) { this.stopListeningForScrollAbort() return } const deltaY = Math.abs(event.touches[0].clientY - this.firstTouchY) const deltaX = Math.abs(event.touches[0].clientX - this.firstTouchX) // 滑動(dòng)范圍在 > 6px 結(jié)束波紋點(diǎn)擊效果 if (deltaY > 6 || deltaX > 6) this.end() } }計(jì)算波紋的位置和大小
需要從點(diǎn)擊處擴(kuò)散的波紋效果,需要計(jì)算波紋元素的大小和位置
{ getRippleStyle (event) { let holder = this.$refs.holder // 這個(gè)方法返回一個(gè)矩形對(duì)象,包含四個(gè)屬性:left、top、right和bottom。分別表示元素各邊與頁(yè)面上邊和左邊的距離。 let rect = holder.getBoundingClientRect() // 獲取點(diǎn)擊點(diǎn)的位置 let x = event.offsetX let y if (x !== undefined) { y = event.offsetY } else { x = event.clientX - rect.left y = event.clientY - rect.top } // 獲取最大邊長(zhǎng) let max if (rect.width === rect.height) { max = rect.width * 1.412 } else { max = Math.sqrt( (rect.width * rect.width) + (rect.height * rect.height) ) } const dim = (max * 2) + "px" return { width: dim, height: dim, // 通過(guò)margin控制波紋中心點(diǎn)和點(diǎn)擊點(diǎn)一致 "margin-left": -max + x + "px", "margin-top": -max + y + "px" } } }使用
由于 touchRipple 內(nèi)部都是 position:absolute 布局,使用時(shí),需要在外部加上 position:relative
// listItem.vue最后 // ...
到這點(diǎn)擊波紋組件就開(kāi)發(fā)完了, 這些代碼借鑒了 keen-ui 和 material-ui 的實(shí)現(xiàn)方式。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/80395.html
摘要:組件的使用場(chǎng)景很多,主要為圖片的展示。一個(gè)主要由頂層容器和每一幀的組成。更多關(guān)于由于支持多個(gè)可用戶(hù)自定義的,所以需要在中聲明這些支持的自定義屬性,以便在組件聲明時(shí)使用上一幀下一幀導(dǎo)航自動(dòng)播放播放效果導(dǎo)航位置滑動(dòng)特效組件支持兩種特效和。 Slider組件的使用場(chǎng)景很多,主要為圖片的展示。一個(gè)slider主要由頂層容器和每一幀的slide組成。下面通過(guò)一個(gè)例子嘗試基于Vue.js去構(gòu)建一個(gè)...
閱讀 775·2021-11-22 13:54
閱讀 3183·2021-09-26 10:16
閱讀 3606·2021-09-08 09:35
閱讀 1643·2019-08-30 15:55
閱讀 3488·2019-08-30 15:54
閱讀 2144·2019-08-30 10:57
閱讀 551·2019-08-29 16:25
閱讀 935·2019-08-29 16:15