Vue 3 Teleport仅能在vue外部移植吗?

问题描述

Vue 3具有一项新的Teleport功能,该功能取代了vue 2中的portal-vue插件。但是,我发现无法将组件移植到受vue控制的位置(在vue应用程序中)。仅当移植到外部(主体,其他元素...)时有效。

const app = {
  template: `
  <div>
    <h1>App</h1>
    <div id="dest"></div>
    <comp />
  </div>`
}


Vue.createApp(app).component('comp',{
  template: `
  <div>
    A component
    <Teleport to="#dest">
      Hello From Portal
    </Teleport>
  </div>`
}).mount('#app')
<script src="https://unpkg.com/vue@3.0.0-rc.9/dist/vue.global.js"></script>

<div id="app"></div>

如您所见,控制台甚至报告说,一个传送目标已经被渲染。但是如何告诉vue首先渲染哪个组件?在我的示例中,目标位于传送前的dom中。

这在Portal-Vue中不是问题,而且非常可惜,因为它使整个概念的可用性降低。

解决方法

Vue错误消息指出了该问题。它说Invalid Teleport target on mount: null

问题是目标不存在

仅在安装组件后才渲染传送部分,即可轻松解决此问题。

似乎 就像这样,Vue应该在没有显式检查的情况下进行处理。当您将id作为字符串传递时,很难确定目标是否为Vue组件,尤其是尚未渲染时。但是我只是在推测团队的意图。

const app = {
  template: `
  <div>
    <h1>App</h1>
    <div id="dest"></div>
    <comp />
  </div>`
}

Vue.createApp(app).component('comp',{
  template: `
  <div>
    A component
    <Teleport to="#dest" v-if="isMounted">
      Hello From Portal
    </Teleport>
  </div>`,data: function(){
    return { 
        isMounted: false
    }
  },mounted(){
    this.isMounted = true
  }
}).mount('#app')
<script src="https://unpkg.com/vue@3.0.0-rc.9/dist/vue.global.js"></script>

<div id="app"></div>

,

我看到没有必要在Vue应用程序创建的DOM树中定位元素,因为传送的逻辑和内容与目标无关(我的意思是逻辑和内容都独立于风格) ),它不像scoped slot那样可能需要一些数据才能从子组件中获取给父组件。

示例1 :如我在传送之前依赖于目标样式,在下面的示例中,主体具有relative位置,该位置可使我们的传送按预期显示(作为弹出窗口),但是如果我们将位置更改为fixed,则传送会受到影响(请参见示例2

const app = Vue.createApp({});

app.component('modal-button',{
  template: `
    <button @click="modalOpen = true">
        Open full screen modal! (With teleport!)
    </button>

    <teleport to="body">
      <div v-if="modalOpen" class="modal">
        <div>
          I'm a teleported modal! 
          (My parent is "body")
          <button @click="modalOpen = false">
            Close
          </button>
        </div>
      </div>
    </teleport>
  `,data() {
    return {
      modalOpen: false
    }
  }
})

app.mount('#app')
.modal {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background-color: rgba(0,.5);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.modal div {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background-color: white;
  width: 300px;
  height: 300px;
  padding: 5px;
}
<script src="https://unpkg.com/vue@3.0.0-rc.9/dist/vue.global.js"></script>

<body style="position: relative;">
  <div id="app" >
    <h3>Tooltips with Vue 3 Teleport</h3>
    <div>
      <modal-button></modal-button>
    </div>
  </div>
</body>

示例2

const app = Vue.createApp({});

app.component('modal-button',.5);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.modal div {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background-color: white;
  width: 300px;
  height: 300px;
  padding: 5px;
}
<script src="https://unpkg.com/vue@3.0.0-rc.9/dist/vue.global.js"></script>

<body style="position: fixed;">
  <div id="app" >
    <h3>Tooltips with Vue 3 Teleport</h3>
    <div>
      <modal-button></modal-button>
    </div>
  </div>
</body>

,

在此问题上 GH 包含问题解决。 应该是这样的

   //Root template in App.vue(it doesn't need to wrap in a div or smth else)
<template>
    <div class="modal" :style="style">
        <div class="modal-background"></div>
        <div class="modal-content">
            <div id="modal"></div>
        </div>
        <button class="modal-close is-large" aria-label="close" 
        @click="modal.hideModal"></button>
    </div>

    // App instance
    <section class="section">
            <div class="container">
                <Navbar/>
                <router-view/>
            </div>
        </section>
</template>

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...