我在这里https://codepen.io/stevemr/pen/VNQbYe对我的问题进行了笔误
我有一个根Vue实例,该实例维护一个组件VideoPlayer的道具。我的根实例有一个名为setVideo的方法,该方法现在仅分配一些虚拟值。
这是我在根实例的数据中使用的对象:
video: {
drive: '',
filename: '',
mediaType: '',
},
这是setVideo函数:
setVideo: function() {
// Get the drive, filename, and mediaType
this.video.drive = 'hdd1';
this.video.filename = 'game-of-thrones_s01e04.mp4';
this.video.mediaType = 'show';
// Hide all modals and trigger the display of the video player
Event.trigger('hideModal');
Event.trigger('displayVideoPlayer');
},
Event类只是Vue基本事件的包装:
window.Event = new class {
constructor() {
this.vue = new Vue();
}
trigger(event, data = null) {
this.vue.$emit(event, data);
}
listen(event, callback) {
this.vue.$on(event, callback);
}
};
这是初始化我的VideoPlayer组件的DOM:
<video-player
v-bind:drive="video.drive"
v-bind:filename="video.filename"
v-bind:media-type="video.mediaType"
></video-player>
最后,这是我的VideoPlayer组件:
<template>
<div>
<div id="movie-container">
<div
class="video-loader top-most"
v-if="showVideoPlayer && !loaded"
></div>
<video
id="video-player"
ref="video"
v-if="showVideoPlayer && src !== ''"
class="top-most"
v-bind:class="{ hidden: !loaded }"
v-on:click="togglePlay"
controls
autoplay
>
<source v-bind:src="src" v-bind:type="videoType"></source>
</video>
</div>
<div id="time-range-container" v-if="showTimeRange">
<input
id="time-range"
ref="timeRange"
type="range"
min="0"
v-bind:max="duration"
step="30"
v-model:value="currentTime"
/>
</div>
</div>
</template>
<script>
export default {
props: [
'drive',
'filename',
'mediaType',
],
data() {
return {
currentTime: 0,
duration: 0,
loaded: false,
showTimeRange: false,
showVideoPlayer: false,
}
},
computed: {
src: function() {
if(this.filename !== '') {
return
'/video/' + this.drive +
'/' + this.mediaType +
's/' + this.filename;
}
return '';
},
videoType: function() {
var ext = this.filename.split('.')[1];
var type = '';
switch(ext) {
case 'mk4':
case 'm4v':
type = 'webm';
break;
case 'avi':
type = 'ogg';
break;
default:
type = ext;
}
return 'video/' + type;
},
},
created() {
Event.listen('displayVideoPlayer', this.display);
},
methods: {
display: function() {
if(this.src === '') {
return;
}
this.showVideoPlayer = true;
this.loaded = false;
var self = this;
setTimeout(function() {
var interval = setInterval(function() {
var video = self.$refs.video;
if(video.readyState > 0) {
self.loaded = true;
self.duration = Math.round(video.duration);
self.currentTime = video.currentTime;
clearInterval(interval);
}
}, 500);
}, 800);
},
togglePlay: function() {
var video = this.$refs.video;
if(video.paused) {
video.play();
}
if(!video.paused) {
video.pause();
}
},
},
}
</script>
调用setVideo时,应将VideoPlayer组件的prop设置为虚拟值,然后显示视频播放器。但是,当触发displayVideoPlayer事件时,组件props仍设置为其默认值(空字符串)。最重要的是,在调用display方法之前不会更新src计算的属性,因此display函数将立即返回而无需执行任何操作。
这就像我的组件的props和数据没有被更新,即使我可以通过开发工具看到它们。就像是发生的速度不够快。
我尝试将src用作组件数据的一部分,并使用另一个功能setSrc在显示功能中对其进行设置。但是发生了同样的事情。
我也尝试过移动Event.listen('displayVideoPlayer',this.display);进入mount()而不是created(),也没有解决任何问题。
如果您查看代码笔,则第一次单击按钮以触发setVideo功能时,应该显示视频播放器组件,而不是2次点击。
答案 0 :(得分:0)
似乎问题在于Vue更新值与您调用display
方法之间的竞争状态:
display: function() {
console.log(this.src) // ""
setTimeout(() => console.log(this.src)) // "/video/hdd1/shows/game-of-thrones_s01e04.mp4"
if(this.src === '') {
return
}
这意味着您在更新值之前调用了display
方法。
一种解决您问题的方法是在调用display
方法之前增加一些延迟:
setVideo: function() {
this.video.drive = 'hdd1'
this.video.filename = 'game-of-thrones_s01e04.mp4'
this.video.mediaType = 'show'
setTimeout(() => {
Event.trigger('displayVideoPlayer')
})
但是我认为这将来可能会遇到更多问题。如果您想依靠道具,则应该改用观察者模式:
watch: {
src (src) {
if(src === '') {
return
}
// ... display
}
}
或者通过事件传递这些值,而不是像props这样的道具传递
Event.trigger('displayVideoPlayer', this.video)