结论
template 主要是作为一个占位符去使用,在 Vue 2 和 Vue 3 中 template 的表现有一些区别:
Vue 2:作为一个占位符去使用或者是在组件中传递一个插槽内容。无论什么情况,template 在 compiler 后会被去除。
Vue 3:用法同 Vue 2,但是在不使用 v-if、v-else-if 或 v-else、v-slot、v-for 的时候,Vue 不会进行处理,会直接渲染成一个 HTML 原生的 template 标签。
Vue 2 表现分析
Vue 2 中对应 template 仅仅是属于一个占位符,在 vue-template-compiler 处理完毕后,其并不会保留在 render 函数中。换句话说,其最后并不会影响到渲染到页面上的 DOM。
讲实际例子前,我们先讲一下 render 函数中一些方法作用:
_c: 创建 VNode 节点
_v: 创建文本节点
_e: 创建一个空的 VNode 节点
_u: 处理插槽数据
我们可以用 vue-template-compiler 来验证一下上面的结论:
const compiler = require('vue-template-compiler')
// 这里解析的是 Vue 单文件的模板
const res = compiler.compile(`<div class='root-container'>
<template>
<div>测试元素1</div><div>测试元素2</div>
</template>
<template #slotName>
<div>测试元素1</div><div>测试元素2</div>
</template>
<template v-if="true">
<div>测试元素1</div><div>测试元素2</div>
</template>
<template v-if="false">
<div>测试元素1</div><div>测试元素2</div>
</template>
</div>`)
上面会输出一些结果,我们只需要关注 render 这个属性就行了。
下面解析一下 render 结果:
with (this) {
return _c(
'div',
{
staticClass: "root-container",
// 插槽属性,这个元素最后会挂载到特定组件的定义好的插槽位置上
scopedSlots: _u(
[{
key: "slotName",
fn: function () {
// 可以看到这里是直接将 template 中的元素给平铺了出来,template 这个元素本身并没有被渲染出来
return [
_c('div', [_v("插槽元素1")]),
_c('div', [_v("插槽元素2")])
]
},
proxy: true
}]
)
},
// 空格占位符(因为 2 个 template 之间有换行)
[_v(" "),
// 解析:无条件元素这里的 2 个元素是直接作为元素被创建
[
_c('div', [_v("无条件元素1")]), _c('div', [_v("无条件元素2")])
],
// 空格占位符(因为 2 个 template 之间有换行)
_v(" "),
// 这里的 2 个元素是根据 v-if 传进去的条件来决定是否渲染。否的话会创建一个空的 VNode 节点
(true) ? [
_c('div', [_v("有条件元素1")]), _c('div', [_v("有条件元素2")])
] : _e()],
2)
}
我们可以将下面这段代码放到 Vue 2 中去跑下。这里把 slot 去掉了,只看 template 带不带条件的表现:
<template>
<div class='root-container'>
<template>
<div>无条件元素1</div><div>无条件元素2</div>
</template>
<template v-if="true">
<div>有条件元素1</div><div>有条件元素2</div>
</template>
</div>
</template>
可以看到,和分析的是一致的。
Vue 3 表现分析
Vue3 中的 template 与 Vue 2 中的有些差别:
template 如果上面不携带任何指令,那么它将被渲染成一个原生的 template 标签。
template 只有与下面的指令一起使用时,里面的元素才会被 Vue 内部进行处理。也就是决定它展示或不展示,或者展示到哪个插槽的位置。
v-if 、 v-else-if 或 v-else
v-for
v-slot(简写为 #插槽名)
我们可以将下面这段代码放到 Vue 3 中去跑下:
<template>
<template v-if="false">
<div>
template with false
</div>
</template>
<template v-if="true">
<div>
template with true
</div>
</template>
<template>
<div>
origin template
</div>
</template>
</template>
可以看到只有条件为 true 的 template 中的元素被展示到了 DOM 上。而不带任何条件的 template 则被解析成了 HTML 原生的 template 元素。
使用场景
1)对多个同级元素进行统一显隐:
<template>
<div>
<template v-if="mode === 'male'">
<div>子级元素1</div>
<div>子级元素2</div>
<div>子级元素3</div>
<div>子级元素4</div>
<div>子级元素5</div>
</template>
<template v-else-if>
<div>子级元素1</div>
<div>子级元素2</div>
<div>子级元素3</div>
<div>子级元素4</div>
<div>子级元素5</div>
</template>
<div>other children....</div>
</div>
</template>
<script>
export default {
data() {
return {
mode: 'male'
}
}
}
</script>
好处:template 不会在 DOM 上真实渲染,提高简洁性。 如果换成其他元素的话,则这些元素会在 DOM 上真实渲染。
实际效果:
例如:
<template>
<div>
<div v-if="mode === 'male'">
<div>子级元素1</div>
<div>子级元素2</div>
<div>子级元素3</div>
<div>子级元素4</div>
<div>子级元素5</div>
</div>
<div v-else>
<div>子级元素1</div>
<div>子级元素2</div>
<div>子级元素3</div>
<div>子级元素4</div>
<div>子级元素5</div>
</div>
<div>other children....</div>
</div>
</template>
<script>
export default {
data() {
return {
mode: 'male'
}
}
}
</script>
则会变成这样:外层元素多了一个 div 元素,就显得没这么简洁了。
最后
如果大家还有什么想要了解的题目,也可以评论区告诉我