亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

vue3 拖拽hooks(可兼容移動(dòng)端)和自定義指令拖拽的實(shí)現(xiàn)代碼

 更新時(shí)間:2024年01月25日 15:38:24   作者:暮冬十七  
這篇文章主要介紹了vue3 拖拽hooks(可兼容移動(dòng)端)和自定義指令拖拽的實(shí)現(xiàn)代碼,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考借鑒價(jià)值,需要的朋友參考下吧

具體目標(biāo)

1、拖拽功能完好使用
2、不入侵業(yè)務(wù)
3、邊界值比如不能拖拽出瀏覽器外

整體架構(gòu)流程

三步走
鼠標(biāo)按下:將鼠標(biāo)按下時(shí)的位置記錄并與被拖拽元素的左上角位置進(jìn)行比較,以計(jì)算出鼠標(biāo)按下點(diǎn)相對(duì)于被拖拽元素的偏移,
鼠標(biāo)移動(dòng):根據(jù)鼠標(biāo)指針的移動(dòng)來(lái)更新被拖拽元素的位置,確保元素跟隨鼠標(biāo)的移動(dòng)。
鼠標(biāo)抬起:移除事件

具體代碼實(shí)現(xiàn)

方案一 hooks寫(xiě)法

// 創(chuàng)建useDraggable.ts
export const useDraggable = (): Ref<HTMLDivElement | null> => {
  // 聲明一個(gè) ref,用于存儲(chǔ) div 元素的引用
  const divRef = ref<HTMLDivElement | null>(null)
  // 聲明一些變量,用于存儲(chǔ)鼠標(biāo)或觸摸位置以及拖拽狀態(tài)
  let offsetX = 0 // 鼠標(biāo)點(diǎn)擊或觸摸點(diǎn)距離 div 左側(cè)的偏移
  let offsetY = 0 // 鼠標(biāo)點(diǎn)擊或觸摸點(diǎn)距離 div 頂部的偏移
  let isDragging = false // 是否正在拖拽中
  // 禁用頁(yè)面滾動(dòng)的函數(shù)
  const disablePageScroll = () => {
    document.body.style.overflow = 'hidden'
  }
  // 啟用頁(yè)面滾動(dòng)的函數(shù)
  const enablePageScroll = () => {
    document.body.style.overflow = 'auto'
  }
  // 開(kāi)始拖拽,禁用頁(yè)面滾動(dòng)
  const startDragging = () => {
    isDragging = true
    disablePageScroll()
  }
  // 停止拖拽,啟用頁(yè)面滾動(dòng),并稍后重新啟用點(diǎn)擊事件
  const stopDragging = () => {
    isDragging = false
    enablePageScroll()
    setTimeout(() => {
      if (divRef.value) {
        divRef.value.style.pointerEvents = 'auto'
      }
    }, 100)
  }
  // 處理鼠標(biāo)移動(dòng)或觸摸移動(dòng)事件
  const handleMouseMove = (event: MouseEvent | TouchEvent) => {
    requestAnimationFrame(() => {
      if (isDragging && divRef.value) {
        const clientX = 'touches' in event ? event.touches[0].clientX : event.clientX
        const clientY = 'touches' in event ? event.touches[0].clientY : event.clientY
        const x = clientX - offsetX
        const y = clientY - offsetY
        // 阻止事件傳播,避免干擾正常滾動(dòng)
        event.stopPropagation()
        event.preventDefault()
        // 獲取瀏覽器窗口的最大可視區(qū)域?qū)挾群透叨?
        const maxX = window.innerWidth - (divRef.value.clientWidth || 0)
        const maxY = window.innerHeight - (divRef.value.clientHeight || 0)
        // 設(shè)置 div 的位置,確保不超出窗口范圍
        divRef.value.style.left = `${Math.min(maxX, Math.max(0, x))}px`
        divRef.value.style.top = `${Math.min(maxY, Math.max(0, y))}px`
        // 禁用 div 上的點(diǎn)擊事件,以避免拖拽時(shí)觸發(fā)點(diǎn)擊事件
        divRef.value.style.pointerEvents = 'none'
      }
    })
  }
  // 處理鼠標(biāo)松開(kāi)或觸摸結(jié)束事件
  const handleMouseUp = () => {
    // 停止拖拽,恢復(fù)點(diǎn)擊事件
    stopDragging()
    // 移除鼠標(biāo)移動(dòng)事件和觸摸移動(dòng)事件的監(jiān)聽(tīng)器
    document.removeEventListener('touchmove', handleMouseMove)
    document.removeEventListener('mousemove', handleMouseMove)
  }
  // 處理鼠標(biāo)按下或觸摸開(kāi)始事件
  const handleMouseDown = (event: MouseEvent | TouchEvent) => {
    if (!divRef.value) return
    // 獲取鼠標(biāo)點(diǎn)擊或觸摸點(diǎn)相對(duì)于 div 左側(cè)和頂部的偏移
    offsetX = 'touches' in event ? event.touches[0].clientX - divRef.value.offsetLeft : event.clientX - divRef.value.offsetLeft
    offsetY = 'touches' in event ? event.touches[0].clientY - divRef.value.offsetTop : event.clientY - divRef.value.offsetTop
    // 開(kāi)始拖拽,添加鼠標(biāo)移動(dòng)和觸摸移動(dòng)事件監(jiān)聽(tīng)器
    startDragging()
    document.addEventListener('mousemove', handleMouseMove, {
      passive: false, // 阻止默認(rèn)滾動(dòng)行為
    })
    document.addEventListener('touchmove', handleMouseMove, {
      passive: false, // 阻止默認(rèn)滾動(dòng)行為
    })
    // 添加鼠標(biāo)松開(kāi)和觸摸結(jié)束事件監(jiān)聽(tīng)器
    document.addEventListener('mouseup', handleMouseUp)
    document.addEventListener('touchend', handleMouseUp)
  }
  // 在組件掛載時(shí),添加鼠標(biāo)按下和觸摸開(kāi)始事件監(jiān)聽(tīng)器
  onMounted(() => {
    if (divRef.value) {
      divRef.value.addEventListener('mousedown', handleMouseDown)
      divRef.value.addEventListener('touchstart', handleMouseDown)
    }
  })
  // 在組件卸載時(shí),移除事件監(jiān)聽(tīng)器
  onUnmounted(() => {
    if (divRef.value) {
      divRef.value.removeEventListener('mousedown', handleMouseDown)
      divRef.value.removeEventListener('touchstart', handleMouseDown)
    }
    document.removeEventListener('mouseup', handleMouseUp)
    document.removeEventListener('touchend', handleMouseUp)
  })
  // 返回 div 元素的引用,可以在組件中使用該引用來(lái)創(chuàng)建可拖拽的元素
  return divRef
}

