业务场景:用户上传一张图片和json文件,根据json文件中的x和y轴将元素放置在对应的位置上,元素根据width和height字段控制大小
完整代码
<template>
<div>
<div style="display: flex; align-items: center; margin-bottom: 20px">
<el-input
v-model="imgUrl"
style="width: 240px"
placeholder="请输入图片路径"
@input="handelChange"
/>
<el-input
v-model="jsonFilePath"
style="width: 240px"
placeholder="请输入JSON文件路径"
@input="handelChange"
/>
<el-button type="primary" @click="copyText">获取JSON</el-button>
</div>
<div
style="display: flex; align-items: center; width: 100%"
v-show="imgUrl"
>
<div
ref="back_box"
style="width: 1920px; height: 1080px; position: relative"
>
<img :src="imgUrl" style="width: 1920px; height: 1080px" alt="" />
<div v-for="(i, n) in data" :key="n">
<div @click="hever(i.dpId)" @mousedown="onMouseDown($event, i.dpId,)" @mouseup="onMouseUp($event, i.dpId,)"
draggable="true" @dragstart="dragstart" style=" resize: both;
overflow: auto;" @dragend="dragend($event, i.dpId)"
:style="{ 'left': i.x + 'px', 'top': i.y + 'px', 'height': i.height + 'px', 'width': i.width + 'px', 'border': '1px solid red', 'position': 'absolute', '-webkit-transform': 'scale' + meter_zoom, color: 'yellow', 'overflow': 'hidden'}">
{{ "x" + i.x + "y:" + i.y }}
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import dataJson from "../public/json/data.json";
export default {
name: "HelloWorld",
data() {
return {
isResizing: false,
initialWidth: 0,
initialHeight: 0,
mouseX: 0,
mouseY: 0,
imgUrl: "img/img3.jpg",
jsonFilePath: "",
jsonData: null,
data: dataJson.dpData,
initWidth: 0, // 父元素的宽-自适应值
initHeight: 0, // 父元素的高-自适应值
startclientX: 0, // 元素拖拽前距离浏览器的X轴位置
startclientY: 0, //元素拖拽前距离浏览器的Y轴位置
elLeft: 0, // 元素的左偏移量
elTop: 0, // 元素的右偏移量
zoom: 1, // 缩放比例
elWidth: 0, // 元素宽
elHeight: 0, // 元素高
meter_zoom: 0, // 子元素缩放比例
imgWidth: 0, //图片宽度
imgHeight: 0, //图片高度
index: 0,
};
},
methods: {
onMouseDown(event) {
// console.log(event.target.offsetWidth,event.target.offsetHeight);
},
onMouseUp(event, id) {
this.data.forEach((i) => {
if (i.dpId === id) {
i.width = event.target.offsetWidth;
i.height = event.target.offsetHeight;
}
});
console.log(event.target.offsetWidth, event.target.offsetHeight);
},
hever(id) {
this.data.forEach((i) => {
if (i.dpId === id) {
i.select = true;
}
});
},
startResize(event, id, index) {
this.isResizing = true;
this.index = index;
this.initialWidth = this.$refs.resizableElement[index].offsetWidth;
this.initialHeight = this.$refs.resizableElement[index].offsetHeight;
this.mouseX = event.clientX;
this.mouseY = event.clientY;
this.data.forEach((l) => {
if (l.dpId === id) {
document.addEventListener("mousemove", this.resizeElement);
document.addEventListener("mouseup", this.stopResize);
}
});
},
resizeElement(event) {
if (!this.isResizing) return;
const widthChange = event.clientX - this.mouseX;
const heightChange = event.clientY - this.mouseY;
this.$refs.resizableElement[this.index].style.width = `${
this.initialWidth + widthChange
}px`;
this.$refs.resizableElement[this.index].style.height = `${
this.initialHeight + heightChange
}px`;
},
stopResize() {
this.isResizing = false;
document.removeEventListener("mousemove", this.resizeElement);
document.removeEventListener("mouseup", this.stopResize);
},
copyText() {
const el = document.createElement("textarea");
el.value = function(){
let str = "";
let DATA = dataJson.dpData;
console.log(DATA);
for (let i = 0; i < DATA.length; i++) {
str += `${DATA[i].x},${DATA[i].y},${DATA[i].width},${DATA[i].height}` + '\n';
}
return str;
}()
el.setAttribute("readonly", "");
el.style.position = "absolute";
el.style.left = "-9999px";
document.body.appendChild(el);
el.select();
document.execCommand("copy");
document.body.removeChild(el);
this.$message.success("复制成功");
},
handelChange(val) {
this.imgUrl = val;
this.$nextTick(() => {
this.imgWidth = this.$refs.back_box.clientWidth; // 拿到图片宽度
this.imgHeight = this.$refs.back_box.clientHeight; // 拿到图片宽度
});
},
// 页面初始化
initBodySize() {
this.initWidth = 500;
this.initHeight = this.initWidth * ((1080 * 0.88) / (1920 - 1080 * 0.02)); // 根据宽计算高实现自适应
this.elWidth = this.initWidth * (100 / (1920 / 2));
this.elHeight = this.initHeight * (100 / (1080 / 2));
this.meter_zoom = this.elWidth / 100; // 计算子元素缩放比例
},
// 拖拽开始事件
dragstart(e) {
this.startclientX = e.clientX; // 记录拖拽元素初始位置
this.startclientY = e.clientY;
},
// 拖拽完成事件
dragend(e, id) {
let x = e.clientX - this.startclientX; // 计算偏移量
let y = e.clientY - this.startclientY;
this.data.forEach((d) => {
// debugger
if (d.dpId === id) {
d.x += x; // 实现拖拽元素随偏移量移动
d.y += y;
}
});
},
},
mounted() {
// console.log(this.$el);
this.initBodySize();
console.log(this.data);
},
};
</script>
<style scoped>
body {
width: 100%;
}
.zoomable-element {
width: 200px;
height: 200px;
/* background-color: #ccc; */
cursor: pointer;
transition: transform 0.3s;
}
.back_box {
background: #fff;
width: 50vw;
height: 50vh;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -30%);
}
.drag_box {
width: 100px;
height: 100px;
background: red;
position: absolute;
z-index: 10;
user-select: none;
/* 不可选中,为了拖拽时不让文字高亮 */
}
.text {
position: absolute;
width: 100px;
height: 100px;
transform-origin: 0 0;
/* 用作缩放基点 */
font-size: 16px;
}
.resizable-element {
width: 200px;
height: 200px;
/* background-color: #ccc; */
resize: both;
overflow: auto;
}
</style>