vue 组件拖拽

news2024/9/22 23:32:41

需求:将一个组件拖动至页面任何位置,记录并回显

要拖动的组件:

         <div
            class="left left_module_text"
            draggable="true"
            @dragstart="dragstart($event)"
            @dragend.stop="dragend1($event, { left: 0, top: 0 }, '文本', 1)"
          >文本 </div>

拖动后的组件:

说明(如果是需要拖动一个组件并且回显在同一个组件,那么只需要将两个div的style组合就起来就可以了)我得项目里需求是需要多个组件,所以就是用了for循环,再次拖动的时候就传入item,index,根据此参数修改组件对象的left和top记录位置

           <div
                v-for="(item, index) in mediaFrameList"
                :key="item.id"
                :style="`z-index:${item.zindex};background-image:${item.bkImage ? 'url(' + baseUrl+item.bkImage + ')' : 'none'};justify-content:${item.textAlign};background-color:${item.bkColor ? item.bkColor : 'transparent'};color:${item.fontColor};font-size:${item.fontSize + 'px'};align-items:${item.alignItem};font-weight:${item.bold == 1 ? 'bold' : 'normal'};font-style:${item.italic == 1 ? 'italic' : 'normal'};font-family:${item.fontFamily};left:${item.flLeft + 'px'};top:${item.flTop + 'px'};width:${item.flWidth + 'px'};height:${item.flHeight + 'px'};`"
                style="position: absolute; display: flex;background-size:100% 100%"
                ref="text"
                draggable="true"
                @dragstart="dragstart1($event, item)"
                @dragend.stop="dragend($event, item, index)"
                @click="handleClick(item, index)"
              >
{{item.content }}
            </div>

 开始拖拽的方法,记录刚开始拖拽时组件的位置:

// 开始拖拽位置
    dragstart(e, item, index) {
      this.left = this.$refs['ceshi'].getBoundingClientRect().left//记录组件拖拽时的位置
      this.top = this.$refs['ceshi'].getBoundingClientRect().top
    },
    dragstart1(e, item, index) {
      this.left = e.clientX * 1
      this.top = e.clientY * 1
    },

拖拽后的方法,将拖拽后组件的位置存到数组中(mediaFrameList[index].flLeft):

  // 停止拖拽位置
    dragend(e, item, index) {
      let x = e.clientX - this.left
      let y = e.clientY - this.top
      const width = this.$refs.canvas.offsetWidth;
      const height = this.$refs.canvas.offsetHeight;

      this.mediaFrameList[index].flLeft = item.flLeft + x
      this.mediaFrameList[index].flTop = item.flTop + y
    }
 dragend1(e, item, content, flType) {
      let x = e.clientX - this.left
      let y = e.clientY - this.top
        this.mediaFrameList.push({
        flLeft: item.left + x,
        flTop: item.top + y,
        })
}

最后,我上面的代码由于逻辑比较多,所以不看也行,拿着我下面的代码就是一个简单的demo,没有使用任何插件

可以以这个为基础,这个开发空间还是很大的,比如:我在项目中还添加了设置组件的字体、字号、居中等等很多属性,自由度很高,还有回显示添加的等比缩,等比放大

