Svelte:重新安装组件以覆盖媒体元素

Svelte: Remount component to overwrite media elements

在我的 Svelte 应用中,我有多个页面,每个页面显示一个或多个视频。 为了渲染视频,我重复使用了 video 组件(简化):

// video component
<video poster="{source.thumb}">
    <source type="{source.mime}" src="{source.source}" >
</video>

主页通过api接收视频内容并调用视频组件:

// calling video component on main page
<script>
    let source = {
        thumb: 'thumb.jpg',
        source: 'video.mp4',
        mime: 'video/mp4',
    };
</script>
<Video source={source} />

一切正常,视频已渲染并可以播放。

但是: 当我导航或想用另一个视频替换视频时,旧视频元素仍然存在并且播放继续。

我可以使用 beforeUpdate() 暂停视频。但是随后,新视频奇怪地在完全相同的播放时间加载,一切都混淆了。或者,如果我删除 beforeUpdate() 中的视频元素,它不会填充新信息。

这有点道理,因为 video 媒体元素保持完全相同,只有属性和内容发生变化。因此状态和已经缓冲的源仍然存在。

不知何故我需要保证,当数据发生变化时,必须完全重新安装视频组件。 有谁知道这是怎么做到的吗?谢谢!

我遇到了与 <input type="file" ....> 相同的问题 并使用以下方法解决:

let video = true:
function reMountVideo() {
  video = false; 
  setTimeout(() => video = true, 0);
} 

{#if video }
  <Video source={source} />
{/if}

我没试过$destroy

经过反复试验并在@voscausa 的帮助下,它现在可以工作了:

<script>
    export let source;

    let renderVideo = true;

    $: { reMountVideo( source.source ) }
    function reMountVideo(){
        renderVideo = false;
        setTimeout(() => renderVideo = true, 0);
    }
</script>
{#if renderVideo === true}
    <video poster="{source.thumb}">
        <source type="{source.mime}" src="{source.source}" >
    </video>
{/if}

它检查视频 url 是否发生变化,如果发生变化,则触发 reMountVideo()

当前版本的 svelte 支持这个。每次 属性 src 更改时,都会在 video 上附加一个回调。

<script>
    let src = ...
    function load(node, src){
        if(src){
            node.src = src;
            node.load();
        } 
        return {
            update(src){
                if(src){
                    node.src = src;
                    node.load();
                }
            }
        }
    }
</script>

<video use:load={src}>

要在源更改时触发视频的重新渲染,{#key} block could be used REPL

<script>
    export let source;
</script>

{#key source}
<video poster="{source.thumb}" controls>
    <source type="{source.mime}" src="{source.source}" >
</video>
{/key}