通过插槽来分配内容
一些情况下我们会希望能和 HTML 元素一样向组件中传递内容:
html
<AlertBox>
Something bad happened.
</AlertBox>
这可以通过 Vue 的自定义 <slot>
元素来实现:
html
<template>
<div class="alert-box">
<strong>This is an Error for Demo Purposes</strong>
<slot />
</div>
</template>
<style scoped>
.alert-box {
/* ... */
}
</style>
如上所示,我们使用 <slot>
作为一个占位符,父组件传递进来的内容就会渲染在这里。
动态组件
有些场景会需要在两个组件间来回切换,比如 Tab 界面:
上面的例子是通过 Vue 的 <component>
元素和特殊的 is
attribute 实现的:
html
<!-- currentTab 改变时组件也改变 -->
<component :is="tabs[currentTab]"></component>
在上面的例子中,被传给 :is
的值可以是以下几种:
- 被注册的组件名
- 导入的组件对象
你也可以使用 is
attribute 来创建一般的 HTML 元素。
当使用 <component :is="...">
来在多个组件间作切换时,被切换掉的组件会被卸载。我们可以通过 <KeepAlive> 组件强制被切换掉的组件仍然保持"存活"的状态。
DOM 内模板解析注意事项
如果你想在 DOM 中直接书写 Vue 模板,Vue 则必须从 DOM 中获取模板字符串。由于浏览器的原生 HTML 解析行为限制,有一些需要注意的事项。
大小写区分
HTML 标签和属性名称是不分大小写的,所以浏览器会把任何大写的字符解释为小写。这意味着当你使用 DOM 内的模板时,无论是 PascalCase 形式的组件名称、camelCase 形式的 prop 名称还是 v-on 的事件名称,都需要转换为相应等价的 kebab-case (短横线连字符) 形式:
html
// JavaScript 中的 camelCase
const BlogPost = {
props: ['postTitle'],
emits: ['updatePost'],
template: `
<h3>{{ postTitle }}</h3>
`
}
<!-- HTML 中的 kebab-case -->
<blog-post post-title="hello!" @update-post="onUpdatePost"></blog-post>
闭合标签
我们在上面的例子中已经使用过了闭合标签 (self-closing tag):
html
<MyComponent />
这是因为 Vue 的模板解析器支持任意标签使用 />
作为标签关闭的标志。
然而在 DOM 内模板中,我们必须显式地写出关闭标签:
html
<my-component></my-component>
这是由于 HTML 只允许一小部分特殊的元素省略其关闭标签,最常见的就是 <input>
和 <img>
。对于其他的元素来说,如果你省略了关闭标签,原生的 HTML 解析器会认为开启的标签永远没有结束,用下面这个代码片段举例来说:
html
<my-component /> <!-- 我们想要在这里关闭标签... -->
<span>hello</span>
将被解析为:
html
<my-component>
<span>hello</span>
</my-component> <!-- 但浏览器会在这里关闭标签 -->
元素位置限制
某些 HTML 元素对于放在其中的元素类型有限制,例如 <ul>
,<ol>
,<table>
和 <select>
,相应的,某些元素仅在放置于特定元素中时才会显示,例如 <li>
,<tr>
和 <option>
。
这将导致在使用带有此类限制元素的组件时出现问题。例如:
html
<table>
<blog-post-row></blog-post-row>
</table>
自定义的组件 <blog-post-row>
将作为无效的内容被忽略,因而在最终呈现的输出中造成错误。我们可以使用特殊的 is attribute 作为一种解决方案:
html
<table>
<tr is="vue:blog-post-row"></tr>
</table>