hooks的使用方法如下

<template>
  <div
    ref="draggableDiv"
    class="it-layout-aside"
  >古德古德~</div>
</template>
<script setup lang="tsx">
  import { useDraggable } from '~/hooks/useDraggable'
  const draggableDiv = useDraggable()
</script>
<style lang="stylus" scoped>
.it-layout-aside
  flexCenter()
  position fixed
  bottom 100px
  right 10px
  width 60px
  height 60px
  border-radius 50%
  background rgba(0,0,0,.5)
  opacity 0.8
  color #fff
  font-size 40px
  cursor move
  &:hover
    opacity 1
</style>

方案二 自定義指令寫(xiě)法

const vDraggable = {
  mounted(el: HTMLElement) {
    let offsetX = 0
    let offsetY = 0
    let isDragging = false
    el.addEventListener('mousedown', event => {
      isDragging = false
      offsetX = event.clientX - el.offsetLeft
      offsetY = event.clientY - el.offsetTop
      const handleMouseMove = (e: MouseEvent) => {
        if (!isDragging && (Math.abs(event.clientX - offsetX) > 5 || Math.abs(event.clientY - offsetY) > 5)) {
          isDragging = true
        }
        if (isDragging) {
          const x = e.clientX - offsetX
          const y = e.clientY - offsetY
          el.style.left = `${Math.min(window.innerWidth - el.clientWidth, Math.max(0, x))}px`
          el.style.top = `${Math.min(window.innerHeight - el.clientHeight, Math.max(0, y))}px`
          el.style.pointerEvents = 'none'
        }
      }
      const handleMouseUp = () => {
        // 設(shè)置拖動(dòng)狀態(tài)為false
        isDragging = false
        setTimeout(() => {
          el.style.pointerEvents = 'auto'
        }, 100)
        // 移除鼠標(biāo)移動(dòng)和松開(kāi)事件
        document.removeEventListener('mousemove', handleMouseMove)
        // eslint-disable-next-line @typescript-eslint/no-unused-vars
        document.removeEventListener('mouseup', handleMouseUp)
      }
    })
  },
}

自定義指令的方法使用如下

<template>
  <div
    v-draggable
    class="it-layout-aside"
  >你潮嘛~</div>
</template>
<style lang="stylus" scoped>
.it-layout-aside
  flexCenter()
  position fixed
  bottom 100px
  right 10px
  width 60px
  height 60px
  border-radius 50%
  background rgba(0,0,0,.5)
  opacity 0.8
  color #fff
  font-size 40px
  cursor move
  &:hover
    opacity 1
</style>

到此這篇關(guān)于vue3 拖拽hooks(可兼容移動(dòng)端)和自定義指令拖拽的文章就介紹到這了,更多相關(guān)vue3 拖拽hooks內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論