下面是对于“Vue.js 2.0 移动端拍照压缩图片上传预览功能”的完整攻略:
目标技术点
在实现 Vue.js 移动端拍照压缩图片上传预览功能时,需要掌握以下技能点:
- Vue.js 2.x
- 移动端兼容性问题的解决方案
- HTML5 FormData
- HTML5 File API
- Image resize(图片压缩)
目标功能实现
实现以上技术点后,即可实现以下功能:
- 通过移动端在线拍照,支持对图片进行任意尺寸的压缩;
- 支持上传被压缩后的图片至服务器,通过Ajax获取到图片资源并显示;
- 通过Vuetify库提供的卡片,实现简单美观的图片展示功能。
实现步骤
以下是Vue.js移动端拍照压缩图片上传预览功能的完整步骤:
第1步:库导入
使用Vue.js 2.x版本,我们可以简单地通过CDN导入Vue.js和Vuetify库的相关文件:
<!-- Vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!-- Vuetify CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vuetify/dist/vuetify.min.css">
<!-- Vuetify JavaScript -->
<script src="https://cdn.jsdelivr.net/npm/vuetify/dist/vuetify.min.js"></script>
第2步:创建Vue实例
在Vue实例中添加数据和方法等属性,用于实现移动端拍照、压缩图片上传和预览功能:
new Vue({
el: '#app',
vuetify: new Vuetify(),
data() {
return {
imgData: '', // 图片上传后的二进制数据
imgURL: '', // 图片预览地址
msg: '' // 错误提示信息
};
},
methods: {
// 拍照并压缩图片,最终上传数据
uploadImage() {
let that = this;
let formData = new FormData();
// 获取拍照数据
let imgData = this.imgData.split(',')[1];
// 压缩图片,最大宽度为800像素
let imgBlob = this.dataURItoBlob(this.imgData);
let imgFile = this.blobToFile(imgBlob, Date.now() + '.jpg');
// 添加二进制图片文件到FormData中
formData.append('imgFile', imgFile);
// 发起Ajax上传请求,获取上传后的文件地址
// 省略Ajax代码
// 清空图片预览和二进制数据
this.imgURL = '';
this.imgData = '';
},
// 将DataURI转换为Blob类型的二进制数据
dataURItoBlob(dataURI) {
let byteString = atob(dataURI.split(',')[1]);
let mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
let ab = new ArrayBuffer(byteString.length);
let ia = new Uint8Array(ab);
for (let i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ab], { type: mimeString });
},
// 将Blob类型的文件数据转换为File类型
// fileName:新生成的文件名称
blobToFile(blob, fileName) {
blob.lastModifiedDate = new Date();
blob.name = fileName;
return <File>blob;
},
// 获取拍照并压缩后的图片预览地址
takePicture() {
let that = this;
// 相机初始化
let video = document.querySelector('video');
let canvas = document.querySelector('canvas');
const constraints = {
video: { width: 300, height: 300 }
};
// 获取摄像头数据
navigator.mediaDevices.getUserMedia(constraints).then((stream) => {
video.srcObject = stream;
// video.play();
});
// 拍照并压缩后显示图片预览
setTimeout(function () {
let ctx = canvas.getContext('2d');
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
that.imgURL = canvas.toDataURL('image/png', 0.8);
// 获取最终上传的数据,DataURI格式
that.imgData = that.imgURL.replace(/^[^,]+,/, '');
}, 500);
},
// 重置数据
clearData() {
this.imgURL = '';
this.imgData = '';
this.msg = '';
}
}
});
第3步:在Vue模板中使用Vuetify卡片显示并调用方法
接下来,在Vue的模板中添加HTML代码,实现调用上述方法来实现移动端拍照、压缩图片上传和预览功能。在代码中,我们将调用takePicture()
来获取照片并压缩,然后通过Vuetify卡片将照片预览出来。点击“上传”按钮后,将调用uploadImage()
来将压缩后的数据上传至服务器。
<div id="app">
<v-app>
<v-card width="450" height="450" class="mx-auto my-5">
<v-img :src="imgURL" width="100%" height="300px" class="pt-4"></v-img>
<v-input class="mt-4" label="照片名称" hint="请输入照片名称" v-model.trim="msg" clearable required></v-input>
<v-card-actions>
<v-btn color="primary" @click="takePicture">拍照</v-btn>
<v-btn color="green" @click="uploadImage">上传</v-btn>
<v-btn color="warning" @click="clearData">重置</v-btn>
</v-card-actions>
</v-card>
</v-app>
<!-- 拍照Canvas -->
<div style="display:none;">
<video autoplay></video>
<canvas width="300" height="300"></canvas>
</div>
</div>
第4步:实际应用示例
接下来,我们来看一下两个实际应用的示例:
示例1:与 Node.js 和 Express.js 配合
前端代码:
<!-- index.html -->
<div id="app">
<v-app>
<v-card width="450" height="450" class="mx-auto my-5">
<v-img :src="imgURL" width="100%" height="300px" class="pt-4"></v-img>
<v-input class="mt-4" label="照片名称" hint="请输入照片名称" v-model.trim="msg" clearable required></v-input>
<v-card-actions>
<v-btn color="primary" @click="takePicture">拍照</v-btn>
<v-btn color="green" @click="uploadImage">上传</v-btn>
<v-btn color="warning" @click="clearData">重置</v-btn>
</v-card-actions>
</v-card>
</v-app>
<!-- 拍照Canvas -->
<div style="display:none;">
<video autoplay></video>
<canvas width="300" height="300"></canvas>
</div>
</div>
<!-- Vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!-- Vuetify CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vuetify/dist/vuetify.min.css">
<!-- Vuetify JavaScript -->
<script src="https://cdn.jsdelivr.net/npm/vuetify/dist/vuetify.min.js"></script>
<!-- Axios JavaScript -->
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<!-- Vue.js 代码 -->
<script>
new Vue({
el: '#app',
vuetify: new Vuetify(),
data() {
return {
imgData: '', // 图片上传后的二进制数据
imgURL: '', // 图片预览地址
msg: '' // 错误提示信息
};
},
methods: {
// 拍照并压缩图片,最终上传数据
uploadImage() {
let that = this;
if (this.msg === '') {
this.$message({
type: 'error',
message: '请您输入照片名称'
});
return false;
}
if (this.imgData === '') {
this.$message({
type: 'error',
message: '请您先拍摄照片'
});
return false;
}
let formData = new FormData();
// 获取拍照数据
let imgData = this.imgData.split(',')[1];
// 压缩图片,最大宽度为800像素
let imgBlob = this.dataURItoBlob(this.imgData);
let imgFile = this.blobToFile(imgBlob, Date.now() + '.jpg');
// 添加二进制图片文件到FormData中
formData.append('imgFile', imgFile);
// 通过Axios上传FormData中的数据至Node.js
axios.post('/upload', formData, {
headers: { 'Content-Type': 'multipart/form-data' }
}).then((res) => {
console.log(res);
// 获取上传后的图片资源
axios.get('/getImage/' + res.data.fileID, {
responseType: 'arraybuffer'
}).then((res) => {
console.log(res);
// 显示图片
that.imgURL = 'data:image/png;base64,' + btoa(new Uint8Array(res.data).reduce((data, byte) => data + String.fromCharCode(byte), ''));
that.$message({
type: 'success',
message: '图片上传成功!'
});
}).catch((err) => {
console.log(err);
});
}).catch((err) => {
console.log(err);
});
// 清空图片预览和二进制数据
this.imgURL = '';
this.imgData = '';
},
// 将DataURI转换为Blob类型的二进制数据
dataURItoBlob(dataURI) {
let byteString = atob(dataURI.split(',')[1]);
let mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
let ab = new ArrayBuffer(byteString.length);
let ia = new Uint8Array(ab);
for (let i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ab], { type: mimeString });
},
// 将Blob类型的文件数据转换为File类型
// fileName:新生成的文件名称
blobToFile(blob, fileName) {
blob.lastModifiedDate = new Date();
blob.name = fileName;
return <File>blob;
},
// 获取拍照并压缩后的图片预览地址
takePicture() {
let that = this;
// 相机初始化
let video = document.querySelector('video');
let canvas = document.querySelector('canvas');
const constraints = {
video: { width: 300, height: 300 }
};
// 获取摄像头数据
navigator.mediaDevices.getUserMedia(constraints).then((stream) => {
video.srcObject = stream;
// video.play();
});
// 拍照并压缩后显示图片预览
setTimeout(function () {
let ctx = canvas.getContext('2d');
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
that.imgURL = canvas.toDataURL('image/png', 0.8);
// 获取最终上传的数据,DataURI格式
that.imgData = that.imgURL.replace(/^[^,]+,/, '');
}, 500);
},
// 重置数据
clearData() {
this.imgURL = '';
this.imgData = '';
this.msg = '';
}
}
});
</script>
后台代码:
/* server.js */
const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser');
const multer = require('multer');
const FileType = require('file-type');
const fse = require('fs-extra');
const app = express();
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json({ limit: '100mb' }));
app.use(bodyParser.urlencoded({ limit: '100mb', extended: true }));
app.use(cors({ origin: true }));
// 定义文件上传路径
const uploadPath = './upload/';
// 定义文件上传中间件,限制文件大小为10Mb
const upload = multer({
limits: { fileSize: 10000000 },
storage: multer.diskStorage({
destination: function (req, file, cb) {
cb(null, uploadPath);
},
filename: function (req, file, cb) {
cb(null, Date.now() + '.jpg'); // 把所有的文件都存储为jpg格式
}
})
});
// 定义获取图片资源
app.get('/getImage/:id', (req, res) => {
const id = req.params.id;
const filePath = uploadPath + id + '.jpg';
res.sendFile(filePath);
});
// 定义上传图片
app.post('/upload', upload.single('imgFile'), (req, res) => {
const { originalname, mimetype, size } = req.file;
const index = req.file.filename.split('.')[0];
const ext = req.file.filename.split('.')[1];
// 如果上传的文件不是图片,则返回错误信息
if (mimetype.indexOf('image') < 0) {
return res.status(400).json({ error: '仅支持上传图片数据!' });
}
// 如果上传的文件超过大小限制,则返回错误信息
if (size > 10000000) {
return res.status(400).json({ error: '上传文件不能超过10MB!' });
}
// 返回上传后的文件编号
return res.json({ fileID: index });
});
// 监听端口
app.listen(3000, () => {
console.log('Server is running on http://localhost:3000');
});
在后台代码中,上传了所有的jpg格式的文件,您可以根据自己实际的项目需求来变更配置。
示例2:与PHP后端配合
前端代码:
```html
new Vue({
el: '#app',
vuetify: new Vuetify(),
data() {
return {
imgData: '', // 图片上传后的二进制数据
imgURL: '', // 图片预览地址
msg: '' // 错误提示信息
};
},
methods: {
// 拍照并压缩图片,最终上传数据
uploadImage() {
let that = this;
if (this.msg === '') {
this.$message({
type: 'error',
message: '请您输入照片名称'
});
return false;
}
if (this.imgData === '') {
this.$message({
type: 'error',
message: '请您先拍摄照片'
});
return false;
}
let formData = new FormData();
// 获取拍照数据
let imgData = this.imgData.split(',')[1];
//
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Vue.js 2.0 移动端拍照压缩图片上传预览功能 - Python技术站