亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專(zhuān)欄INFORMATION COLUMN

vue 開(kāi)發(fā)波紋點(diǎn)擊特效組件

chavesgu / 2994人閱讀

摘要:最近在使用做一個(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.vueTouchRipple.vue 各自實(shí)現(xiàn)不同的功能

circleRipple.vue 波紋擴(kuò)散組件,完成波紋擴(kuò)散的效果

TouchRipple.vue 監(jiān)聽(tīng) mousetouch 相關(guān)事件,控制 circleRipple 的顯示,位置。

circleRipple.vue

circleRipple 需要完成波紋擴(kuò)展的效果,而且可以從外部控制它的大小和位置, 所以利用 vuetransition 動(dòng)畫(huà)完成效果, 提供 mergeStylecolor 、opacity 參數(shù)來(lái)從外部控制它的樣式。實(shí)現(xiàn)代碼如下。





vue2 對(duì)于動(dòng)畫(huà)方面做了比較大的修改,除了把指令換成組件外,它還可以完成更復(fù)雜的動(dòng)畫(huà)效果,具體可以看這里 vue2 transition

TouchRipple.vue

TouchRipple 需要控制 circleRipple 的顯示。完成以下內(nèi)容:

監(jiān)聽(tīng) mousetouch 相關(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 和 touchstart

mousedown 和 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

相關(guān)文章

  • 構(gòu)建Vue.js組件:slider

    摘要:組件的使用場(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è)...

    zxhaaa 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<