微信小程序相机组件wx.createCameraContext()的使用模拟微信拍照-后端为nodejs

在本文 微信小程序相机组件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://mp.weixin.qq.com/debug/wxadoc/dev/component/camera.html
https://mp.weixin.qq.com/debug/wxadoc/dev/api/api-camera.html

意外金喜的博客:http://blog.csdn.net/zzwwjjdj1



展开阅读全文

Git 实用技巧

11-24
这几年越来越多的开发团队使用了Git,掌握Git的使用已经越来越重要,已经是一个开发者必备的一项技能;但很多人在刚开始学习Git的时候会遇到很多疑问,比如之前使用过SVN的开发者想不通Git提交代码为什么需要先commit然后再去push,而不是一条命令一次性搞定; 更多的开发者对Git已经入门,不过在遇到一些代码冲突、需要恢复Git代码时候就不知所措,这个时候哪些对 Git掌握得比较好的少数人,就像团队中的神一样,在队友遇到 Git 相关的问题的时候用各种流利的操作来帮助队友于水火。 我去年刚加入新团队,发现一些同事对Git的常规操作没太大问题,但对Git的理解还是比较生疏,比如说分支和分支之间的关联关系、合并代码时候的冲突解决、提交代码前未拉取新代码导致冲突问题的处理等,我在协助处理这些问题的时候也记录各种问题的解决办法,希望整理后通过教程帮助到更多对Git操作进阶的开发者。 本期教程学习方法分为“掌握基础——稳步进阶——熟悉协作”三个层次。从掌握基础的 Git的推送和拉取开始,以案例进行演示,分析每一个步骤的操作方式和原理,从理解Git 工具的操作到学会代码存储结构、演示不同场景下Git遇到问题的不同处理方案。循序渐进让同学们掌握Git工具在团队协作中的整体协作流程。 在教程中会通过大量案例进行分析,案例会模拟在工作中遇到的问题,从最基础的代码提交和拉取、代码冲突解决、代码仓库的数据维护、Git服务端搭建等。为了让同学们容易理解,对Git简单易懂,文章中详细记录了详细的操作步骤,提供大量演示截图和解析。在教程的最后部分,会从提升团队整体效率的角度对Git工具进行讲解,包括规范操作、Gitlab的搭建、钩子事件的应用等。 为了让同学们可以利用碎片化时间来灵活学习,在教程文章中大程度降低了上下文的依赖,让大家可以在工作之余进行学习与实战,并同时掌握里面涉及的Git不常见操作的相关知识,理解Git工具在工作遇到的问题解决思路和方法,相信一定会对大家的前端技能进阶大有帮助。
©️2020 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值