Vue3 实现拖拽小图片覆盖大图片并下载合并后的图片
体验地址
技术栈
- Vue3: 用于构建用户界面。
- HTML5 Canvas: 用于绘制和合并图片。
- JavaScript: 处理拖拽和下载逻辑。
功能概述
- 拖拽小图片: 用户可以通过鼠标拖拽小图片到大图片的任意位置。
- 边界限制: 确保小图片不会超出大图片的边界。
- 下载合并后的图片: 用户可以点击按钮下载合并后的图片。
实现步骤
1. 创建 Vue 组件
<template>
<div class="image-container" @mousemove="handleMouseMove" @mouseup="handleMouseUp">
<img
:src="largeImageUrl"
alt="Large Image"
class="large-image"
ref="largeImageRef"
crossorigin="anonymous"
/>
<img
:src="smallImageUrl"
alt="Small Image"
class="small-image"
ref="smallImageRef"
width="60"
:style="{ left: smallImagePosition.x + 'px', top: smallImagePosition.y + 'px' }"
crossorigin="anonymous"
@mousedown="handleMouseDown"
/>
</div>
</template>
<script>
import { ref, onMounted } from "vue";
import { uploadFileFun } from "@/utils/minio.js";
import { dataURLtoFile } from "@/utils/methods";
export default {
setup() {
const largeImageUrl =
"https://";
const smallImageUrl =
"https:/";
const smallImagePosition = ref({ x: 0, y: 0 });
const largeImageRef = ref(null);
const smallImageRef = ref(null);
let isDragging = false;
let dragStart = { x: 0, y: 0 };
const handleMouseDown = (event) => {
isDragging = true;
dragStart = {
x: event.clientX - smallImagePosition.value.x,
y: event.clientY - smallImagePosition.value.y,
};
};
const handleMouseMove = (event) => {
if (!isDragging) return;
const largeImage = largeImageRef.value;
const smallImage = smallImageRef.value;
const smallImageWidth = smallImage.width;
const smallImageHeight = smallImage.height;
let newX = event.clientX - dragStart.x;
let newY = event.clientY - dragStart.y;
// 边界限制,考虑小图片的大小
newX = Math.max(0, Math.min(newX, largeImage.width - smallImageWidth));
newY = Math.max(0, Math.min(newY, largeImage.height - smallImageHeight));
smallImagePosition.value = { x: newX, y: newY };
};
const handleMouseUp = () => {
isDragging = false;
};
const saveAsImage = async () => {
const largeImage = largeImageRef.value;
const smallImage = smallImageRef.value;
// 获取大图片的缩放比例
const scaleX = largeImage.naturalWidth / largeImage.width;
const scaleY = largeImage.naturalHeight / largeImage.height;
const canvas = document.createElement("canvas");
canvas.width = largeImage.naturalWidth;
canvas.height = largeImage.naturalHeight;
const ctx = canvas.getContext("2d");
// 绘制大图片
ctx.drawImage(largeImage, 0, 0);
// 计算小图片在Canvas上的缩放后位置
const scaledX = smallImagePosition.value.x * scaleX;
const scaledY = smallImagePosition.value.y * scaleY;
// 绘制小图片
ctx.drawImage(
smallImage,
scaledX,
scaledY,
smallImage.width * scaleX, // 小图片的缩放宽度
smallImage.height * scaleY // 小图片的缩放高度
);
const dataUrl = canvas.toDataURL("image/png");
const link = document.createElement("a");
link.href = dataUrl;
link.download = "combined-image.png";
link.click();
};
onMounted(() => {
const saveButton = document.createElement("button");
saveButton.innerText = "下载";
saveButton.onclick = saveAsImage;
document.body.appendChild(saveButton);
});
return {
largeImageUrl,
smallImageUrl,
smallImagePosition,
largeImageRef,
smallImageRef,
handleMouseDown,
handleMouseMove,
handleMouseUp,
};
},
};
</script>
<style scoped>
.image-container {
position: relative;
width: 350px;
height: 450px;
}
.large-image {
width: 100%;
height: 100%;
}
.small-image {
position: absolute;
cursor: move;
}
</style>
2. 拖拽小图片
使用 ref
来引用大图片和小图片,并通过监听鼠标事件来实现拖拽功能。
handleMouseDown
: 当用户按下鼠标左键时,记录拖拽起点的位置。handleMouseMove
: 当用户移动鼠标时,更新小图片的位置,并限制其在大图片范围内移动。handleMouseUp
: 当用户释放鼠标左键时,停止拖拽。
3. 下载合并后的图片
使用 HTML5 Canvas 来绘制合并后的图片,并提供下载功能。
saveAsImage
: 创建一个 Canvas 元素,绘制大图片和小图片,然后将 Canvas 内容转换为 Data URL,并生成一个下载链接。
4. 添加下载按钮
在组件挂载完成后,动态创建一个下载按钮并添加到页面中。
onMounted(() => {
const saveButton = document.createElement("button");
saveButton.innerText = "下载";
saveButton.onclick = saveAsImage;
document.body.appendChild(saveButton);
});