vue 组件拖拽

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

要拖动的组件:

         <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>
相关推荐
Java开发追求者10 分钟前
npm镜像源证书过期的问题解决
前端·npm·node.js·npm镜像源证书过期的问题解决
宝子向前冲18 分钟前
React中九大常用Hooks总结
前端·javascript·react.js
小白小白从不日白33 分钟前
react 基础语法
前端·react.js
岸边的风34 分钟前
前端Excel热成像数据展示及插值算法
前端·算法·excel
不良人龍木木2 小时前
sqlalchemy FastAPI 前端实现数据库增删改查
前端·数据库·fastapi
c1tenj22 小时前
Jedis,SpringDataRedis
前端
Code成立2 小时前
HTML5中IndexedDB前端本地数据库
前端·数据库·html5·indexeddb
Code成立3 小时前
最新HTML5中的文件详解
前端·html·html5
橙子家3 小时前
前端项目通过 Nginx 发布至 Linux,并通过 rewrite 配置访问后端接口
前端