<template>
  <div
    class="index_admin_form"
    v-loading="loading"
  >
    <div
      class="top_box"
      style="position: relative;"
    >
      <div
        class="top"
        style="display: flex;"
      >
        <div class="title">模版标题</div>
        <el-input
          style="width: 120px;"
          v-model="cfName"
          maxlength="20"
        ></el-input>
     
        <!-- <div class="title">状态</div>
        <el-switch
          style="align-items: center;height: 36px;"
          v-model="value"
          active-color="#1543FA"
          inactive-color="#999"
        >
        </el-switch> -->
      </div>
      <div
        class="top_right"
        style="display: flex;"
      >
        <div class="title">模块宽度</div>
        <el-input
          style="width: 120px;"
          v-model="selectWidth"
          @change="selectWidthChange"
        ></el-input>
        <div class="title">模块高度</div>
        <el-input
          style="width: 120px;"
          v-model="selectHeight"
          @change="selectHeightChange"
        ></el-input>
        <div class="title">模块X轴</div>
        <el-input
          style="width: 120px;"
          v-model="selectX"
          @change="selectXChange"
        ></el-input>
        <div class="title">模块Y轴</div>
        <el-input
          style="width: 120px;"
          v-model="selectY"
          @change="selectYChange"
        ></el-input>
        <div class="title">模块颜色</div>
        <el-color-picker
          show-alpha
          class="font_color"
          title="字体颜色"
          style="margin-right: 10px;"
          v-model="bkColor"
          @change="fontColorChange"
          :disabled="colordisabled"
        ></el-color-picker>
        <div
          class="top_right_btn_add"
          @click="addMoudle"
        >+ 添加模块</div>
        <div
          class="top_right_btn_del"
          @click="delMoudle"
        >删除</div>

      </div>
    </div>
    <el-row style="height: 89%;">
      <el-col
        :span="2"
        style="height:  100%;border-right: 1px solid #ddd;position: relative;"
      >
        <div class="no_edit">
          <div style="align-self: center;">
            <div class="no_edit_title">不</div>
            <div class="no_edit_title">可</div>
            <div class="no_edit_title">编</div>
            <div class="no_edit_title">辑</div>
            <div class="no_edit_title">区</div>
          </div>
        </div>

      </el-col>
      <el-col
        :span="20"
        style="height:  100%;border-right: 1px solid #ddd;position: relative;"
      >
     
        <div
          style="position: relative;width: 100%;height: 100%;"
          ref="canvas"
        >

          <div
            v-for="(item,index) in moduleList"
            :key="index"
            style=""
            :style="`position: absolute;left:${item.flLeft}px;top:${item.flTop}px;border:${item.isSelect?'1px dashed #333333':'1px dashed #DDDDDD'} ;color:${item.isSelect?' #333333':'#DDDDDD'} ;background:${item.bkColor};width:${item.flWidth}px;height:${item.flHeight}px;`"
            draggable="true"
            @dragstart="dragstart($event, item)"
            @dragend.stop="dragend($event, item, index)"
            @click="itemClick(index)"
          >
            <div> 布局{{ index+1 }}</div>
            <div
              class="icon el-icon-arrow-right"
              title="缩放"
              draggable="true"
              @dragstart.stop="dragstart2($event, item, index)"
              @dragend.stop="dragend2($event, item, index)"
              style="color:#000"
            ></div>
          </div>
        </div>
      </el-col>
      <el-col
        :span="2"
        style="height:  100%;border-right: 1px solid #ddd;"
      >
        <div class="no_edit">
          <div style="align-self: center;">
            <div class="no_edit_title">不</div>
            <div class="no_edit_title">可</div>
            <div class="no_edit_title">编</div>
            <div class="no_edit_title">辑</div>
            <div class="no_edit_title">区</div>
          </div>
        </div>
      </el-col>
    </el-row>
    <div style="background-color: #F4F4F5;width: 100%;position: absolute;">
      <div style="display: flex;margin: 0 auto; height: 50px; justify-content: center;  align-items: center;">
        <div
          class="programcanvas_box_del"
        >取消</div>
        <div
          class="programcanvas_box_save"
        >保存配置</div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    id: { type: String, default: '' },
    // isEdit: { type: String, required: true },

  },
  data() {
    return {
      loading: false,
      colordisabled: true,
      bkColor: '',
      cfName: '',
      textAlign: '',
      value: '',
      moduleList: [],
      moudle: {},
      selectWidth: 0,
      selectHeight: 0,
      selectX: 0,
      selectY: 0,
      selectIndex: -1
    };
  },
  watch: {

  },
  computed: {

  },
  mounted() {

  },
  methods: {
    itemClick(index){
      this.selectIndex = index
    },
    fontColorChange() {
      this.moduleList[this.selectIndex].bkColor = this.bkColor
    },
    selectWidthChange(e) {
      this.moduleList[this.selectIndex].flWidth = e * 1
    
    },
    selectHeightChange(e) {
      this.moduleList[this.selectIndex].flHeight = e * 1
    
    },
    selectXChange(e) {
      this.moduleList[this.selectIndex].flLeft = e * 1
   

    },
    selectYChange(e) {
      this.moduleList[this.selectIndex].flTop = e * 1
     
    },
   
   
    dragstart(e, item, index) {
      this.left = e.clientX * 1
      this.top = e.clientY * 1
    },
    // 停止拖拽位置
    dragend(e, item, index) {
      let x = Math.round(e.clientX - this.left)
      let y = Math.round(e.clientY - this.top)

      this.moduleList[index].flLeft = Math.round(item.flLeft + x)
      this.moduleList[index].flTop = Math.round(item.flTop + y)
      if (this.moduleList[index].flLeft < 0) {
        this.moduleList[index].flLeft = 0
      } if (this.moduleList[index].flTop < 0) {
        this.moduleList[index].flTop = 0
      }
      if (this.moduleList[index].flLeft + this.moduleList[index].flWidth > this.width) {
        this.moduleList[index].flLeft = Math.round(this.width - this.moduleList[index].flWidth)
      }
      if (this.moduleList[index].flTop + this.moduleList[index].flHeight > this.height) {
        this.moduleList[index].flTop = Math.round(this.height - this.moduleList[index].flHeight)
      }
     
    },
    // 开始拖拽大小 右下角
    dragstart2(e, item, index) {
      this.startX = e.clientX
      this.startY = e.clientY
    },
    // 停止拖拽大小 右下角
    dragend2(e, item, index) {
      let x = e.clientX - this.startX
      let y = e.clientY - this.startY
      this.moduleList[index].flWidth = Math.round(item.flWidth + x)
      this.moduleList[index].flHeight = Math.round(item.flHeight + y)

      if (this.moduleList[index].flLeft + this.moduleList[index].flWidth > this.width) {
        this.moduleList[index].flWidth = Math.round(this.width - this.moduleList[index].flLeft)
      }
      if (this.moduleList[index].flTop + this.moduleList[index].flHeight > this.height) {
        this.moduleList[index].flHeight = Math.round(this.height - this.moduleList[index].flTop)
      }
      if (this.moduleList[index].isSelect) {
        this.selectWidth = this.setLeft1(this.moduleList[index].flWidth)
        this.selectHeight = this.setTop1(this.moduleList[index].flHeight)
      }
    },
    addMoudle() {
      console.log(this.$refs.canvas)
      this.width = this.$refs.canvas.offsetWidth;
      this.height = this.$refs.canvas.offsetHeight;
      this.moduleList.push({
        bkColor: "#fff",
        cfName: "布局",
        flHeight: 100,
        flWidth: 100,
        flLeft: 0,
        flTop: 0,
        isSelect: false
      });
    },
    delMoudle() {
      console.log(this.selectIndex)
      if (this.selectIndex == -1) return
      this.moduleList.splice(this.selectIndex, 1)
      this.selectIndex = -1
    },
  


  }
};
</script>

