封装v-drag

This commit is contained in:
xhf 2025-02-17 16:46:50 +08:00
parent 437738b211
commit 557f557857
3 changed files with 137 additions and 69 deletions

View File

@ -44,6 +44,7 @@ import VueDOMPurifyHTML from 'vue-dompurify-html' // 解决v-html 的安全隐
import VueDragResizeRotate from '@gausszhou/vue3-drag-resize-rotate'
import '@gausszhou/vue3-drag-resize-rotate/lib/bundle.esm.css'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
import { vDrag } from './utils/drag';
// 创建实例
const setupAll = async () => {
const app = createApp(App)
@ -67,7 +68,8 @@ const setupAll = async () => {
setupMountedFocus(app)
await router.isReady()
// 注册全局指令
app.directive('drag', vDrag);
app.use(VueDOMPurifyHTML)
app.use(VueDragResizeRotate)
app.mount('#app')

31
src/utils/drag.ts Normal file
View File

@ -0,0 +1,31 @@
// directives.js
export const vDrag = {
mounted(el) {
el.style.position = 'absolute';
let startX, startY, initialMouseX, initialMouseY;
const mousemove = (e) => {
const dx = e.clientX - initialMouseX;
const dy = e.clientY - initialMouseY;
el.style.top = `${startY + dy}px`;
el.style.left = `${startX + dx}px`;
};
const mouseup = () => {
document.removeEventListener('mousemove', mousemove);
document.removeEventListener('mouseup', mouseup);
};
el.addEventListener('mousedown', (e) => {
startX = el.offsetLeft;
startY = el.offsetTop;
initialMouseX = e.clientX;
initialMouseY = e.clientY;
document.addEventListener('mousemove', mousemove);
document.addEventListener('mouseup', mouseup);
e.preventDefault();
});
}
};

View File

@ -1,5 +1,5 @@
<template>
<div class="affix-container">
<div class="affix-container" :style="{ height: heightVal + 'px' }">
<el-affix target=".affix-container" :offset="80">
<div class="affix-container-top">
<el-scrollbar>
@ -28,14 +28,26 @@
</el-scrollbar>
</div>
</el-affix>
<div class="indexpage-container" v-if="imgUrl">
<div class="indexpage-container" v-if="imgUrl" v-drag>
<div class="indexpage-container-box">
<img :src="imgUrl" alt="" class="indexpage-container-box-img" />
<div class="indexpage-container-box-point">
<div class="line-box" v-for="(item, index) in lineList" :key="index" :style="{ left: item.left * radio + 'px', top: item.top * radio + 'px', width: item.distance * radio + 'px', height: item.height * radio + 'px', transform: 'rotate(' + item.angle + 'deg)', backgroundColor: item.color ,transformOrigin: 'left top'}">
</div>
<div class="indexpage-container-box-point">
<div
class="line-box"
v-for="(item, index) in lineList"
:key="index"
:style="{
left: item.left * radio + 'px',
top: item.top * radio + 'px',
width: item.distance * radio + 'px',
height: item.height * radio + 'px',
transform: 'rotate(' + item.angle + 'deg)',
backgroundColor: item.color,
transformOrigin: 'left top'
}"
>
</div>
<div
class="indexpage-container-box-point-item"
v-for="(item, index) in pointList"
@ -51,38 +63,48 @@
}"
>
<div v-if="item.type == 2" style="width: 100%; height: 100%">
<el-popover
placement="top-start"
trigger="hover"
width="auto"
>
<el-popover placement="top-start" trigger="hover" width="auto">
<template #reference>
<img :src="item.imgUrl" alt="" style="width: 100%; height: 100%" @dblclick="storeClick(item)"/>
<img
:src="item.imgUrl"
alt=""
style="width: 100%; height: 100%"
@dblclick="storeClick(item)"
/>
</template>
<div class="indexpage-container-box-point-item-inner-popover">
<div class="indexpage-container-box-point-item-inner-popover-item" style="margin-bottom: 8px;">
<div
class="indexpage-container-box-point-item-inner-popover-item"
style="margin-bottom: 8px"
>
<div class="indexpage-container-box-point-item-inner-popover-name">
库位名
库位名
</div>
<div class="indexpage-container-box-point-item-inner-popover-value">
{{ item.showData.locationNo || '' }}
</div>
</div>
<div class="indexpage-container-box-point-item-inner-popover-value">
{{ item.showData.locationNo || '' }}
</div>
</div>
<div class="indexpage-container-box-point-item-inner-popover-item" style="margin-bottom: 8px;">
<div
class="indexpage-container-box-point-item-inner-popover-item"
style="margin-bottom: 8px"
>
<div class="indexpage-container-box-point-item-inner-popover-name">
所属线库
所属线库
</div>
<div class="indexpage-container-box-point-item-inner-popover-value">
{{ item.showData.laneName || '' }}
</div>
</div>
<div class="indexpage-container-box-point-item-inner-popover-value">
{{ item.showData.laneName || '' }}
</div>
</div>
<div class="indexpage-container-box-point-item-inner-popover-item" style="margin-bottom: 8px;">
<div
class="indexpage-container-box-point-item-inner-popover-item"
style="margin-bottom: 8px"
>
<div class="indexpage-container-box-point-item-inner-popover-name">
所属区域
</div>
<div class="indexpage-container-box-point-item-inner-popover-value">
{{ item.showData.areaName || '' }}
</div>
所属区域
</div>
<div class="indexpage-container-box-point-item-inner-popover-value">
{{ item.showData.areaName || '' }}
</div>
</div>
<!-- <div class="indexpage-container-box-point-item-inner-popover-item" style="margin-bottom: 8px;">
<div class="indexpage-container-box-point-item-inner-popover-name">
@ -160,7 +182,7 @@ const getPositionMapListFun = async (positionMapId) => {
if (data && data.length > 0) {
data.forEach((item) => {
// console.log(JSON.parse(item.dataJson))
item.formattedData = item.dataJson ?JSON.parse(item.dataJson):''
item.formattedData = item.dataJson ? JSON.parse(item.dataJson) : ''
item.showData = item.dataJson ? JSON.parse(item.dataJson)[0] : null
item.imgUrl = formatteTypeImg(item.type)
})
@ -169,41 +191,46 @@ const getPositionMapListFun = async (positionMapId) => {
pointList.value = data
console.log(pointList.value)
let lineStyle = calculateDistanceAndAngle({
left: pointList.value[0].locationX,
top: pointList.value[0].locationY
}, {
left: pointList.value[1].locationX,
top: pointList.value[1].locationY
})
let lineStyle = calculateDistanceAndAngle(
{
left: pointList.value[0].locationX,
top: pointList.value[0].locationY
},
{
left: pointList.value[1].locationX,
top: pointList.value[1].locationY
}
)
console.log(lineStyle)
lineList.value = [{
...lineStyle,
color: '#1677ff',
height: 2,
}]
lineList.value = [
{
...lineStyle,
color: '#1677ff',
height: 2
}
]
}
const calculateDistanceAndAngle = (point1, point2) => {
//
const dx = point2.left - point1.left;
const dy = point2.top - point1.top;
//
const dx = point2.left - point1.left
const dy = point2.top - point1.top
// 使
const distance = Math.sqrt(dx * dx + dy * dy);
// 使
const distance = Math.sqrt(dx * dx + dy * dy)
// 线
const angleInRadians = Math.atan2(dy, dx);
// 线
const angleInRadians = Math.atan2(dy, dx)
//
const angleInDegrees = angleInRadians * (180 / Math.PI);
//
const angleInDegrees = angleInRadians * (180 / Math.PI)
return {
distance: distance,
angle: angleInDegrees,
left: point1.left,
top: point1.top
};
return {
distance: distance,
angle: angleInDegrees,
left: point1.left,
top: point1.top
}
}
const formatteTypeImg = (type) => {
@ -263,14 +290,14 @@ const getMapData = async (item) => {
})
imgUrl.value = data
computedRatio()
}
const heightVal = ref(0)
const radio = ref(1)
const computedRatio = () => {
nextTick(() => {
if (imgUrl.value) {
let width = getElementWidthByClass('indexpage-container')
getImageWidth(imgUrl.value).then((res) => {
getImageWidth(imgUrl.value,'width').then((res) => {
// console.log(res)
let ratioVal = width / res
radio.value = ratioVal
@ -280,16 +307,20 @@ const computedRatio = () => {
})
}
})
getImageWidth(imgUrl.value,'height').then((res) => {
console.log("高",res)
heightVal.value = res
})
// console.log(width)
}
})
}
const getImageWidth = (imageUrl) => {
const getImageWidth = (imageUrl,name) => {
return new Promise((resolve, reject) => {
const img = new Image()
img.onload = function () {
resolve(img.width)
resolve(img[name])
}
img.onerror = function () {
reject(new Error('图片加载失败'))
@ -320,6 +351,8 @@ onBeforeUnmount(() => {
<style lang="scss" scoped>
.affix-container {
width: 100%;
position: relative;
overflow: hidden;
}
.indexpage-container {
width: 100%;
@ -379,14 +412,16 @@ onBeforeUnmount(() => {
width: 100%;
height: auto;
}
.indexpage-container-box-point-item-inner-popover-item{
.indexpage-container-box-point-item-inner-popover-item {
display: flex;
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 14px;
color: #0D162A;
font-family:
PingFangSC,
PingFang SC;
font-weight: 400;
font-size: 14px;
color: #0d162a;
}
.line-box{
.line-box {
position: absolute;
}
</style>