• vue制作拍照、录像功能


    使用vue制作出来相机的功能:照相、录视频

    废话不多说,直接上代码!

    布局:

    1. <template>
    2. <div>
    3. <video ref="video" autoplay>video>
    4. <canvas ref="canvas" width="64" height="48">canvas>
    5. <div class="footer">
    6. <div class="font"><b>{{ content }}b>div>
    7. <div class="but">
    8. <input type="file" id="file">
    9. <label for="file"><img src="../assets/img.png" alt="">label>
    10. <div @touchstart="gtouchstart()" @touchmove="gtouchmove()" @touchend="showDeleteButton()" class="lick">
    11. <p class="li">p>
    12. div>
    13. <img @click='changeDevice' src="../assets/look.png" alt="">
    14. div>
    15. div>
    16. <div>
    17. <button @click="getCamera" style="margin-right: 10px;">开启摄像头button>
    18. <button @click="closeCamera">关闭摄像头button>
    19. div>
    20. <a id="downLoadLink" style="display: none;">a>
    21. div>
    22. template>

    CSS样式:

    1. <style scoped>
    2. video {
    3. width: 100%;
    4. height: 60vh;
    5. background-color: black;
    6. }
    7. #file {
    8. display: none;
    9. }
    10. .font {
    11. width: 100%;
    12. text-align: center;
    13. font-size: 15px;
    14. color: #667E6E;
    15. margin-bottom: 20px;
    16. }
    17. .footer {
    18. width: 90%;
    19. height: 23vh;
    20. margin-left: 5%;
    21. position: fixed;
    22. bottom: 0;
    23. z-index: 10;
    24. background-color: white;
    25. }
    26. .but {
    27. display: flex;
    28. justify-content: space-around;
    29. }
    30. .lick {
    31. width: 70px;
    32. height: 70px;
    33. line-height: 70px;
    34. border-radius: 50%;
    35. background-color: #E6E6E6;
    36. /* text-align: center; */
    37. }
    38. .li {
    39. width: 30px;
    40. height: 30px;
    41. line-height: 30px;
    42. background-color: #B7B7B7;
    43. border-radius: 50%;
    44. margin: 20px 0 0 20px;
    45. }
    46. input {
    47. width: 50px;
    48. }
    49. img {
    50. width: 40px;
    51. height: 40px;
    52. margin-top: 15px;
    53. }
    54. style>

    脚本:

    1. <script>
    2. export default {
    3. data() {
    4. return {
    5. videoArr: [],//所有的摄像头,也可以加入音频设备
    6. modelSel: '',//当前使用的摄像头
    7. myInterval: null,
    8. mediaStreamTrack: {}, // 退出时关闭摄像头
    9. video_stream: '', // 视频stream
    10. recordedBlobs: [], // 视频音频 blobs
    11. isRecord: false, // 视频是否正在录制
    12. content: '按住拍摄,点击拍照'
    13. }
    14. },
    15. created() {
    16. this.changeDevice();
    17. },
    18. mounted() {
    19. this.getCamera();
    20. },
    21. methods: {
    22. getCamera() {
    23. // 旧版本浏览器可能根本不支持mediaDevices,我们首先设置一个空对象
    24. if (navigator.mediaDevices === undefined) {
    25. navigator.mediaDevices = {};
    26. }
    27. navigator.mediaDevices
    28. .getUserMedia({
    29. video: true,
    30. })
    31. .then((stream) => {
    32. // 摄像头开启成功
    33. this.mediaStreamTrack = typeof stream.stop === 'function' ? stream : stream.getTracks()[0];
    34. this.video_stream = stream;
    35. this.$refs.video.srcObject = stream;
    36. this.$refs.video.play();
    37. })
    38. .catch(err => {
    39. console.log(err);
    40. });
    41. },
    42. //长按事件(起始) 返回按钮--------------------------------------------------------------------------------------------
    43. gtouchstart() {
    44. var self = this;
    45. this.timeOutEvent = setTimeout(function () {
    46. self.longPress();
    47. }, 500); //这里设置定时器,定义长按500毫秒触发长按事件
    48. return false;
    49. },
    50. //手释放,如果在500毫秒内就释放,则取消长按事件,此时可以执行onclick应该执行的事件
    51. showDeleteButton() {
    52. clearTimeout(this.timeOutEvent); //清除定时器
    53. if (this.timeOutEvent != 0) { //这里写要执行的内容(如onclick事件)点击未长按
    54. this.returns = true
    55. setTimeout(() => {
    56. this.uploadImg()
    57. }, 100);
    58. } else { //长按后松开要执行的内容
    59. this.returns = false
    60. this.stop()
    61. this.content = '按住拍摄,点击拍照'
    62. }
    63. return false;
    64. },
    65. //如果手指有移动,则取消所有事件,此时说明用户只是要移动而不是长按
    66. gtouchmove() {
    67. clearTimeout(this.timeOutEvent); //清除定时器
    68. this.timeOutEvent = 0;
    69. console.log("移动");
    70. },
    71. //真正长按后应该执行的内容
    72. longPress() { //执行长按要执行的内容,如弹出菜单
    73. this.timeOutEvent = 0;
    74. this.returns = true
    75. this.record();
    76. this.content = '视频录制中'
    77. console.log("长按");
    78. },
    79. // 拍照--------------------------------------------------------------------------------------------------------------------
    80. uploadImg() {
    81. let ctx = this.$refs['canvas'].getContext('2d');
    82. ctx.drawImage(this.$refs['video'], 0, 0, 64, 48);
    83. // let imgBase64 = this.$refs['canvas'].toDataURL('image/jpeg', 0.7);
    84. console.log(this.$refs['canvas']);
    85. },
    86. closeCamera() {
    87. if (!this.$refs['video'].srcObject) return;
    88. let stream = this.$refs['video'].srcObject;
    89. let tracks = stream.getTracks();
    90. tracks.forEach(track => {
    91. track.stop();
    92. });
    93. this.$refs['video'].srcObject = null;
    94. },
    95. changeDevice() {
    96. navigator.mediaDevices.enumerateDevices().then((devices) => {
    97. this.videoArr = [];
    98. devices.forEach((device) => {
    99. //音频是audioautput 摄像头videoinput
    100. if (device.kind == 'videoinput') {
    101. this.videoArr.push({
    102. 'label': device.label,
    103. 'id': device.deviceId
    104. })
    105. }
    106. });
    107. })
    108. },
    109. setCurrentDevice(val) {
    110. const videoConstraints = {};
    111. if (val === '') {
    112. videoConstraints.facingMode = 'environment';
    113. } else {
    114. videoConstraints.deviceId = { exact: val };
    115. }
    116. var constraints = {
    117. video: videoConstraints,
    118. };
    119. this.getUserMedia(constraints);
    120. },
    121. getUserMedia(constraints, success, error) {
    122. if (navigator.mediaDevices.getUserMedia) {
    123. //最新的标准API
    124. navigator.mediaDevices.getUserMedia(constraints).then(success => {
    125. // 摄像头开启成功
    126. this.$refs['video'].srcObject = success
    127. // 实时拍照效果
    128. this.$refs['video'].play()
    129. }).catch(error);
    130. } else if (navigator.webkitGetUserMedia) {
    131. //webkit核心浏览器
    132. navigator.webkitGetUserMedia(constraints, success, error)
    133. } else if (navigator.mozGetUserMedia) {
    134. //firfox浏览器
    135. navigator.mozGetUserMedia(constraints, success, error);
    136. } else if (navigator.getUserMedia) {
    137. //旧版API
    138. navigator.getUserMedia(constraints, success, error);
    139. }
    140. },
    141. // 视频录制----------------------------------------------------------------------------------------------------------------------
    142. record() {
    143. console.log('record');
    144. this.isRecord = !this.isRecord;
    145. let mediaRecorder;
    146. let options;
    147. this.recordedBlobs = [];
    148. if (typeof MediaRecorder.isTypeSupported === 'function') {
    149. // 根据浏览器来设置编码参数
    150. if (MediaRecorder.isTypeSupported('video/webm;codecs=vp9')) {
    151. options = {
    152. MimeType: 'video/webm;codecs=h264',
    153. };
    154. } else if (MediaRecorder.isTypeSupported('video/webm;codecs=h264')) {
    155. options = {
    156. MimeType: 'video/webm;codecs=h264',
    157. };
    158. } else if (MediaRecorder.isTypeSupported('video/webm;codecs=vp8')) {
    159. options = {
    160. MimeType: 'video/webm;codecs=vp8',
    161. };
    162. }
    163. mediaRecorder = new MediaRecorder(this.video_stream, options);
    164. } else {
    165. // console.log('isTypeSupported is not supported, using default codecs for browser');
    166. console.log('当前不支持isTypeSupported,使用浏览器的默认编解码器');
    167. mediaRecorder = new MediaRecorder(this.video_stream);
    168. }
    169. mediaRecorder.start();
    170. // 视频录制监听事件
    171. mediaRecorder.ondataavailable = e => {
    172. console.log(e);
    173. // 录制的视频数据有效
    174. if (e.data && e.data.size > 0) {
    175. this.recordedBlobs.push(e.data);
    176. }
    177. };
    178. // 停止录像后增加下载视频功能,将视频流转为mp4格式
    179. mediaRecorder.onstop = () => {
    180. const blob = new Blob(this.recordedBlobs, { type: 'video/mp4' });
    181. this.recordedBlobs = [];
    182. // 将视频链接转换完可以用于在浏览器上预览的本地视频
    183. const videoUrl = window.URL.createObjectURL(blob);
    184. // 设置下载链接
    185. document.getElementById('downLoadLink').href = videoUrl;
    186. // 设置下载mp4格式视频
    187. document.getElementById('downLoadLink').download = 'media.mp4';
    188. document.getElementById('downLoadLink').innerHTML = 'DownLoad video file';
    189. // 生成随机数字
    190. const rand = Math.floor((Math.random() * 1000000));
    191. // 生成视频名
    192. const name = `video${rand}.mp4`;
    193. // setAttribute() 方法添加指定的属性,并为其赋指定的值
    194. document.getElementById('downLoadLink').setAttribute('download', name);
    195. document.getElementById('downLoadLink').setAttribute('name', name);
    196. // 0.5s后自动下载视频
    197. setTimeout(() => {
    198. document.getElementById('downLoadLink').click();
    199. }, 500);
    200. };
    201. },
    202. // 停止录制----------------------------------------------------------------------------------------------------------------------
    203. stop() {
    204. this.isRecord = !this.isRecord;
    205. if (!this.$refs.video.srcObject) return;
    206. const stream = this.$refs.video.srcObject;
    207. const tracks = stream.getTracks();
    208. // 关闭摄像头和音频
    209. tracks.forEach(track => {
    210. track.stop();
    211. });
    212. },
    213. }
    214. }
    215. script>

  • 相关阅读:
    虚拟机安装Kali Linux操作系统
    《算法竞赛进阶指南》破坏正方形
    水溶性,非反应性,含有游离羧酸功能----cy染料 近红外荧光亲水CY7 COOH;Sulfo-CY5/CY7 COOH
    Java学习笔记3.10.2 异常处理 - 异常捕获
    网段与广播域
    【开源】嵌入式微服务框架MAES
    Tomcat 开启远程调试
    Google Hacking搜索
    网站打不开的九个因素
    Python 自动化: eip、cen监控数据对接到 grafana
  • 原文地址:https://blog.csdn.net/dxn16638400024/article/details/134428707