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'
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)