Building an Image Resizer Component with Vue and DaisyUI
In this tutorial, we’ll create a practical image resizer component using Vue 3 and DaisyUI. This component allows users to upload images and automatically convert them into various common sizes, perfect for scenarios where different image dimensions are needed.
Live Demo
拖拽图片到这里或点击上传
Features
- Drag and drop image upload
- Original image preview
- Convert to multiple preset sizes
- Download converted images
- Elegant user interface
Prerequisites
First, ensure your project has the necessary dependencies installed:
npm install vue@3
npm install daisyui
npm install tailwindcss
Component Code
Create a new component file ImageResizer.vue:
<template>
<div class="container mx-auto p-4">
<!-- Upload Area -->
<div
class="border-2 border-dashed border-gray-300 rounded-lg p-8 text-center"
@drop.prevent="handleDrop"
@dragover.prevent
@click="triggerFileInput"
>
<input
type="file"
ref="fileInput"
class="hidden"
accept="image/*"
@change="handleFileSelect"
/>
<div v-if="!selectedImage" class="text-gray-500">
<i class="fas fa-cloud-upload-alt text-3xl mb-2"></i>
<p>Drag and drop an image here or click to upload</p>
</div>
<img v-else :src="selectedImage" class="max-w-md mx-auto rounded-lg shadow" />
</div>
<!-- Preset Size Options -->
<div v-if="selectedImage" class="mt-8">
<h3 class="text-lg font-semibold mb-4">Select Target Size:</h3>
<div class="grid grid-cols-2 md:grid-cols-3 gap-4">
<button
v-for="size in presetSizes"
:key="size.name"
class="btn btn-primary"
@click="resizeImage(size.width, size.height)"
>
{{ size.name }} ({{ size.width }}x{{ size.height }})
</button>
</div>
</div>
<!-- Converted Images Display -->
<div v-if="resizedImages.length" class="mt-8">
<h3 class="text-lg font-semibold mb-4">Conversion Results:</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div
v-for="(image, index) in resizedImages"
:key="index"
class="card bg-base-100 shadow-xl"
>
<figure class="px-4 pt-4">
<img :src="image.url" class="rounded-xl" />
</figure>
<div class="card-body">
<h2 class="card-title">{{ image.width }}x{{ image.height }}</h2>
<div class="card-actions justify-end">
<button
class="btn btn-primary"
@click="downloadImage(image.url, image.width, image.height)"
>
Download
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue';
import ReferenceAnswer from '@/components/common/ReferenceAnswer.vue';
const fileInput = ref(null);
const selectedImage = ref(null);
const resizedImages = ref([]);
// Preset sizes
const presetSizes = [
{ name: 'Social Media Cover', width: 1200, height: 630 },
{ name: 'WeChat Avatar', width: 132, height: 132 },
{ name: 'Instagram Square', width: 1080, height: 1080 },
{ name: 'Mobile Wallpaper', width: 1080, height: 1920 },
];
// Trigger file selection
const triggerFileInput = () => {
fileInput.value.click();
};
// Handle file selection
const handleFileSelect = event => {
const file = event.target.files[0];
if (file) {
loadImage(file);
}
};
// Handle drag and drop
const handleDrop = event => {
const file = event.dataTransfer.files[0];
if (file && file.type.startsWith('image/')) {
loadImage(file);
}
};
// Load image
const loadImage = file => {
const reader = new FileReader();
reader.onload = e => {
selectedImage.value = e.target.result;
resizedImages.value = []; // Clear previous results
};
reader.readAsDataURL(file);
};
// Resize image
const resizeImage = (targetWidth, targetHeight) => {
const img = new Image();
img.src = selectedImage.value;
img.onload = () => {
const canvas = document.createElement('canvas');
canvas.width = targetWidth;
canvas.height = targetHeight;
const ctx = canvas.getContext('2d');
// Use white background
ctx.fillStyle = '#FFFFFF';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Calculate scale and position to maintain aspect ratio
const scale = Math.min(targetWidth / img.width, targetHeight / img.height);
const x = (targetWidth - img.width * scale) / 2;
const y = (targetHeight - img.height * scale) / 2;
ctx.drawImage(img, x, y, img.width * scale, img.height * scale);
const resizedUrl = canvas.toDataURL('image/jpeg', 0.9);
resizedImages.value.push({
url: resizedUrl,
width: targetWidth,
height: targetHeight,
});
};
};
// Download image
const downloadImage = (dataUrl, width, height) => {
const link = document.createElement('a');
link.download = `resized-${width}x${height}.jpg`;
link.href = dataUrl;
link.click();
};
</script>
Usage Instructions
-
Upload Image:
- Click the upload area to select an image file
- Or drag and drop an image directly into the upload area
-
Select Target Size:
- After uploading an image, you’ll see preset size options
- Click the desired size button to convert
-
View and Download:
- Converted images will appear below
- Each conversion result has preview and download buttons
Key Implementation Details
1. Image Upload Handling
The component supports two upload methods: click-to-select and drag-and-drop. It uses the FileReader API to read image files:
const loadImage = (file) => {
const reader = new FileReader()
reader.onload = (e) => {
selectedImage.value = e.target.result
resizedImages.value = []
}
reader.readAsDataURL(file)