<style scoped lang="scss">
.index_admin_form {
  width: 100%;
  height: 100%;
  background-color: #fff;
  z-index: 2000;
  position: fixed;
  top: 0;
  left: 0;
}

.title {
  line-height: 36px;
  font-size: 12px;
  margin-right: 10px;
  color: #fff;
  margin-left: 20px;
}
.top_box {
  width: 100%;
  padding: 10px 30px;
  background-color: #121b36;
}
.top_right {
  position: absolute;
  right: 50px;
  top: 10px;
}
.top_right_btn_add {
  background: #1543fa;
  border-radius: 5px;
  line-height: 36px;
  font-size: 12px;
  padding: 0 15px;
  color: #fff;
  margin-right: 20px;
  cursor: pointer;
}
.top_right_btn_del {
  background: #121b36;
  border-radius: 5px;
  border: 1px solid #999999;
  color: #999999;
  line-height: 36px;
  font-size: 12px;
  padding: 0 15px;
  cursor: pointer;
}
.no_edit {
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
}
.no_edit_title {
  width: 100%;
  text-align: center;
  line-height: 86px;
  font-size: 24px;
  color: #e5e5e5;
}
.bottom {
  width: 100%;
  height: 36px;
}
.programcanvas_box_del {
  line-height: 25px;
  width: 60px;
  height: 25px;
  background: #e7e7e7;
  border-radius: 3px;
  text-align: center;
  font-size: 12px;
  margin-right: 20px;
  cursor: pointer;
  color: #666;
}
.programcanvas_box_save {
  line-height: 25px;
  width: 60px;
  height: 25px;
  background: #1543fa;
  border-radius: 3px;
  text-align: center;
  font-size: 12px;
  cursor: pointer;
  color: #fff;
}
.icon {
  position: absolute;
  z-index: 13;
  width: 12px;
  height: 13px;
  font-size: 10px;
  cursor: pointer;
  font-weight: bold;
  transform: rotate(45deg);
  right: -4px;
  bottom: -6px;
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2086053.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

macos 自定义用户目录方法, /Users/xxx 用户文件存储路径自定义方法

在macos中,我们的用户数据全部都存储在了 /Users/xxx 文件夹下, 而这个文件夹默认是和我们的macos系统文件存放在了同一个磁盘卷宗(分区)里面的, 这个就给我们在遭遇系统崩溃或者其他情况重装系统时带来了极大的不便, 如果是格式化后全新安装 数据全部丢失,如果是覆盖安装同…

刘文超行测笔记

一、判断推理 1.位置规律 2.样式规律 特征&#xff1a;元素组成相似 &#xff08;1&#xff09;加减同异 &#xff08;2&#xff09;黑白运算 1.特征&#xff1a;图形轮廓和分隔区域相同&#xff0c;内部的颜色不同 2.方法&#xff1a;相同位置运算 区分&#xff1a; 黑块…

2.3 阿里巴巴-背包问题

题目&#xff1a; 代码&#xff1a; #include <iostream> using namespace std; #include<algorithm> #include<stdlib.h>#define M 1000005//结构体&#xff0c;重量&#xff0c;价值&#xff0c;价重比 struct three {double w;double v;double p; }s[M];…

UE【材质编辑】Shader模板

【UE 4.27.2】 在UE中双击材质球会进入材质编辑界面。PBR的材质参数呈现为材质蓝图的各个节点&#xff0c;提供数据源&#xff0c;传递进材质。最后材质对其进行组织&#xff0c;呈现为VS&#xff0c;PS等着色器代码&#xff0c;基本流程&#xff1a; 本文会刨析在UE4.27.2中材…

Postman注册使用

文章目录 介绍下载安装官网&#xff1a;[Postman API Platform | Sign Up for Free](https://www.postman.com/) 使用过程 介绍 Postman是一款功能强大的网页调试与发送网页HTTP请求的Chrome插件。 Postman原是Chrome浏览器的插件&#xff0c;可以模拟浏览器向后端服务器发起…

「Python程序设计」基本数据类型:列表(数组)

​列表是python程序设计中的一个基本的&#xff0c;也是重要的数据结构。我们可以把列表数据结构&#xff0c;理解为其它编程语言中的数组。 定义和创建列表 列表中的数据元素的索引&#xff0c;和数组基本一致&#xff0c;第一个元素的索引&#xff0c;或者是下标为0&#x…

CSS-径向渐变【看这一篇就够了!!!】

目录 线性渐变 未设置角度&#xff0c;默认从上向下渐变 关键字指定渐变方向 用度数来指定渐变方向 多个颜色值&#xff0c;并且可以用百分数定义它出现的位置 自定义转换中点 浏览器私有前缀 渐变色工具 径向渐变 简单的径向渐变 设置颜色节点出现的位置 设置径向渐…

(ECCV-2024)SwiftBrush v2:让你的一步扩散模型比它的老师更好

SwiftBrush v2&#xff1a;让你的一步扩散模型比它的老师更好 Paper Title&#xff1a;SwiftBrush v2: Make Your One-step Diffusion Model Better Than Its Teacher paper是VinAI Research发表在ECCV 2024的工作 paper地址 Code地址 Abstract. 在本文中&#xff0c;我们旨在…

Datawhale x李宏毅苹果书入门 AI夏令营 task03学习笔记

实践方法论 训练模型的基本步骤&#xff1a;&#xff08;如下图所示&#xff09; 用训练集训练模型&#xff0c;&#xff08;最终得出来最优的参数集&#xff09;将最优参数集带入模型中&#xff0c;用测试集测试模型&#xff08;人话&#xff1a;将最优参数集带入原来函数中…

观测云「可观测性解决方案」亮相 828 B2B 企业节

今年&#xff0c;随着第三届828 B2B企业节与中国国际大数据产业博览会的同步盛大开幕&#xff0c;我们迎来了企业发展和技术创新的崭新篇章。作为国内可观测性领域的领军企业&#xff0c;观测云不断深化在监控观测技术与能力上的探索&#xff0c;致力于为全球用户提供全面而统一…

如何用网络分析仪测试软件测试天线?

随着射频技术的发展&#xff0c;对于天线性能的精确测试需求日益增长&#xff0c;矢量网络分析仪因此成为测试环节中不可或缺的工具之一。今天天宇微纳为大家介绍网络分析仪测试天线S参数的方法与流程。 网络分析仪测试天线的方法 S参数是衡量和评估天线性能和通信质量的重要指…

springboot接收时间类型参数的方式

参数直接跟在url上面用DateTimeFormat接收 参数写在实体类中 用JsonFormat接收 注意&#xff1a; pattern 中的表达式要和接受的数据类型格式一致。不然会报错。例如表达式是 yyyy-MM-dd 就只能匹配LocalDate ,不能用 LocalDateTime去接收。即使LocalDateTime是更细化的时间类型…

Redis过期键监听

在 Redis 中&#xff0c;为了监听过期键事件&#xff0c;需要使用 Redis 的 Keyspace Notifications 功能。这一功能允许客户端订阅某些事件的发生&#xff0c;比如键过期、键删除等。 启用过期键监听 在 Redis 的配置文件 redis.conf 中&#xff0c;确保配置项 notify-keysp…

恒电流间歇滴定法 (GITT) 测试教程

文章目录 恒电流间歇滴定法 (GITT) 测试教程1. GITT 测试原理2. 实验准备2.1 设备与材料2.2 配置实验装置 3. GITT 测试步骤3.1 设定测试参数3.2 执行 GITT 测试 4. 数据分析4.1 电压变化分析4.2 扩散系数计算4.3 电荷传输阻抗分析 5. 总结与应用 恒电流间歇滴定法 (GITT) 测试…

【最新发布】OpenCV实验大师工作流引擎 - 实现OpenCV算法从设计到交付零代码

点击查看 更多 OpenCV工作流引擎案例与代码教程&#xff0c;QT集成案例 OpenCV实验大师工具软件介绍 一款能够提升OpenCV教学质量与OpenCV工程化开发质量与速度的OpenCV算法设计与流程验证 工具软件 - OpenCV实验大师平台。 一款OpenCV工程化开发效率提升与OpenCV教学质量提升…

一步迅速了解Spring框架中的几大特点

一&#xff0c;Spring框架的特点1 &#xff1a;AOP 1, AOP全称&#xff1a; Aspect Oriented Programming 2, AOP主要是用面向切面编程思想处理问题&#xff0c;面向切面编程是对面向对象编程的补充和延续 3,面向切面编程思想 面向切面编程思想是将我们程序中的非业务代码&am…

[SimCLR v2] Big Self-Supervised Models are Strong Semi-Supervised Learners

1、目的 借助无监督预训练来提升半监督学习的效果 2、方法 1&#xff09;unsupervised/self-supervised pretrain -> task-agnostic -> big (deep and wide) neural network可以有效提升准确性 -> improvements upon SimCLR larger ResNet models&#xff1b;deeper …

03:logic软件操作界面及常用设置

1.打开logic软件 2显示工具栏 3.logic软件常用设置 3.1常规页设置 3.2设计页设置 3.3颜色设置

在发布您的插件之前,如何在 ONLYOFFICE 插件市场中进行测试?

ONLYOFFICE 插件为我们提供了强大的定制和拓展功能。作为插件开发人员&#xff0c;您可能希望在发布之前&#xff0c;在插件管理器中预览您的插件。这篇文章将指导您如何在 ONLYOFFICE 插件市场中预览插件。 关于 ONLYOFFICE ONLYOFFICE 是一个国际开源项目&#xff0c;由领先…

大数据智能风控核心:模型

概述 模型 线性判别分析方法&#xff0c;Sir Ronald Fisher最早提出模型评分的概念。 个人FICO模型信用分。 巴塞尔委员会发布巴塞尔Ⅱ协议&#xff0c;推出内部评级法&#xff08;Internal Rating Based Approach&#xff0c;IRB&#xff09;​。IRB综合考虑客户评级和债项…