在本文 微信小程序相机组件wx.createCameraContext()的使用模拟微信拍照之前需要看看
微信小程序-获取用户session_key,openid,unionid - 后端为nodejs
代码封装是在上文添加的。
本文知识点:
1、微信小程序相机组件wx.createCameraContext()使用
2、微信小程序拍照,录视频实现
3、微信小程序上传文件接口wx.uploadFile()的使用
4、微信小程序wx:if的使用
5、nodejs上传文件multer模块的使用
6、camera组件使用
效果
在笔记本上,没有前后置翻转效果,真机上是有的;
在微信开发工具里camera组件是透明的,真机上没问题;
在微信开发工具里上传的视频格式为webm,真机上为mp4。
小程序代码
1、在utils下的wechat.js文件里添加代码
/**
* 将本地资源上传到开发者服务器,客户端发起一个 HTTPS POST 请求
* @param {string} url 开发者服务器 url
* @param {string} filePath 要上传文件资源的路径
* @param {string} name
* @param {object} formData HTTP 请求中其他额外的 form data
*/
static uploadFile(url, filePath, name, formData = { openid: "test" }) {
return new Promise((resolve, reject) => {
let opts = { url, filePath, name, formData, header: { 'Content-Type': "multipart/form-data" }, success: resolve, fail: reject };
wx.uploadFile(opts);
});
}
js
//index.js
//获取应用实例
let app = getApp();
let wechat = require("../../utils/wechat");
Page({
data: {
device: true,
tempImagePath: "", // 拍照的临时图片地址
tempThumbPath: "", // 录制视频的临时缩略图地址
tempVideoPath: "", // 录制视频的临时视频地址
camera: false,
ctx: {},
type: "takePhoto",
startRecord: false,
time: 0,
timeLoop: "",
},
onLoad() {
this.setData({
ctx: wx.createCameraContext()
})
},
// 切换相机前后置摄像头
devicePosition() {
this.setData({
device: !this.data.device,
})
console.log("当前相机摄像头为:", this.data.device ? "后置" : "前置");
},
camera() {
let { ctx, type, startRecord } = this.data;
// 拍照
if (type == "takePhoto") {
console.log("拍照");
ctx.takePhoto({
quality: "normal",
success: (res) => {
// console.log(res);
this.setData({
tempImagePath: res.tempImagePath,
camera: false,
});
wechat.uploadFile("https://xx.xxxxxx.cn/api/upload", res.tempImagePath, "upload")
.then(d => {
console.log(d);
})
.catch(e => {
console.log(e);
})
},
fail: (e) => {
console.log(e);
}
})
}
// 录视频
else if (type == "startRecord") {
if (!startRecord) {
console.log("开始录视频");
this.setData({
startRecord: true
});
// 30秒倒计时
let t1 = 0;
let timeLoop = setInterval(() => {
t1++;
this.setData({
time: t1,
})
// 最长录制30秒
if (t1 == 30) {
clearInterval(timeLoop);
this.stopRecord(ctx);
}
}, 1000);
this.setData({
timeLoop
})
// 开始录制
ctx.startRecord({
success: (res) => {
console.log(res);
},
fail: (e) => {
console.log(e);
}
})
}
else {
this.stopRecord(ctx);
}
}
},
// 停止录制
stopRecord(ctx) {
console.log("停止录视频");
clearInterval(this.data.timeLoop);
ctx.stopRecord({
success: (res) => {
this.setData({
tempThumbPath: res.tempThumbPath,
tempVideoPath: res.tempVideoPath,
camera: false,
startRecord: false,
time: 0
});
wechat.uploadFile("https://xx.xxxxxx.cn/api/upload", res.tempThumbPath, "tempThumbPath")
.then(d => {
console.log(d);
return wechat.uploadFile("https://xx.xxxxxx.cn/api/upload", res.tempVideoPath, "tempVideoPath")
})
.then(d => {
console.log(d);
})
.catch(e => {
console.log(e);
})
},
fail: (e) => {
console.log(e);
}
})
},
// 打开模拟的相机界面
open(e) {
let { type } = e.target.dataset;
console.log("开启相机准备", type == "takePhoto" ? "拍照" : "录视频");
this.setData({
camera: true,
type
})
},
// 关闭模拟的相机界面
close() {
console.log("关闭相机");
this.setData({
camera: false
})
}
})
html
<view class="view">
<view class="window">
<image class="cover-9" src="{{tempImagePath}}" bindtap="img" wx:if="{{type=='takePhoto'}}"></image>
<video class="cover-9" src="{{tempVideoPath}}" poster="{{tempThumbPath}}" wx:if="{{type=='startRecord'}}"></video>
<view class="window-2">
<button bindtap="open" type="primary" data-type="takePhoto">拍照</button>
<button bindtap="open" type="primary" data-type="startRecord">录制</button>
</view>
</view>
<camera class="camera" device-position="{{device?'back':'front'}}" wx:if="{{camera}}" flash="off">
<cover-view class="cover-1" bindtap="camera">
<cover-view class="cover-2">
<cover-view class="cover-5" wx:if="{{type=='startRecord'&&startRecord}}">{{time}}S</cover-view>
</cover-view>
</cover-view>
<cover-image class="cover-3" src="/images/xx2.png" style="width:60rpx;height:60rpx;" bindtap="close"></cover-image>
<cover-image class="cover-4" src="/images/zh.png" style="width:80rpx;height:60rpx;" bindtap="devicePosition"></cover-image>
</camera>
</view>
css
page{
height: 100%;
}
.view{
width: 100%;
height: 100%;
}
.window{
width: 100%;
height: 100%;
position: absolute;
}
.window-2{
display: flex;
flex-direction: row;
}
.camera{
width: 100%;
height: 100%;
}
.cover-1{
width: 150rpx;
height: 150rpx;
border-radius: 150rpx;
background-color: #dedcdc;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
position: absolute;
bottom: 60rpx;
left: 300rpx;
}
.cover-3{
position: absolute;
bottom: 105rpx;
left:135rpx;
}
.cover-9{
width: 728rpx;
height: 80%;
margin: 0 10rpx;
border:2rpx solid;
border-radius:5px;
}
button{
margin: 0 10rpx;
width: 100%;
}
.cover-4{
position: absolute;
top: 60rpx;
right:40rpx;
}
.cover-2{
width: 110rpx;
height: 110rpx;
border-radius: 110rpx;
background-color: #ffffff;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
color:#da2121;
font-size: 32rpx;
}
nodejs代码
文件上传使用multer模块,引入multer模块后配置好并添加一个上传处理的路由,创建上传的目录,
本文是uploads/tmp目录
const multer = require('multer');
let path = require("path");
//上传文件配置
const storage = multer.diskStorage({
//文件存储位置
destination: (req, file, cb) => {
cb(null, path.resolve(__dirname, '../uploads/tmp/'));
},
//文件名
filename: (req, file, cb) => {
cb(null, `${Date.now()}_${Math.ceil(Math.random() * 1000)}_multer.${file.originalname.split('.').pop()}`);
}
});
const uploadCfg = {
storage: storage,
limits: {
//上传文件的大小限制,单位bytes
fileSize: 1024 * 1024 * 20
}
};
router.post("/api/upload", async (req, res) => {
let upload = multer(uploadCfg).any();
upload(req, res, async (err) => {
if (err) {
res.json({ path: `//uploads/tmp/${uploadFile.filename}` });
console.log(err);
return;
};
console.log(req.files);
let uploadFile = req.files[0];
res.json({ path: `//uploads/tmp/${uploadFile.filename}` });
});
})
后端打印
上传的文件夹
素材
向下箭头:https://img-blog.csdn.net/20180226111545178
翻转图片:https://img-blog.csdn.net/20180226111559273
参考地址:
https://mp.weixin.qq.com/debug/wxadoc/dev/component/camera.html
https://mp.weixin.qq.com/debug/wxadoc/dev/api/api-camera.html