在UniApp中使用Vue3实现微信小程序图片处理功能
下面是一个完整的UniApp组件实现,专门针对微信小程序环境,包含图片压缩、分辨率调整和缩略图生成功能。
完整组件代码
xml
<template>
<view class="image-processor">
<view class="header">
<text class="title">微信小程序图片处理工具</text>
</view>
<view class="upload-area" @click="chooseImage">
<text>点击选择图片</text>
</view>
<view v-if="originalImage" class="controls">
<view class="control-group">
<text>压缩质量 (0-100):</text>
<slider :value="quality" min="0" max="100" @change="onQualityChange" show-value />
</view>
<view class="control-group">
<text>最大宽度:</text>
<input type="number" v-model="maxWidth" min="100" />
</view>
<view class="control-group">
<text>最大高度:</text>
<input type="number" v-model="maxHeight" min="100" />
</view>
<view class="control-group">
<text>缩略图尺寸:</text>
<input type="number" v-model="thumbnailSize" min="50" />
</view>
<button @click="processImage" type="primary">处理图片</button>
</view>
<view v-if="processedImage" class="results">
<view class="image-container">
<text class="subtitle">原始图片 ({{ originalSize }})</text>
<image :src="originalImage" mode="widthFix" class="original" />
</view>
<view class="image-container">
<text class="subtitle">处理后图片 ({{ processedSize }})</text>
<image :src="processedImage" mode="widthFix" class="processed" />
</view>
<view class="image-container" v-if="thumbnailImage">
<text class="subtitle">缩略图 ({{ thumbnailSize }}px)</text>
<image :src="thumbnailImage" mode="widthFix" class="thumbnail" />
</view>
<button @click="saveImage" type="primary" class="download-btn">保存到相册</button>
</view>
<canvas canvas-id="thumbnailCanvas" style="position: absolute; left: -9999px; width: 300px; height: 300px;"></canvas>
</view>
</template>
js
ini
import { ref } from 'vue';
const originalImage = ref(null);
const processedImage = ref(null);
const thumbnailImage = ref(null);
const quality = ref(80);
const maxWidth = ref(800);
const maxHeight = ref(600);
const thumbnailSize = ref(200);
const originalSize = ref('');
const processedSize = ref('');
const tempFilePath = ref('');
const chooseImage = async () => {
try {
const res = await uni.chooseImage({
count: 1,
sourceType: ['album', 'camera'],
sizeType: ['original', 'compressed'] });
if (res.tempFilePaths.length > 0) {
tempFilePath.value = res.tempFilePaths[0];
originalImage.value = tempFilePath.value; // 获取文件信息
const fileInfo = await uni.getFileInfo({
filePath: tempFilePath.value
});
originalSize.value = formatFileSize(fileInfo.size);
} } catch (error) {
uni.showToast({
title: '选择图片失败', icon: 'none'
});
console.error(error);
} };
const onQualityChange = (e) => {
quality.value = e.detail.value;
};
const processImage = async () => {
if (!originalImage.value) return;
uni.showLoading({title: '处理中...' });
try { // 压缩并调整尺寸
const compressedRes = await uni.compressImage({
src: tempFilePath.value,
quality: quality.value,
width: maxWidth.value,
height: maxHeight.value
});
processedImage.value = compressedRes.tempFilePath;
// 获取处理后文件大小
const fileInfo = await uni.getFileInfo({ filePath: compressedRes.tempFilePath
});
processedSize.value = formatFileSize(fileInfo.size);
// 生成缩略图
await generateThumbnail(compressedRes.tempFilePath);uni.hideLoading();
} catch (error) {
uni.hideLoading();
uni.showToast({
title: '图片处理失败', icon: 'none'
}); console.error(error); } };
const generateThumbnail = async (filePath) => {
try {
// 使用canvas生成缩略图
const ctx = uni.createCanvasContext('thumbnailCanvas', this);
// 获取图片信息
const imgInfo = await new Promise((resolve, reject) => {
uni.getImageInfo({
src: filePath, success: resolve, fail: reject });
});
// 计算缩略图尺寸,保持宽高比
let width = thumbnailSize.value;
let height = (imgInfo.height / imgInfo.width) * width;
// 绘制缩略图
ctx.drawImage(filePath, 0, 0, width, height);
// 将canvas转为临时文件
const tempFile = await new Promise((resolve, reject) => {
ctx.draw(false, () => {
uni.canvasToTempFilePath({
canvasId: 'thumbnailCanvas', quality: 0.7, success: resolve, fail: reject
}, this); }); });
thumbnailImage.value = tempFile.tempFilePath;
} catch (error) {
console.error('生成缩略图失败:', error);
} };
const saveImage = async () => {
if (!processedImage.value) return;
try { await uni.saveImageToPhotosAlbum({ filePath: processedImage.value
});
uni.showToast({ title: '保存成功', icon: 'success' }); }
catch (error) { uni.showToast({ title: '保存失败', icon: 'none' });
console.error(error); } };
const formatFileSize = (bytes) => {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; }; ;
css
xml
<style lang="scss">
.image-processor {
padding: 20rpx;
font-family: -apple-system, BlinkMacSystemFont,
'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell,
'Open Sans', 'Helvetica Neue', sans-serif;
}
.header {
margin-bottom: 30rpx;
text-align: center;
}
.title {
font-size: 36rpx;
font-weight: bold;
}
.upload-area {
margin: 30rpx 0;
padding: 40rpx;
border: 2rpx dashed #ccc;
border-radius: 10rpx;
text-align: center;
color: #666;
}
.controls {
margin: 30rpx 0;
padding: 20rpx;
background: #f5f5f5;
border-radius: 10rpx;
}
.control-group {
margin-bottom: 20rpx;
text{
display: block;
margin-bottom: 10rpx;
font-size: 28rpx;
}
input {
border: 1rpx solid #ddd;
padding: 10rpx;
border-radius: 5rpx;
width: 100%;
} }
.results {
margin-top: 30rpx;
}
.image-container {
margin-bottom: 30rpx;
border: 1rpx solid #eee;
padding: 20rpx;
border-radius: 10rpx;
}
.subtitle {
display: block;
margin-bottom: 15rpx;
font-size: 28rpx;
font-weight: bold;
}
.original {
border: 4rpx solid #1890ff;
}
.processed {
border: 4rpx solid #52c41a;
}
.thumbnail {
border: 4rpx solid #faad14;
}
.download-btn {
margin-top: 30rpx;
}
</style>
-
API差异处理:
- 使用
uni.chooseImage
代替浏览器文件选择 - 使用
uni.compressImage
进行图片压缩 - 使用
uni.canvasToTempFilePath
将canvas转为图片
- 使用
-
性能优化:
- 使用微信小程序的原生压缩API,性能更好
- 隐藏的canvas用于生成缩略图,不影响界面
-
权限处理:
- 需要在小程序配置中声明相册权限
- 处理用户拒绝授权的情况