【问题标题】:Pass an Iframe to different Components in an SPA (similar to Youtube)将 iframe 传递给 SPA 中的不同组件(类似于 Youtube)
【发布时间】:2019-11-03 16:58:29
【问题描述】:

因此,自从一段时间以来 Youtube 具有在浏览页面时最小化 Youtube 播放器的功能,LolEsports.com 具有与 Twitch 和嵌入式 Youtube 播放器类似的功能。

我想为我的页面带来类似的功能,基本上我的状态如下所示:

  • 前端的 Vue
  • 在子网址上嵌入了 Youtube 播放器
  • 当我离开子网址时,我希望 Youtube 播放器移动到具有当前状态的角落并仍然在那里

我想听听一些关于如何实现这一点的灵感,因为当我尝试将状态重置传递给不同的组件并且播放停止等时。

很想听听意见

【问题讨论】:

    标签: javascript html css vue.js


    【解决方案1】:

    简短的回答是:您不能在不丢失其状态的情况下移动 iframe DOM 节点,如in this answer 所述。

    长答案是:您有其他选择。我认为您最好的选择是直接在“角落播放器”中播放视频,然后将其重新设置为页面的正确位置。为此,您需要自己与 DOM 进行一些交互,您可以通过在要显示视频的容器上设置 ref 轻松完成。

    最后你会得到这样的结果:

    在您的 App.vue 中,您有您的标准 router-view,以及一些将包含您的实际视频的元素。

    <template>
      <div id="app">
        <router-view/>
        <corner-player/>
      </div>
    </template>
    

    您将开始播放视频的页面将包含一些占位符元素,作为放置视频的指导点:

    <div class="player-container" ref="player"></div>
    

    然后我们使用生命周期挂钩来获取正确的 url 和样式以发送给播放器。我使用简单的总线来更轻松地在应用程序中传递事件,否则将数据传输到播放器组件通常会很麻烦。我们使用安装的钩子来设置视频,因为那是第一个渲染周期发生的时候。 beforeDestroy 生命周期允许我们发送某种事件,将视频放在角落里。

    export default {
      name: "child1",
    
      mounted() {
        const container = this.$refs.player;
        const boundingBox = container.getBoundingClientRect();
    
        this.$bus.$emit("play-video", {
          url: "https://www.youtube.com/embed/dW4HCi1zZh8",
          styling: {
            position: "absolute",
            top: `${boundingBox.top}px`,
            left: `${boundingBox.left}px`,
            width: `${boundingBox.width}px`,
            height: `${boundingBox.height}px`,
            border: "3px dotted red"
          }
        });
      },
    
      beforeDestroy() {
        this.$bus.$emit("move-to-corner-player");
      }
    };
    

    然后播放器组件使用这两个事件并确保应用正确的样式。我不建议像在这里那样应用原始 css,但这是一个概念证明。

    <template>
      <div class="corner-player" :style="styling" v-if="url">
        <iframe
          width="1280"
          height="540"
          :src="url"
          frameborder="0"
          allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
          allowfullscreen
        ></iframe>
      </div>
    </template>
    
    <script>
    export default {
      name: "CornerPlayer",
    
      data() {
        return {
          styling: {},
          url: "",
    
          defaultStyling: {
            border: "3px solid blue",
            position: "fixed",
            bottom: 0,
            right: 0,
            height: "150px",
            width: "220px"
          }
        };
      },
    
      created() {
        this.$bus.$on("play-video", this.playVideo);
        this.$bus.$on("move-to-corner-player", this.moveToCornerPlayer);
      },
    
      beforeDestroy() {
        // Prevent memory leaks
        this.$bus.$off("play-video", this.playVideo);
        this.$bus.$off("move-to-corner-player", this.moveToCornerPlayer);
      },
    
      methods: {
        playVideo({ url, styling }) {
          this.url = url;
          this.styling = styling;
        },
    
        moveToCornerPlayer() {
          this.styling = {
            ...this.defaultStyling
          };
        }
      }
    };
    </script>
    
    <style scoped>
    iframe {
      width: 100%;
      height: 100%;
    }
    </style>
    

    你可以在 Codesandbox 上玩这个:

    【讨论】:

    • 非常感谢你非常有趣的方法,我试图将它引入我的应用程序并成功地做到了,我决定反对事件总线并选择 Vuex 但我想如果它你也会这样做不是为了简单地展示你的例子。
    • 可能会使用 EventBus 来处理事件,例如通过时间戳向前跳过,因为如果没有观察者和商店的东西,这将无法工作,除非有更好的方法让我知道 :)
    • 是的,Vuex 也可以。在这种情况下,您将在 vuex 模块而不是组件中处理状态。除此之外,同样的情况仍然适用。我同意使用事件来跳过视频可能是最好的选择,特别是如果您使用某种库与播放器交互,而不是仅仅使用一些神奇的 url 重新加载 iframe。
    【解决方案2】:

    感谢 Sumurai8!为了使 iframe 容器更具响应性,我稍微编辑了您的 CodeSandbox:https://codesandbox.io/s/pass-an-iframe-to-different-components-forked-jeipq?file=/src/components/Child1.vue

    所以现在容器将缩放并在滚动和刷新时保持在同一位置。

    【讨论】:

      猜你喜欢
      • 2019-11-14
      • 2016-10-10
      • 2019-10-15
      • 1970-01-01
      • 1970-01-01
      • 2018-12-03
      • 1970-01-01
      • 2019-01-23
      • 1970-01-01
      相关资源
      最近更新 更多