使用拖拽生成活动海报(vue项目)
<template>
<div class="poster-editor">
<div class="toolbar" v-if="edit == '1'">
<div style="text-align: center;font-size: 14px;font-weight: 700;margin-bottom: 10px;">工具栏</div>
<div class="toolbar-item" v-for="(item, index) in toolbarItems" :key="index"
@dragstart="onDragStart($event, item)" draggable="true">
<span>{{ item.label }}</span>
<el-popover placement="top" width="350" trigger="click">
<div style="margin-bottom: 5px;">
<el-input v-model="item.fontSize" placeholder="文字大小" @input="item.fontSize = integer(item.fontSize)"
@blur="clickFontSizeColor(item)" @change="clickFontSizeColor(item)">
<template slot="prepend">文字大小</template>
</el-input>
</div>
<div style="display: flex;">
<el-input v-model="item.color" placeholder="颜色" @blur="clickFontSizeColor(item)" @change="clickFontSizeColor(item)">
<template slot="prepend">文字颜色</template>
</el-input>
<el-color-picker v-model="item.color" @change="clickFontSizeColor(item)" style="margin-left: 10px;"></el-color-picker>
</div>
<el-button v-if="item.type == 'text'" slot="reference" type="text" icon="el-icon-edit"></el-button>
</el-popover>
</div>
</div>
<div class="poster-canvas" ref="posterCanvas" @drop="onDrop($event)" @dragover="onDragOver($event)">
<div class="background" :style="{ backgroundImage: `url(${backgroundImage})` }"></div>
<div v-for="(element, index) in elements" :key="index" class="poster-element" :style="{
top: element.top + 'px',
left: element.left + 'px',
width: element.width + 'px',
height: element.height + 'px',
transform: `rotate(${element.rotation}deg)`
}" @mousedown="onMouseDown($event, index)">
<button class="delete-btn" @click.stop="onDeleteElement(index)" v-if="edit == '1'">x</button>
<img v-if="element.type === 'image'" :src="element.content" class="draggable-image" />
<div v-else :style="{ fontSize: element.fontSize + 'px', color: element.color }" class="draggable-text">{{
element.content }}</div>
</div>
</div>
</div>
</template>
<script>
// import html2canvas from 'html2canvas'
export default {
props: {
backgroundImage: {
type: String,
default: ''
},
edit: {
type: String,
default: ''
}
},
watch: {
},
data() {
return {
toolbarItems: [
{ label: '二维码', type: 'image', content: require("../../../../assets/img/card_hm.png") },
{ label: '名称', type: 'text', content: '123', fontSize: 14, color: '#000000' },
{ label: '电话', type: 'text', content: '123', fontSize: 14, color: '#000000' },
{ label: '地址', type: 'text', content: '123', fontSize: 14, color: '#000000' }
],
elements: [],
currentElementIndex: null,
offsetX: 0,
offsetY: 0,
isDragging: false,
isResizing: false,
isRotating: false,
startWidth: 0,
startHeight: 0,
startFontSize: 16,
startRotation: 0,
resizeStartX: 0,
resizeStartY: 0,
rotateStartX: 0,
rotateStartY: 0,
// backgroundImage: '', // 背景图片
};
},
methods: {
onDragStart(event, item) {
const itemJSON = JSON.stringify(item);
event.dataTransfer.setData('element', itemJSON);
},
onDragOver(event) {
event.preventDefault();
},
onDrop(event) {
event.preventDefault();
const canvasRect = this.$refs.posterCanvas.getBoundingClientRect();
const elementDataString = event.dataTransfer.getData('element');
if (!elementDataString) {
console.error('No data found in drag event');
return; // 提早返回,避免解析错误
}
let elementData;
try {
elementData = JSON.parse(elementDataString);
} catch (error) {
console.error('Failed to parse element data:', error);
return; // 处理解析错误
}
// console.log('elementData:', elementData);
let newElement = {
...elementData,
top: event.clientY - canvasRect.top,
left: event.clientX - canvasRect.left,
width: elementData.type === 'image' ? 100 : 150,
height: elementData.type === 'image' ? 100 : 40,
fontSize: elementData.type === 'text' ? elementData.fontSize : '',
color: elementData.type === 'text' ? elementData.color : '',
rotation: 0, // 新增旋转属性
};
this.elements.push(newElement);
this.$emit('savePoster', this.elements);
},
onMouseDown(event, index) {
// console.log(event, index,'event, index')
this.currentElementIndex = index;
this.offsetX = event.clientX - (this.elements[index].left);
this.offsetY = event.clientY - (this.elements[index].top);
this.isDragging = true;
document.addEventListener('mousemove', this.onMouseMove);
document.addEventListener('mouseup', this.onMouseUp);
// 停止并更新
this.$emit('savePoster', this.elements);
},
onMouseMove(event) {
if (this.isDragging && this.currentElementIndex !== null) {
const fixedWidth = 400; // 固定宽度
const fixedHeight = 800; // 固定高度
const element = this.elements[this.currentElementIndex];
// 计算新的位置
let newTop = event.clientY - this.offsetY;
let newLeft = event.clientX - this.offsetX;
// 限制移动范围(上下左右)
if (newTop < 0) newTop = 0; // 上边界
if (newLeft < 0) newLeft = 0; // 左边界
console.log()
if (newTop + element.height > fixedHeight) {
newTop = fixedHeight - element.height; // 下边界
}
if (newLeft + element.width > fixedWidth) {
newLeft = fixedWidth - element.width; // 右边界
}
// 更新元素位置
this.$set(this.elements, this.currentElementIndex, {
...element,
top: newTop,
left: newLeft,
});
}
},
onMouseUp() {
this.isDragging = false;
this.isResizing = false;
this.isRotating = false;
document.removeEventListener('mousemove', this.onMouseMove);
document.removeEventListener('mouseup', this.onMouseUp);
},
onResizeStart(event, index) {
this.currentElementIndex = index;
this.isResizing = true;
const element = this.elements[index];
this.startWidth = element.width;
this.startHeight = element.height;
this.resizeStartX = event.clientX;
this.resizeStartY = event.clientY;
document.addEventListener('mousemove', this.onMouseMove);
document.addEventListener('mouseup', this.onMouseUp);
},
onRotateStart(event, index) {
this.currentElementIndex = index;
this.isRotating = true;
const element = this.elements[index];
this.startRotation = element.rotation;
this.rotateStartX = event.clientX;
this.rotateStartY = event.clientY;
document.addEventListener('mousemove', this.onMouseMove);
document.addEventListener('mouseup', this.onMouseUp);
},
onDeleteElement(index) {
this.elements.splice(index, 1);
},
//修改文字大小
clickFontSizeColor(item) {
if (this.elements.length > 0) {
this.elements.forEach(element => {
if (element.label == item.label) {
element.fontSize = item.fontSize
element.color = item.color
}
});
this.$emit('savePoster', this.elements);
}
},
},
};
</script>
<style lang="less" scoped>
.poster-editor {
display: flex;
padding: 20px;
margin-top: 20px;
}
.toolbar {
width: 125px;
background-color: #f5f5f5;
padding: 10px;
}
.toolbar-item {
display: flex;
justify-content: space-between;
align-items: center;
text-align: left;
margin-bottom: 10px;
padding: 10px;
background-color: #e1e1e1;
border-radius: 5px;
cursor: grab;
}
.poster-canvas {
position: relative;
width: 400px;
height: 800px;
background-color: #ffffff;
border: 1px solid #ddd;
border-radius: 40px;
overflow: hidden;
margin-left: 20px;
}
.background {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
// width: 400px;
// height: 800px;
background-size: 100% 100%;
background-position: center;
}
.poster-element {
position: absolute;
cursor: move;
box-sizing: border-box;
}
.poster-element:hover {
.delete-btn {
display: block;
}
.draggable-tex {
border: 1px solid #ccc;
background-color: rgba(240, 240, 240, 0.8);
}
}
.draggable-image {
width: 100%;
height: 100%;
}
.draggable-text {
text-align: left;
// padding: 10px;
// line-height: 20px;
// 下面才是重点关注代码
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
text-overflow: ellipsis;
white-space: normal;
-webkit-line-clamp: 4;
/* 设置最大显示行数 */
}
.delete-btn {
position: absolute;
top: -10px;
right: -10px;
background-color: red;
color: white;
border: none;
border-radius: 50%;
width: 20px;
height: 20px;
cursor: pointer;
font-size: 12px;
display: none;
}
.resize-handle {
position: absolute;
right: 0;
bottom: 0;
width: 10px;
height: 10px;
background-color: blue;
cursor: se-resize;
}
.rotate-handle {
position: absolute;
top: -10px;
left: 50%;
transform: translateX(-50%);
width: 10px;
height: 10px;
background-color: green;
cursor: grab;
}
.controls {
margin: 20px;
}
</style>
使用
// 拖拽画布
import Dragcanvas from "./components/dragcanvas.vue";
<Dragcanvas @savePoster='savePoster' :backgroundImage="ruleForm.cover" :edit="$route.query.edit"></Dragcanvas>
components: {
Dragcanvas
},
// 活码拖拽
savePoster(item) {
let width = 400 // 固定宽
let height = 800 // 固定高度
let ary = []
item.map(it => {
ary.push({
content: it.content,
fontSize: it.fontSize,
label: it.label,
rotation: it.rotation,
type: it.type,
width: it.width,
height: it.height,
left: it.left,
top: it.top,
fixedwidth: width,
fixedheight: height,
leftpercentage: (it.left / width) * 100,
toppercentage: (it.top / height) * 100,
color: it.color,
})
})
console.log(ary, '拖拽的数据')
}
展示效果
原文地址:https://blog.csdn.net/weixin_44694682/article/details/142909740
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!