类似于 component
和 keep-alive
, teleport
同样是Vue 的内建组件。
现在有一个自定义组件 error-alert
, 是对 JavaScript 的 alert()
的改进,当输入不合法时,会弹出警告,代码如下所示,看起来是没有任何问题。
<template>
<div>
<h2>Manage Goals</h2>
<input type="text" ref="goal" />
<button @click="setGoal">Set Goal</button>
<error-alert v-if="inputIsInvalid">
<h2>Input is invalid!</h2>
<p> Please enter a few characters... </p>
<button @click="confirmError">Okay</button>
</error-alert>
</div>
</template>
<script>
import ErrorAlert from "./ErrorAlert.vue";
export default {
components: {
ErrorAlert,
},
data() {
return {
inputIsInvalid: false,
}
},
methods: {
setGoal() {
const enteredValue = this.$refs.goal.value;
if (enteredValue==='') {
this.inputIsInvalid = true;
}
},
confirmError() {
this.inputIsInvalid =false;
}
}
}
</script>
但是如果查看HTML code,会发现 error-alert 的内容<dialog>
紧邻其他元素 <h2><input><button>
,不过code里就是按这个顺序写的,虽然不影响功能,但从HTML语义的角度看显得很奇怪,因为这种 alert 应该是覆盖整个页面的,而不是嵌套到HTML code的某个地方。
为了解决这个问题,使用 Vue 内建组件 teleport
,将自定义组件 error-alert
放到此组件内,并设置 to
属性,指向某个CSS 选择器,比方说 body
:
<template>
<div>
<h2>Manage Goals</h2>
<input type="text" ref="goal" />
<button @click="setGoal">Set Goal</button>
<teleport to="body">
<error-alert v-if="inputIsInvalid">
<h2>Input is invalid!</h2>
<p> Please enter a few characters... </p>
<button @click="confirmError">Okay</button>
</error-alert>
</teleport>
</div>
</template>
逻辑上而言,<error-alert>
仍然属于这个容器组件, 仍然可以与这个组件内的方法交互等等,但是它会被渲染到dom结构的别的地方,在这个例子中,是在body
元素内,可以通过页面源代码查看。
这是一个小小的优化,使 HTML 结构更加合理。