当前位置:网站首页>web资源部署后navigator获取不到mediaDevices实例的解决方案(navigator.mediaDevices为undefined)
web资源部署后navigator获取不到mediaDevices实例的解决方案(navigator.mediaDevices为undefined)
2022-07-05 04:05:00 【乐辞】
问题
最近在开发中,有一个功能需要实现录制屏幕的功能,我这边使用了recordrtc库,在过程中本地开发都没有问题,部署到线上环境时出现 navigator.mediaDevices为undefined,查找了不少文章和官方文章才得以解决
原因和解决方案
由于浏览器的安全策略导致了这个问题,目前经尝试,在以下几种情况中 navigator.mediaDevices 可以正常使用
1. 地址为localhost:// 访问时
2. 地址为https:// 时
3. 为文件访问file:///
// 注:如果有其他方案欢迎指正
另附上 recordrtc 使用源码以供参考 (参考源码使用了element UI)
index.vue
<template>
<div>
<button @click="handleScreenRecord">开始录屏</button>
<el-dialog
style="max-width: 60%"
v-model="screenRecorder.dialogVisible"
:before-close="handleClose"
top="0"
>
<Screenrecording
:isSubmitting="screenRecorder.isSubmitting"
@submit="recordedVideoSubmit"
/>
</el-dialog>
</div>
</template>
<script>
import { defineComponent, reactive } from "vue";
import Screenrecording from "./ScreenRecorder.vue";
export default defineComponent({
components: {
Screenrecording,
},
setup() {
const screenRecorder = reactive({
fileurl: "",
dialogVisible: false,
title: "",
isSubmitting: false,
});
const handleScreenRecord = async () => {
screenRecorder.dialogVisible = true;
};
const recordedVideoSubmit = async (file) => {
screenRecorder.isSubmitting = true;
try {
// 拿到录制后的文件 file,这里是处理 file 的业务逻辑
console.log("file", file);
} catch (error) {
// notify.error(error.message)
}
screenRecorder.isSubmitting = false;
};
const handleClose = () => {
screenRecorder.dialogVisible = false;
};
return {
screenRecorder,
handleScreenRecord,
recordedVideoSubmit,
handleClose,
};
},
});
</script>
ScreenRecorder.vue
<template>
<div class="h-recorder-wrapper">
<el-card class="row">
<div class="col-12">
<video
ref="video"
style="width: 100%"
loop
controls
autoplay
playsinline
/>
</div>
<div>
<el-button
ref="startRecord"
@click="startRecord"
:disabled="isSubmitting"
v-show="!recording && !startedBefore"
type="primary"
>
record
</el-button>
<el-button
ref="recordAgain"
@click="startRecord"
v-show="!recording && startedBefore"
:disabled="isSubmitting"
type="primary"
>
recordAgain
</el-button>
<el-button
ref="stopRecord"
v-show="recording"
@click="stopRecord"
type="primary"
>
finish
</el-button>
<el-button
v-show="!recording && startedBefore"
@click="handleRecordedVideo(video.blob)"
type="green"
:loading="isSubmitting"
>
submit
</el-button>
</div>
</el-card>
</div>
</template>
<script>
import RecordRTC from "recordrtc";
export default {
name: "screen-recorder",
langPrefix: "components.recorder",
data() {
return {
recorder: null,
stream: null,
video: null,
recording: false,
startedBefore: false,
};
},
props: {
isSubmitting: {
type: Boolean,
required: true,
},
},
methods: {
handleRecordedVideo() {
this.$emit("submit", {
file: this.video.blob,
});
},
startRecord() {
this.captureScreen((screen) => {
this.video.srcObject = screen;
this.recorder = RecordRTC(screen, {
type: "video",
});
this.recorder.startRecording();
this.recorder.screen = screen;
this.startedBefore = this.recording = true;
});
},
stopRecord() {
this.recorder.stopRecording(this.stopRecordingCallback);
this.recording = false;
},
async stopRecordingCallback() {
this.video.src = this.video.srcObject = null;
const blob = this.recorder.getBlob();
this.video.src = URL.createObjectURL(blob);
this.video.blob = blob;
this.recorder.screen.stop();
this.recorder.destroy();
},
getStream() {
if (navigator.mediaDevices.getDisplayMedia) {
return navigator.mediaDevices.getDisplayMedia({
video: {
displaySurface: "monitor",
logicalSurface: true,
cursor: "always",
},
});
}
},
invokeGetDisplayMedia(success, error) {
let displaymediastreamconstraints = {
video: {
displaySurface: "monitor",
logicalSurface: true,
cursor: "always",
},
};
displaymediastreamconstraints = {
video: true,
};
if (navigator.mediaDevices.getDisplayMedia) {
navigator.mediaDevices
.getDisplayMedia(displaymediastreamconstraints)
.then(success)
.catch(error);
} else {
navigator
.getDisplayMedia(displaymediastreamconstraints)
.then(success)
.catch(error);
}
},
addStreamStopListener(stream, callback) {
stream.addEventListener(
"ended",
() => {
callback();
callback = () => {};
},
false
);
stream.addEventListener(
"inactive",
() => {
callback();
callback = () => {};
},
false
);
stream.getTracks().forEach((track) => {
track.addEventListener(
"ended",
() => {
callback();
callback = () => {};
},
false
);
track.addEventListener(
"inactive",
() => {
callback();
callback = () => {};
},
false
);
});
},
captureScreen(callback) {
this.invokeGetDisplayMedia(
(screen) => {
this.addStreamStopListener(screen, () => {
this.$refs.stopRecord.click();
});
callback(screen);
},
(error) => {
console.error(error);
}
);
},
},
mounted() {
this.video = this.$refs.video;
},
};
</script>
recordrtc库参考文档:https://github.com/muaz-khan/RecordRTC
边栏推荐
- MindFusion. Virtual Keyboard for WPF
- How to use jedis of redis
- Judge whether the stack order is reasonable according to the stack order
- As soon as I write the code, President Wang talks with me about the pattern all day
- How to solve the problem that easycvr changes the recording storage path and does not generate recording files?
- Is "golden nine and silver ten" the best time to find a job? Not necessarily
- Use Firefox browser to quickly pick up Web image materials
- mysql的七种join连接查询
- Deflocculant aminoiodotide eye drops
- NEW:Devart dotConnect ADO.NET
猜你喜欢
JWT vulnerability recurrence
ActiveReportsJS 3.1 VS ActiveReportsJS 3.0
Resolved (sqlalchemy+pandas.read_sql) attributeerror: 'engine' object has no attribute 'execution_ options‘
3. Package the bottom navigation tabbar
mysql的七种join连接查询
Technical tutorial: how to use easydss to push live streaming to qiniu cloud?
企业级:Spire.Office for .NET:Platinum|7.7.x
PlasticSCM 企业版Crack
Online text line fixed length fill tool
Plasticscm enterprise crack
随机推荐
Pyqt5 displays file names and pictures
测试开发是什么?为什么现在那么多公司都要招聘测试开发?
Rust区块琏开发——签名加密与私钥公钥
DFS and BFS concepts of trees and graphs
error Couldn‘t find a package. JSON file in "your path“
How does the applet solve the rendering layer network layer error?
Threejs Internet of things, 3D visualization of factory
Threejs realizes rain, snow, overcast, sunny, flame
NEW:Devart dotConnect ADO.NET
面试汇总:这是一份全面&详细的Android面试指南
Test d'automatisation de l'interface utilisateur télécharger manuellement le pilote du navigateur à partir de maintenant
输入的查询SQL语句,是如何执行的?
English essential vocabulary 3400
[Chongqing Guangdong education] 2408t Chinese contemporary literature reference test in autumn 2018 of the National Open University
反絮凝剂-氨碘肽滴眼液
MindFusion. Virtual Keyboard for WPF
小程序中实现文章的关注功能
Interview summary: This is a comprehensive & detailed Android interview guide
Possible stack order of stack order with length n
Special Edition: spreadjs v15.1 vs spreadjs v15.0