vue3實(shí)現(xiàn)對(duì)自定義組件自由拖動(dòng)效果
在數(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ù)制方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-11-11
利用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跨行顯示(非腳手架),本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-09-09
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)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04
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

