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

vue3實(shí)現(xiàn)對(duì)自定義組件自由拖動(dòng)效果

 更新時(shí)間:2025年04月28日 12:02:18   作者:℡52Hz★  
在數(shù)據(jù)可視化看板開(kāi)發(fā)中,組件的自由拖拽功能能極大提升交互體驗(yàn),本文將基于Vue3生態(tài),從零開(kāi)始解析如何實(shí)現(xiàn)一個(gè)支持自由拖拽的容器組件,感興趣的朋友一起看看吧

在數(shù)據(jù)可視化看板開(kāi)發(fā)中,組件的自由拖拽功能能極大提升交互體驗(yàn)。本文將基于Vue3生態(tài),從零開(kāi)始解析如何實(shí)現(xiàn)一個(gè)支持自由拖拽的容器組件。

一、核心實(shí)現(xiàn)原理

1.組件定位基礎(chǔ)

使用position: fixed實(shí)現(xiàn)絕對(duì)定位,通過(guò)動(dòng)態(tài)樣式綁定left/top控制位置,@mousedown事件來(lái)觸發(fā)拖曳效果。

<template>
  <div class="left-admin" @mousedown="startDrag" :style="{ left: panelPosition.x + 'px', top: panelPosition.y + 'px' }">
  </div>
</template>
<style lang="less" scoped>
.left-admin {
  position: fixed;
  cursor: move;
}
</style>

2.拖曳過(guò)程實(shí)現(xiàn)

(1)定義初始屏幕寬度、位置及判斷條件

const panelWidth = 443//初始寬度
const panelPosition = ref({//初始位置
  x: 8,
  y: 80
  // x: 0.5,
  // y: 0.5
})
let isDragging = false//是否拖拽中
let startX = 0//開(kāi)始X坐標(biāo)
let startY = 0//開(kāi)始Y坐標(biāo)
let initialX = 0//初始X坐標(biāo)
let initialY = 0//初始Y坐標(biāo)

(2)鼠標(biāo)按下事件

當(dāng)鼠標(biāo)進(jìn)行拖動(dòng)時(shí),獲取獲取鼠標(biāo)的X、Y坐標(biāo),并且綁定鼠標(biāo)的移動(dòng)和釋放事件

// 鼠標(biāo)按下事件
const startDrag = e => {
  isDragging = true
  startX = e.clientX//獲取鼠標(biāo)X坐標(biāo)
  startY = e.clientY//獲取鼠標(biāo)Y坐標(biāo)
  initialX = panelPosition.value.x//獲取初始X坐標(biāo)
  initialY = panelPosition.value.y//獲取初始Y坐標(biāo)
  document.addEventListener('mousemove', onDrag)//綁定鼠標(biāo)移動(dòng)事件  
  document.addEventListener('mouseup', stopDrag)//綁定鼠標(biāo)釋放事件
}

(3)鼠標(biāo)移動(dòng)事件

// 鼠標(biāo)移動(dòng)事件
const onDrag = e => {
  // 防止拖拽過(guò)程中鼠標(biāo)點(diǎn)擊導(dǎo)致的頁(yè)面閃爍
  if (!isDragging) return
  //計(jì)算移動(dòng)距離
  const dx = e.clientX - startX
  const dy = e.clientY - startY
  // 添加邊界限制
  let newX = initialX + dx
  let newY = initialY + dy
  newX = Math.max(newX, 8)//最小值
  newX = Math.min(newX, window.innerWidth - panelWidth - 8)//最大值
  panelPosition.value = {//更新位置數(shù)據(jù)
    x: newX,
    y: newY
  }
}

(4)鼠標(biāo)釋放事件

// 鼠標(biāo)釋放事件
const stopDrag = () => {
  isDragging = false
  document.removeEventListener('mousemove', onDrag)// 鼠標(biāo)移動(dòng)事件
  document.removeEventListener('mouseup', stopDrag)// 鼠標(biāo)釋放事件
}

(5)組件卸載時(shí)清理事件

// 組件卸載時(shí)清理事件
onBeforeUnmount(() => {
  document.removeEventListener('mousemove', onDrag)
  document.removeEventListener('mouseup', stopDrag)
})

二、全部代碼

