需求:将一个组件拖动至页面任何位置,记录并回显
要拖动的组件:
<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>
复制