问题
Setting the "src" attribute of the html video element does not work with Vue.js and Vuex:
<video id="myVideoEl" :src="myStreamSrc" autoplay="autoplay">
myStreamSrc
is a computed value and is set in a mutation by an event handler:
AddStream: function (state, plMyStream) {
state.myRTCPeerConnection.addStream(plMyStream)
state.myStreamSrc = plMyStream
}
When I run my application with that code, I get the following error:
HTTP “Content-Type” of “text/html” is not supported. Load of media resource http://localhost:8080/[object%20MediaStream] failed.
When I do the following:
state.myVideoEl = document.querySelector('#myVideoEl')
state.myVideoEl.srcObject = payloadWithMyStream
I do not get any error and the stream is shown. The problem is, I can not use the working code snipped because the referenced elements are added later to the DOM. This code snippet does not work when I bind the html video element in a div with a v-if
Vuex.js attribute. Then I just get "undefined" as a result (because the div element with the video element did not exist on page load).
Is there a difference between setting the srcObject
and setting the src
attribute? I thought that when I set srcObject
the video element will have a src
attribute, but it does not.
Is it possible to set the srcObject
in the video html attribute?
For more info, please visit my theard in the Vue.js forum: https://forum.vuejs.org/t/reference-elements-when-they-rendered-with-v-if/16474/13
回答1:
Have you tried
<video v-if="myStreamSrc" id="myVideoEl" :srcObject ="myStreamSrc" autoplay="autoplay"> ?
Otherwise i would recommend you to write a component for that case:
var videoComponent = {
template: '<video ref="myVideoEl" :srcObject ="myStreamSrc" autoplay="autoplay">'
props: ['myStreamSrc']
}
Vue.component("video-component", videoComponent)
In the parent template
<video-component v-if="myStreamSrc" :myStreamSrc="myStreamSrc"></video-component>
OR in the parent you can just put a watcher for the srcObject which i assume to be equal to false until the correct video source gets loaded. In this case you can wait till the source target is set and then do it in the working way.
...
watchers:{
myStreamSrc: function (newValue, oldValue) {
if(!oldValue && !!newValue){
this.nextTick(function () {
state.myVideoEl = document.querySelector('#myVideoEl')
state.myVideoEl.srcObject = payloadWithMyStream
})
}
}
}
Hint:
You can use $refs.myVideoEl
instead of document.querySelector('#myVideoEl')
when you set ref="myVideoEl"
to the html-element instead of id="myVideoEl"
. This is just a sort of taste.
PS: I wrote the code in stackoverflow directly without an spellchecker...
回答2:
srcObject is modifier not a html attribute, so you need to write
<video :srcObject.prop="myStreamSrc" autoplay/>
回答3:
Wanted to chime in with my (similar) solution. I'm using the Nuxt framework for Vue. Setting MediaStream thru Vuex also didn't work for me. The state of the webcam being on is initiated thru a button click in a non-child component and I needed to set the mediastream for the video object in this other component.
In the method that runs when you click the button to toggle my view, as well as kick off navigator.mediaDevices
I ended up doing this (probably not the cleanest?).
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.`);
}
});
So since my component I need to set the source in is already created/mounted I just fired of the usual document.getElementById('XXXX').srcObject =
and it worked like I wanted.
回答4:
Posting an updated solution for newer versions of Vue in case anyone comes across this and runs across the same errors I did.
Updating for 2019:
<video :src-object.prop.camel="stream">
The first change is to bind to srcObject
using v-bind, here’s an example with the shorthand:
<video :srcObject.prop="stream">
However srcObject
is camel cased so in HTML it just becomes srcobject
(lowercase) which is considered a different property and so won’t fire the video.
If you’re using Vue < 2.1, you’ll have to fire it manually using document.getXXXXX(...).srcObject = stream
.
But if you’re using Vue v2.1+ you’re in luck as there is now an API modifier for this as well:
<video :src-object.prop.camel="stream">
.camel
converts kebab-case to camel case, so to get srcObject
we do the reverse and get src-object.camel
. Combining this with .prop
and v-bind
we get the above syntax.
来源:https://stackoverflow.com/questions/45888111/alternative-for-setting-the-srcobject-using-vuejs