以下代碼是實(shí)際項(xiàng)目中使用到的,重要的過(guò)程代碼對(duì)應(yīng)以上核心實(shí)現(xiàn)原理這里,可根據(jù)自行項(xiàng)目需要進(jìn)行摘取

<template>
  <div class="left-admin" @mousedown="startDrag" :style="{ left: panelPosition.x + 'px', top: panelPosition.y + 'px' }">
    <!-- <div class="top-title">
      <h1>各行政區(qū)檢修工單統(tǒng)計(jì)(本月度)</h1>
    </div> -->
    <div class="admin-top">
      <h1>{{ adminTitle }}</h1>
      <img src="@/assets/images/page/close.svg" class="close-btn" @click="closeLeftAdmin" />
    </div>
    <div class="chart">
      <radarChart :indicatorData="indicatorData" :radarData="radarData" :chartColor="props.chartColor" />
    </div>
  </div>
</template>
<script setup>
import { onMounted, ref, onBeforeUnmount, getCurrentInstance } from 'vue'
import radarChart from '@/components/chart/radar-chart.vue'
import { getDevRepairCount } from '@/api/home/home-left.js'
const props = defineProps(['chartColor'])
const emit = defineEmits(['closeLeftAdmin'])
const context = getCurrentInstance()?.appContext.config.globalProperties
const dayjs = context?.$dayjs
const adminTitle = ref('各行政區(qū)檢修工單統(tǒng)計(jì)(本月度)')
const indicatorData = ref([
  // { name: '張家港市' },
  // { name: '吳江區(qū)' },
  // { name: '吳中區(qū)' },
  // { name: '姑蘇區(qū)' },
  // { name: '虎丘區(qū)' },
  // { name: '相城區(qū)' },
  // { name: '昆山市' },
  // { name: '太倉(cāng)市' },
  // { name: '常熟市' }
])
const radarData = ref([
  // { value: [1200, 3000, 4000, 1000, 30000, 3000, 35000, 50000, 18000] }
  // { name: '已開(kāi)工', value: [5200, 2000, 30000, 2000, 10000, 18000] },
  // { name: '未開(kāi)工', value: [3200, 2000, 5000, 2000, 10000, 18000] },
  // { name: '已竣工', value: [2200, 2000, 5000, 2000, 10000, 18000] },
  // { name: '當(dāng)值開(kāi)竣工', value: [4200, 3000, 20000, 35000, 50000, 18000] },
  // { name: '改期和延期', value: [5000, 14000, 28000, 26000, 42000, 21000] }
])
const closeLeftAdmin = () => {
  emit('closeLeftAdmin')
}
// 新增狀態(tài)
// const panelPosition = ref({ x: 8, y: 80 })
const panelWidth = 443
const panelPosition = ref({
  x: 8,
  y: 80
  // x: 0.5,
  // y: 0.5
})
let isDragging = false
let startX = 0
let startY = 0
let initialX = 0
let initialY = 0
// 鼠標(biāo)按下事件
const startDrag = e => {
  isDragging = true
  startX = e.clientX
  startY = e.clientY
  initialX = panelPosition.value.x
  initialY = panelPosition.value.y
  document.addEventListener('mousemove', onDrag)
  document.addEventListener('mouseup', stopDrag)
}
// 鼠標(biāo)移動(dòng)事件
const onDrag = e => {
  if (!isDragging) return
  const dx = e.clientX - startX
  const dy = e.clientY - startY
  let newX = initialX + dx
  let newY = initialY + dy
  newX = Math.max(newX, 8)
  newX = Math.min(newX, window.innerWidth - panelWidth - 8)
  panelPosition.value = {
    x: newX,
    y: newY
  }
}
// 鼠標(biāo)釋放事件
const stopDrag = () => {
  isDragging = false
  document.removeEventListener('mousemove', onDrag)
  document.removeEventListener('mouseup', stopDrag)
}
// 組件卸載時(shí)清理事件
onBeforeUnmount(() => {
  document.removeEventListener('mousemove', onDrag)
  document.removeEventListener('mouseup', stopDrag)
})
</script>
<style lang="less" scoped>
.left-admin {
  position: fixed;
  cursor: move;
}
</style>

