方法一:使用wx.chooseVideo,wx.chooseVideo是微信官方提供的接口,不需要用户授权,可直接调用返回拍摄完的视频地址。

1
2
3
4
5
6
7
8
wx.chooseVideo({
sourceType: ['camera'],
maxDuration: 60,
camera: 'back',
success(res) {
console.log(res.tempFilePath)
}
})

方法二:使用wx.createCameraContext(),自己定义录制方法

注意点:
1.使用该方法需要用户授权摄像头权限和麦克风权限,需要对未授权时的情况进行处理
2.startRecord和stopRecord方法注意调用时机,都不可连续调用,需要对用户连续点击的行为做处理

代码如下:

index.wxml

1
2
3
4
<view class="video">
<video wx:if="{{video}}" src="{{video}}" style="width: 100%;display: block;"></video>
<button type="primary" bindtap="checkSetting">录制视频demo</button>
</view>

index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
const app = getApp()
Page({
data: {
video:null
},
onLoad: function(options) {

},
onShow() {
/**
* 每次进入页面判断本地是否存在录制视频地址,有则取,取完清除
*/
if (wx.getStorageSync('auth_video')) {
this.setData({
video: wx.getStorageSync('auth_video')
})
wx.removeStorageSync('auth_video')
}
},
/**
* 由于录像页面使用了camera标签,使用该标签时需要获取摄像头权限,否则无法捕捉画面
* 所以每次进入页面时先进行检验用户是否授权摄像头权限
*/
checkSetting() {
wx.getSetting({
success: (res) => {
console.log(res)
let authSetting = res.authSetting
/**
* authSetting.hasOwnProperty('scope.camera')==true 说明用户不是首次授权
* authSetting['scope.camera']==false 说明用户未允许授权
* 只有当两个条件同时满足时需要提示用户开启授权
*/
if (authSetting.hasOwnProperty('scope.camera') && !authSetting['scope.camera']) {
wx.showModal({
content: '检测到您当前未开启摄像头权限,将无法使用相机功能',
confirmText: '去开启',
success: (res) => {
if (res.confirm) {
console.log('用户点击确定')
wx.openSetting({
success(res) {
console.log(res.authSetting)
}
});
} else if (res.cancel) {
console.log('用户点击取消')
}
}
})
} else {
wx.navigateTo({
url:"../camera/camera"
})
}
}
})
}
})

camera.wxml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<view class="video">
<view wx:if="{{!video_url}}" style="position: relative;">
<cover-view class="time-container" wx:if="{{isRecording}}">
<cover-view class="time">正在录制 {{time}}s</cover-view>
</cover-view>
<cover-view class="change-btn" wx:else bindtap="changePosition">
<cover-view>点击切换{{devicePosition=='front'?'后置':'前置'}}摄像头</cover-view>
</cover-view>
<camera binderror="getError" device-position="{{devicePosition}}" style="width: 100vw;height: 100vh;"></camera>
<cover-view class="btn-container">
<cover-view class="btn-item" bindtap="back" style="background-color: #ddd;">返回</cover-view>
<cover-view class="btn-item" bindtap="record">{{isRecording?'结束录制':'点击录制'}}</cover-view>
</cover-view>
</view>
<view wx:else style="position: fixed;width: 100vw;height: 100vh;">
<video src="{{video_url}}" style="width: 100%;height: 100%;" autoplay="{{true}}" loop="{{true}}" controls="{{false}}"></video>
<cover-view class="btn-container">
<cover-view class="btn-item" bindtap="recordAgain">重新录制</cover-view>
<cover-view class="btn-item" bindtap="sureVideo">确认选择</cover-view>
</cover-view>
</view>
</view>

camera.wxss

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

.time-container{
position: absolute;
width: 100%;
left:0;
top: 0;
height: 240rpx;
display: flex;
justify-content: center;
align-items: center;
background-color: rgba(0,0,0,0.4);
z-index: 100;
}
.change-btn{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
display: flex;
align-items: center;
height: 100rpx;
color: #fff;
font-size: 30rpx;
padding: 0 50rpx;
border-radius: 50rpx;
z-index: 100;
background-color: rgba(0,0,0,0.5);
}
.time{
font-size: 30rpx;
color: red;
padding: 0 20rpx;
margin-top: 30rpx;
}
.btn-container{
position: absolute;
width: 100%;
padding: 0 80rpx;
box-sizing: border-box;
bottom: 160rpx;
display: flex;
justify-content: space-between;
z-index: 100;
}
.btn-item{
padding: 30rpx 0;
border-radius: 45rpx;
background-color: #FF6685;
color: #fff;
font-size: 32rpx;
text-align: center;
width: 240rpx;
}

