vue实现图片上传封面
图片上传与封面设置实现
前端部分(Vue.js)
使用<input type="file">元素配合FileReaderAPI实现图片预览功能,通过FormData对象处理文件上传。
<template>
<div>
<input type="file" @change="handleFileChange" accept="image/*">
<img :src="previewUrl" v-if="previewUrl" class="preview-image">
<button @click="uploadImage" :disabled="!selectedFile">设为封面</button>
</div>
</template>
<script>
export default {
data() {
return {
selectedFile: null,
previewUrl: ''
}
},
methods: {
handleFileChange(event) {
const file = event.target.files[0];
if (file && file.type.match('image.*')) {
this.selectedFile = file;
const reader = new FileReader();
reader.onload = (e) => {
this.previewUrl = e.target.result;
};
reader.readAsDataURL(file);
}
},
async uploadImage() {
const formData = new FormData();
formData.append('image', this.selectedFile);
try {
const response = await axios.post('/api/upload', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
});
this.$emit('cover-updated', response.data.url);
} catch (error) {
console.error('上传失败:', error);
}
}
}
}
</script>
<style>
.preview-image {
max-width: 300px;
max-height: 200px;
margin-top: 10px;
}
</style>
后端处理(Node.js示例)
使用multer中间件处理文件上传,保存到指定目录并返回文件路径。
const express = require('express');
const multer = require('multer');
const path = require('path');
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'uploads/');
},
filename: (req, file, cb) => {
cb(null, Date.now() + path.extname(file.originalname));
}
});
const upload = multer({ storage });
app.post('/api/upload', upload.single('image'), (req, res) => {
if (!req.file) {
return res.status(400).send('未上传文件');
}
res.json({ url: `/uploads/${req.file.filename}` });
});
图片裁剪与压缩优化
使用cropper.js实现客户端图片裁剪,减少服务器压力。
<div ref="imageContainer">
<img :src="previewUrl" id="image-to-crop">
</div>
<button @click="cropImage">确认裁剪</button>
<script>
import Cropper from 'cropperjs';
import 'cropperjs/dist/cropper.css';
export default {
mounted() {
if (this.previewUrl) {
this.initCropper();
}
},
methods: {
initCropper() {
const image = document.getElementById('image-to-crop');
this.cropper = new Cropper(image, {
aspectRatio: 16/9,
viewMode: 1
});
},
cropImage() {
this.cropper.getCroppedCanvas().toBlob((blob) => {
this.selectedFile = new File([blob], 'cropped.jpg', { type: 'image/jpeg' });
this.previewUrl = URL.createObjectURL(blob);
}, 'image/jpeg', 0.8);
}
}
}
</script>
多图上传与封面选择
扩展组件支持多文件上传和封面选择功能。
<template>
<div>
<input type="file" multiple @change="handleFilesChange" accept="image/*">
<div class="image-list">
<div v-for="(img, index) in images" :key="index" @click="selectCover(index)">
<img :src="img.preview" class="thumbnail" :class="{ 'selected': img.isCover }">
</div>
</div>
<button @click="uploadImages">确认上传</button>
</div>
</template>
<script>
export default {
data() {
return {
images: []
}
},
methods: {
handleFilesChange(event) {
this.images = [];
Array.from(event.target.files).forEach(file => {
const reader = new FileReader();
reader.onload = (e) => {
this.images.push({
file,
preview: e.target.result,
isCover: false
});
};
reader.readAsDataURL(file);
});
},
selectCover(index) {
this.images.forEach((img, i) => {
img.isCover = i === index;
});
},
uploadImages() {
const coverImage = this.images.find(img => img.isCover);
if (coverImage) {
this.uploadImage(coverImage.file);
}
}
}
}
</script>






