vue3
安装vue-draggable-resizable
详细信息:https://blog.csdn.net/yrqlyq/article/details/124843770
组件
<script lang="ts" setup>
import VueDraggableResizable from "vue3-draggable-resizable"
// import "vue3-draggable-resizable/dist/Vue3DraggableResizable.css"
import { ref, watchEffect } from "vue"
const draggingId = ref()
const emit = defineEmits(["tungInfo"])
const props = defineProps({
imgUrl: {
type: String,
default: ""
},
// 图标数组
list: {
type: Array,
default: () => []
},
// 组件对应字段
objName: {
type: Object,
default: () => {}
}
})
const dragStart = (id: number | string) => {
draggingId.value = id
console.log("draggingId", draggingId.value)
}
const onDragEnd = (e: { x: number; y: number }) => {
const item = props.list.find(
(i: any) => i[props.objName.id] === draggingId.value
)
item[props.objName.x] = e.x
item[props.objName.y] = e.y
emit("tungInfo", item)
}
</script>
<template>
<div>
<div
class="bg-img"
:style="'background:url(' + imgUrl + ');backgroundSize:100% 100%'"
>
<VueDraggableResizable
v-for="item in list"
:key="item[objName.id]"
:onDragStart="() => dragStart(item[objName.id])"
:x="item[objName.x]"
:y="item[objName.y]"
:w="40"
:h="30"
:resizable="false"
:parent="true"
@drag-end="onDragEnd"
>
<div class="icon">{{ item[objName.name] }}</div>
</VueDraggableResizable>
</div>
</div>
</template>
<style lang="scss" scoped>
.bg-img {
width: 800px;
height: 500px;
position: relative;
.icon {
display: inline-block;
padding: 5px 15px;
border-radius: 5px;
background: #1381f3;
color: #fff;
position: relative;
&::after {
content: "";
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-bottom: 8px solid #1381f3;
position: absolute;
top: 33px;
left: 23px;
transform: rotate(180deg);
}
}
}
.vdr-container .dragging {
border-color: transparent !important;
}
:deep(.vdr-container .dragging) {
border-color: transparent !important;
}
:deep(.vdr-container.active) {
border-color: transparent !important;
}
</style>
例子
<script setup lang="ts">
import { reactive, onMounted } from "vue"
import MapIcon from "./HotspotMap.vue"
const state = reactive({
imgUrl:
"https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fstatic.loupan.com%2Fupfile2%2Fimage%2F20170315%2F20170315131312_8211318.jpg&refer=http%3A%2F%2Fstatic.loupan.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1663741900&t=71252557b8aace751a4d2963974a26e8",
list: [
{ mapId: 1, name: 15, mapX: 200, mapY: 200 },
{ mapId: 2, name: 5, mapX: 100, mapY: 100 },
{ mapId: 3, name: 8, mapX: 680, mapY: 370 },
{ mapId: 4, name: 7, mapX: 36, mapY: 190 },
{ mapId: 5, name: 10, mapX: 63, mapY: 45 }
],
subrr: [],
objName: {}
})
state.objName = {
id: "mapId",
name: "name",
x: "mapX",
y: "mapY"
}
const tungInfo = (e: any) => {
console.log(e, state.list)
}
</script>
<template>
<div class="content-manage">
<div class="button">
<el-button @click="addEditClick(1, {})">新增</el-button>
</div>
<MapIcon
:imgUrl="state.imgUrl"
:list="state.list"
@tungInfo="tungInfo"
:objName="state.objName"
/>
</div>
</template>
vue2
<template>
<div>
<div class="bg-img" :style="'background:url('+imgUrl+');backgroundSize:100% 100%'">
<VueDraggableResizable
v-for="item in list"
:key="item[objName.id]"
:onDragStart="() => dragStart(item[objName.id])"
:x ="item[objName.x]"
:y ="item[objName.y]"
:w ="40"
:h ="30"
:parent="true"
@dragstop ="onDragstop"
>
<div class="icon">{{item[objName.name]}}</div>
</VueDraggableResizable>
</div>
</div>
</template>
<script>
import VueDraggableResizable from 'vue-draggable-resizable'
export default({
components: {
VueDraggableResizable
},
props: {
imgUrl: {
type: String,
default: ''
},
// 图标数组
list: {
type: Array,
default: () => []
},
// 组件对应字段
objName: {
type: Object,
default: () => {}
}
},
data() {
return {
draggingId: 0
}
},
methods: {
dragStart(id) {
this.draggingId = id
},
onDragstop(x, y) {
const item = this.list.find((i) => i[this.objName.id] === this.draggingId)
console.log(this.list, item)
item[this.objName.x] = x
item[this.objName.y] = y
this.$emit('tungInfo', item)
}
}
})
</script>
<style lang="scss" scoped>
.bg-img{
width: 800px;
height: 500px;
display: flex;
.icon{
display: inline-block;
padding: 5px 15px;
border-radius: 5px;
background: #1381f3;
color: #fff;
position: relative;
&::after{
content: '';
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-bottom: 8px solid #1381f3;
position: absolute;
top: 27px;
left: 23px;
transform: rotate(180deg);
}
}
}
</style>
例子
<template>
<div>
图标拖动
<MapIcon :imgUrl='imgUrl' :list='list' @tungInfo='tungInfo' :objName='objName'/>
</div>
</template>
<script>
import MapIcon from './mapIcon.vue'
export default({
components: {
MapIcon
},
data() {
return {
imgUrl: 'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fstatic.loupan.com%2Fupfile2%2Fimage%2F20170315%2F20170315131312_8211318.jpg&refer=http%3A%2F%2Fstatic.loupan.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1663741900&t=71252557b8aace751a4d2963974a26e8',
list: [
{ mapId: 1, name: 15, mapX: 200, mapY: 200 },
{ mapId: 2, name: 5, mapX: 100, mapY: 100 },
{ mapId: 3, name: 8, mapX: 20, mapY: 200 },
{ mapId: 4, name: 7, mapX: 36, mapY: 190 },
{ mapId: 5, name: 10, mapX: 63, mapY: 45 }
],
subrr: [],
objName: {}
}
},
created() {
this.objName = {
id: 'mapId',
name: 'name',
x: 'mapX',
y: 'mapY'
}
},
methods: {
tungInfo(e) {
console.log(e, this.list)
}
}
})
</script>
注:父页面需要position: relative;这样小图标才会定位在父页面上