camera.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
const app = getApp()
Page({
data: {
ctx: null,
isRecording: false,
video_url: null,
time: 0,
min_time:5, //录制视频最小时长
timer: null,
devicePosition: "back", //摄像头朝向
isStart:false, //记录用户点击开始录制的状态
isStop:false //记录用户点击结束录制的状态
},
onLoad(options) {
const ctx = wx.createCameraContext()
this.setData({
ctx
})
},
onUnload() {
clearInterval(this.data.timer)
},
//切换前置/后置摄像头
changePosition() {
this.setData({
devicePosition: this.data.devicePosition == 'back' ? 'front' : 'back'
})
},
checkSetting() {
//这里定义一个状态isStart来记录用户点击开始录制行为,待startRecord接口请求成功后还原状态
if(this.data.isStart){
return
}
this.data.isStart = true
/**
* 调用wx.createCameraContext().startRecord()方法需要获取用户麦克风权限,否则无法调用且无法录制视频
* 所以每次进入页面时先进行检验用户是否授权麦克风权限
*/
wx.getSetting({
success: (res) => {
console.log(res)
let authSetting = res.authSetting
/**
* 原理同检测摄像头权限
*/
if (authSetting.hasOwnProperty('scope.record') && !authSetting['scope.record']) {
wx.showModal({
content: '检测到您当前未开启麦克风权限,将无法录制视频',
confirmText: '去开启',
success: (res) => {
if (res.confirm) {
console.log('用户点击确定')
wx.openSetting({
success(res) {
console.log(res.authSetting)
}
});
} else if (res.cancel) {
console.log('用户点击取消')
// this.back()
}
}
})
} else {
this.startRecord()
}
}
})
},
//用户进入页面授权时点击不允许授权时触发该方法,且不允许授权后每次进入页面都会直接触发
getError() {
console.log("用户未授权使用摄像头")
this.back()
},
//点击开始录制/结束录制
record() {
if (this.data.isRecording) {
console.log("结束录制视频")
this.stopRecord()
} else {
console.log("开始录制视频")
this.checkSetting()
}
},
//开始录制
startRecord() {
this.data.ctx.startRecord({
timeoutCallback: (res) => {
/**
* 微信官方限制
* 使用该方法录制视频最多录制30s,30s后自动停止录制
* 停止录制计时
*/
console.log("30秒时间结束,自动停止录制")
console.log(res)
clearInterval(this.data.timer)
this.setData({
video_url: res.tempVideoPath,
isRecording: false
})
},
success: (res) => {
console.log(res)
this.timing()
this.setData({
isRecording: true
})
this.data.isStart = false
},
fail:(err)=>{
console.log(err)
this.data.isStart = false
}
})
},
//结束录制
stopRecord() {
//stopRecord方法不可连续调用,否则无法停止录制
//这里定义一个状态isStop来记录用户点击结束录制行为,待stopRecord接口请求成功后还原状态
if(this.data.isStop){
return
}
if(this.data.time<this.data.min_time){
wx.showToast({
title:"视频时长小于"+this.data.min_time+"秒",
icon:"none"
})
return
}
wx.showLoading({
title:"请稍候"
})
this.data.isStop = true
this.data.ctx.stopRecord({
//compressed: false, //是否压缩录完的视频
success: (res) => {
console.log(res)
clearInterval(this.data.timer)
this.setData({
video_url: res.tempVideoPath,
isRecording: false
})
this.data.isStop = false
wx.hideLoading()
},
fail(err){
console.log(err)
this.data.isStop = false
wx.hideLoading()
}
})
},
//计时
timing() {
let time = 0
//每次计时前先将页面上的时间重置为0
this.setData({
time
})
let self = this
let timer = setInterval(function() {
time++
console.log(time)
self.setData({
time
})
}, 1000)
this.setData({
timer
})
},
//重新录制
recordAgain() {
this.setData({
video_url: null
})
},
//返回上一页
back() {
wx.navigateBack()
},
//确认选择
sureVideo() {
/**
* 将录完的视频地址保存本地,返回上一页时在onShow里面判断本地是否存在录制视频的地址
*/
wx.setStorageSync('auth_video', this.data.video_url)
wx.navigateBack()
}
})