实现拖拽元素,控制元素大小,根据x和y轴放置元素功能

业务场景:用户上传一张图片和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>

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值