到此這篇關(guān)于vue3實(shí)現(xiàn)對(duì)自定義組件自由拖動(dòng)效果的文章就介紹到這了,更多相關(guān)vue自定義組件自由拖動(dòng)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Vue 實(shí)現(xiàn)復(fù)制功能,不需要任何結(jié)構(gòu)內(nèi)容直接復(fù)制方式

    Vue 實(shí)現(xiàn)復(fù)制功能,不需要任何結(jié)構(gòu)內(nèi)容直接復(fù)制方式

    今天小編就為大家分享一篇Vue 實(shí)現(xiàn)復(fù)制功能,不需要任何結(jié)構(gòu)內(nèi)容直接復(fù)制方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-11-11
  • 解決vue同一slot在組件中渲染多次的問(wèn)題

    解決vue同一slot在組件中渲染多次的問(wèn)題

    今天小編就為大家分享一篇解決vue同一slot在組件中渲染多次的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-09-09
  • npm?run?dev失敗的簡(jiǎn)單解決辦法

    npm?run?dev失敗的簡(jiǎn)單解決辦法

    最近工作中遇到了npm?run?dev報(bào)錯(cuò)這個(gè)問(wèn)題,通過(guò)查找相關(guān)資料最終解決了,所以下面這篇文章主要給大家介紹了關(guān)于npm?run?dev失敗的詳細(xì)解決辦法,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-07-07
  • 淺談Vue.js組件(二)

    淺談Vue.js組件(二)

    這篇文章主要介紹了Vue.js組件,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • 利用vue+elementUI實(shí)現(xiàn)部分引入組件的方法詳解

    利用vue+elementUI實(shí)現(xiàn)部分引入組件的方法詳解

    這篇文章主要給大家介紹了關(guān)于利用vue+elementUI實(shí)現(xiàn)部分引入組件的相關(guān)資料,以及介紹了vue引入elementUI報(bào)錯(cuò)的解決方法,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-11-11
  • Vue3+Element?Plus實(shí)現(xiàn)el-table跨行顯示(非腳手架)

    Vue3+Element?Plus實(shí)現(xiàn)el-table跨行顯示(非腳手架)

    這篇文章主要介紹了Vue3+Element Plus實(shí)現(xiàn)el-table跨行顯示(非腳手架),本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-09-09
  • vue+axios+java實(shí)現(xiàn)文件上傳功能

    vue+axios+java實(shí)現(xiàn)文件上傳功能

    這篇文章主要為大家詳細(xì)介紹了vue+axios+java實(shí)現(xiàn)文件上傳功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • vue中的input框點(diǎn)擊后不聚焦問(wèn)題

    vue中的input框點(diǎn)擊后不聚焦問(wèn)題

    這篇文章主要介紹了vue中的input框點(diǎn)擊后不聚焦問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-04-04
  • 分分鐘玩轉(zhuǎn)Vue.js組件(二)

    分分鐘玩轉(zhuǎn)Vue.js組件(二)

    這篇文章教大家如何分分鐘玩轉(zhuǎn)Vue.js組件,完善了vue.js組件的學(xué)習(xí)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-03-03
  • node.js開(kāi)發(fā)輔助工具nodemon安裝與配置詳解

    node.js開(kāi)發(fā)輔助工具nodemon安裝與配置詳解

    node.js代碼修改后,需要重新啟動(dòng) Express 應(yīng)用,所做的修改才能生效。若之后的每次代碼修改都要重復(fù)這樣的操作,勢(shì)必會(huì)影響開(kāi)發(fā)效率,本文將詳細(xì)介紹Nodemon,它會(huì)監(jiān)測(cè)項(xiàng)目中的所有文件,一旦發(fā)現(xiàn)文件有改動(dòng),Nodemon 會(huì)自動(dòng)重啟應(yīng)用
    2020-02-02

最新評(píng)論

延庆县| 阿坝| 信丰县| 登封市| 安溪县| 咸阳市| 革吉县| 长兴县| 木里| 遵义市| 辽宁省| 南澳县| 舒兰市| 洞口县| 漳浦县| 杭锦旗| 咸宁市| 马公市| 长治市| 高台县| 瑞安市| 绿春县| 临泽县| 徐水县| 巫山县| 乃东县| 舟曲县| 邵阳市| 丹巴县| 莱芜市| 咸丰县| 崇明县| 呼伦贝尔市| 收藏| 华容县| 临城县| 平潭县| 常山县| 禹州市| 太原市| 大方县|