使用 VueJS 设置 srcObject 的替代方法
Alternative for setting the srcObject using VueJS
设置 html 视频元素的 "src" 属性不适用于 Vue.js 和 Vuex:
<video id="myVideoEl" :src="myStreamSrc" autoplay="autoplay">
myStreamSrc
是一个计算值,由事件处理程序在突变中设置:
AddStream: function (state, plMyStream) {
state.myRTCPeerConnection.addStream(plMyStream)
state.myStreamSrc = plMyStream
}
当我 运行 我的应用程序使用该代码时,出现以下错误:
HTTP “Content-Type” of “text/html” is not supported. Load of media
resource http://localhost:8080/[object%20MediaStream] failed.
当我执行以下操作时:
state.myVideoEl = document.querySelector('#myVideoEl')
state.myVideoEl.srcObject = payloadWithMyStream
我没有收到任何错误,并且显示了流。问题是,我不能使用截断的工作代码,因为引用的元素稍后添加到 DOM。当我使用 v-if
Vuex.js 属性绑定 div 中的 html 视频元素时,此代码片段不起作用。然后我得到 "undefined" 作为结果(因为页面加载时不存在带有视频元素的 div 元素)。
设置srcObject
和设置src
属性有区别吗?我认为当我设置 srcObject
时,视频元素将具有 src
属性,但它没有。
是否可以在视频html属性中设置srcObject
?
欲了解更多信息,请访问 Vue.js 论坛中的 my theard:
https://forum.vuejs.org/t/reference-elements-when-they-rendered-with-v-if/16474/13
你试过了吗
<video v-if="myStreamSrc" id="myVideoEl" :srcObject ="myStreamSrc" autoplay="autoplay"> ?
否则我会建议你为这种情况编写一个组件:
var videoComponent = {
template: '<video ref="myVideoEl" :srcObject ="myStreamSrc" autoplay="autoplay">'
props: ['myStreamSrc']
}
Vue.component("video-component", videoComponent)
在父模板中
<video-component v-if="myStreamSrc" :myStreamSrc="myStreamSrc"></video-component>
或者在父级中,您可以只为 srcObject 设置一个观察器,我假设它等于 false,直到加载正确的视频源。在这种情况下,您可以等到设置源目标,然后按工作方式进行。
...
watchers:{
myStreamSrc: function (newValue, oldValue) {
if(!oldValue && !!newValue){
this.nextTick(function () {
state.myVideoEl = document.querySelector('#myVideoEl')
state.myVideoEl.srcObject = payloadWithMyStream
})
}
}
}
提示:
当您将 ref="myVideoEl"
设置为 html 元素而不是 id="myVideoEl"
时,您可以使用 $refs.myVideoEl
而不是 document.querySelector('#myVideoEl')
。这只是一种品味。
PS: 我直接在Whosebug里写代码,没有拼写检查器...
想配合我的(类似)解决方案。我正在为 Vue 使用 Nuxt 框架。通过 Vuex 设置 MediaStream 对我也不起作用。网络摄像头的开启状态是通过在非子组件中单击按钮启动的,我需要在该其他组件中为视频对象设置媒体流。
在单击按钮切换我的视图以及启动时运行的方法中 navigator.mediaDevices
我最终这样做了(可能不是最干净的?)。
let constraints = (window.constraints = {
audio: false,
video: {
facingMode: "user"
}
});
navigator.mediaDevices
.getUserMedia(constraints)
.then((stream) => {
let videoTracks = stream.getVideoTracks();
if (this.$store.state.debug) console.log("Got stream with constraints:", constraints);
if (this.$store.state.debug) console.log("Using video device: " + videoTracks[0].label);
stream.oninactive = function() {
if (this.$store.state.debug) console.log("Stream inactive");
};
// NOTE: this is done this way because I couldnt set it via Vuex state
document.getElementById('user-media__source').srcObject = stream;
})
.catch((error) => {
if (error.name === "ConstraintNotSatisfiedError") {
if (this.$store.state.debug) console.log(`The resolution ${constraints.video.width.exact} "x" ${constraints.video.width.exact} px is not supported by your device.`);
} else if (error.name === "PermissionDeniedError") {
if (this.$store.state.debug) console.log(`Permissions have not been granted to use your camera and microphone, you need to allow the page access to your devices in order for the demo to work.`);
}
});
因此,由于我需要在其中设置源的组件已经 created/mounted 我刚刚解雇了通常的 document.getElementById('XXXX').srcObject =
并且它按我想要的方式工作。
srcObject 是修饰符而不是 html 属性,所以你需要写
<video :srcObject.prop="myStreamSrc" autoplay/>
有关 2019 年更新,请参阅 Priansh Shah 的回答。
为新版本的 Vue 发布更新的解决方案,以防有人遇到这个问题并遇到与我相同的错误。
2019 年更新:
<video :src-object.prop.camel="stream">
第一个更改是使用 v-bind 绑定到 srcObject
,这里是 shorthand 的示例:
<video :srcObject.prop="stream">
但是 srcObject
是驼峰式的,所以在 HTML 中它只是变成 srcobject
(小写),这被认为是不同的 属性,因此不会触发视频.
如果您使用的 Vue < 2.1,则必须使用 document.getXXXXX(...).srcObject = stream
.
手动启动它
但是,如果您使用的是 Vue v2.1+,那么您很幸运,因为现在还有一个 API 修饰符:
<video :src-object.prop.camel="stream">
.camel
将 kebab-case 转换为驼峰式大小写,因此要获得 srcObject
我们执行相反的操作并获得 src-object.camel
。将它与 .prop
和 v-bind
结合起来,我们得到上面的语法。
设置 html 视频元素的 "src" 属性不适用于 Vue.js 和 Vuex:
<video id="myVideoEl" :src="myStreamSrc" autoplay="autoplay">
myStreamSrc
是一个计算值,由事件处理程序在突变中设置:
AddStream: function (state, plMyStream) {
state.myRTCPeerConnection.addStream(plMyStream)
state.myStreamSrc = plMyStream
}
当我 运行 我的应用程序使用该代码时,出现以下错误:
HTTP “Content-Type” of “text/html” is not supported. Load of media resource http://localhost:8080/[object%20MediaStream] failed.
当我执行以下操作时:
state.myVideoEl = document.querySelector('#myVideoEl')
state.myVideoEl.srcObject = payloadWithMyStream
我没有收到任何错误,并且显示了流。问题是,我不能使用截断的工作代码,因为引用的元素稍后添加到 DOM。当我使用 v-if
Vuex.js 属性绑定 div 中的 html 视频元素时,此代码片段不起作用。然后我得到 "undefined" 作为结果(因为页面加载时不存在带有视频元素的 div 元素)。
设置srcObject
和设置src
属性有区别吗?我认为当我设置 srcObject
时,视频元素将具有 src
属性,但它没有。
是否可以在视频html属性中设置srcObject
?
欲了解更多信息,请访问 Vue.js 论坛中的 my theard: https://forum.vuejs.org/t/reference-elements-when-they-rendered-with-v-if/16474/13
你试过了吗
<video v-if="myStreamSrc" id="myVideoEl" :srcObject ="myStreamSrc" autoplay="autoplay"> ?
否则我会建议你为这种情况编写一个组件:
var videoComponent = {
template: '<video ref="myVideoEl" :srcObject ="myStreamSrc" autoplay="autoplay">'
props: ['myStreamSrc']
}
Vue.component("video-component", videoComponent)
在父模板中
<video-component v-if="myStreamSrc" :myStreamSrc="myStreamSrc"></video-component>
或者在父级中,您可以只为 srcObject 设置一个观察器,我假设它等于 false,直到加载正确的视频源。在这种情况下,您可以等到设置源目标,然后按工作方式进行。
...
watchers:{
myStreamSrc: function (newValue, oldValue) {
if(!oldValue && !!newValue){
this.nextTick(function () {
state.myVideoEl = document.querySelector('#myVideoEl')
state.myVideoEl.srcObject = payloadWithMyStream
})
}
}
}
提示:
当您将 ref="myVideoEl"
设置为 html 元素而不是 id="myVideoEl"
时,您可以使用 $refs.myVideoEl
而不是 document.querySelector('#myVideoEl')
。这只是一种品味。
PS: 我直接在Whosebug里写代码,没有拼写检查器...
想配合我的(类似)解决方案。我正在为 Vue 使用 Nuxt 框架。通过 Vuex 设置 MediaStream 对我也不起作用。网络摄像头的开启状态是通过在非子组件中单击按钮启动的,我需要在该其他组件中为视频对象设置媒体流。
在单击按钮切换我的视图以及启动时运行的方法中 navigator.mediaDevices
我最终这样做了(可能不是最干净的?)。
let constraints = (window.constraints = {
audio: false,
video: {
facingMode: "user"
}
});
navigator.mediaDevices
.getUserMedia(constraints)
.then((stream) => {
let videoTracks = stream.getVideoTracks();
if (this.$store.state.debug) console.log("Got stream with constraints:", constraints);
if (this.$store.state.debug) console.log("Using video device: " + videoTracks[0].label);
stream.oninactive = function() {
if (this.$store.state.debug) console.log("Stream inactive");
};
// NOTE: this is done this way because I couldnt set it via Vuex state
document.getElementById('user-media__source').srcObject = stream;
})
.catch((error) => {
if (error.name === "ConstraintNotSatisfiedError") {
if (this.$store.state.debug) console.log(`The resolution ${constraints.video.width.exact} "x" ${constraints.video.width.exact} px is not supported by your device.`);
} else if (error.name === "PermissionDeniedError") {
if (this.$store.state.debug) console.log(`Permissions have not been granted to use your camera and microphone, you need to allow the page access to your devices in order for the demo to work.`);
}
});
因此,由于我需要在其中设置源的组件已经 created/mounted 我刚刚解雇了通常的 document.getElementById('XXXX').srcObject =
并且它按我想要的方式工作。
srcObject 是修饰符而不是 html 属性,所以你需要写
<video :srcObject.prop="myStreamSrc" autoplay/>
有关 2019 年更新,请参阅 Priansh Shah 的回答。
为新版本的 Vue 发布更新的解决方案,以防有人遇到这个问题并遇到与我相同的错误。
2019 年更新:
<video :src-object.prop.camel="stream">
第一个更改是使用 v-bind 绑定到 srcObject
,这里是 shorthand 的示例:
<video :srcObject.prop="stream">
但是 srcObject
是驼峰式的,所以在 HTML 中它只是变成 srcobject
(小写),这被认为是不同的 属性,因此不会触发视频.
如果您使用的 Vue < 2.1,则必须使用 document.getXXXXX(...).srcObject = stream
.
但是,如果您使用的是 Vue v2.1+,那么您很幸运,因为现在还有一个 API 修饰符:
<video :src-object.prop.camel="stream">
.camel
将 kebab-case 转换为驼峰式大小写,因此要获得 srcObject
我们执行相反的操作并获得 src-object.camel
。将它与 .prop
和 v-bind
结合起来,我们得到上面的语法。