vue.js中的template标签

🧠 是什么?

从 HTML 原生角度来看, 是一种声明式的占位容器,其内容不会立即渲染,而是等待 JavaScript 激活。

Vue 借用了这个语义,在模板编译阶段用它来封装多个元素或结构性指令(如 v-if, v-for, v-slot)的渲染逻辑。

特点总结:

特性说明
不会渲染成真实 DOM是的,运行时会“解开”
编译阶段可识别Vue 编译器知道如何把它转换成渲染函数
提高语法灵活性可包裹多个元素,使指令或插槽更加灵活

✅ 基本作用

Vue 的模板语法要求一个组件只能有一个根节点。当你需要根据条件渲染多个元素、或在某些结构性指令(比如 v-if、v-for)中包裹多个元素时, 就派上用场了。

🧩 用法场景

多元素条件渲染 (v-if)

错误写法(多个根节点):

<!-- ❌ 语法错误 -->
<div v-if="show">A</div>
<span v-if="show">B</span>

正确写法:

<template v-if="show">
  <div>A</div>
  <span>B</span>
</template>

循环多个元素 (v-for)

<template v-for="item in list" :key="item.id">
  <h3>{{ item.title }}</h3>
  <p>{{ item.content }}</p>
</template>

这将为 list 中的每一项生成一组 h3 + p 标签。

插槽中的 template

可以与插槽搭配使用,形成具名插槽或作用域插槽:

<!-- 父组件 -->
<my-layout>
  <template #header>
    <h1>标题区域</h1>
  </template>
  <template #default>
    <p>主体内容</p>
  </template>
</my-layout>

使用 v-slot 的作用域插槽

<my-list :items="books">
  <template v-slot:default="slotProps">
    <li>{{ slotProps.item.title }}</li>
  </template>
</my-list>

⚠️ 注意事项

  • 不会在 DOM 中渲染为标签,只是一个包裹容器。
  • 使用 v-if、v-for 时,如果控制多个元素,必须用 包裹。
  • v-for 的 key 应写在 上,而不是子元素。

👀 示例对比

普通的 div 包裹(有 DOM 输出):

<div v-if="isVisible">
  <p>A</p>
  <p>B</p>
</div>

渲染结果:

<div>
  <p>A</p>
  <p>B</p>
</div>

使用 包裹(无 DOM 输出):

<template v-if="isVisible">
  <p>A</p>
  <p>B</p>
</template>

渲染结果:

<p>A</p>
<p>B</p>

🛠️ 编译阶段发生了什么?

Vue 模板经过编译器转换为“渲染函数”。 在这一步不会生成一个 DOM 节点对应的虚拟节点(VNode),它的子元素会直接被提升为父节点的子节点。

例如:

<template v-if="ok">
  <div>A</div>
  <div>B</div>
</template>

经过编译后会变成(简化版):

ok ? [h('div', 'A'), h('div', 'B')] : null

你可以看到 自身并不会成为虚拟节点,它只是一种包裹结构的语法糖。

⚙️ 运行时行为 —— 它“消失了”

在运行时,Vue 渲染引擎(比如 vDOM diff + patch)完全忽略 ,直接处理它内部的子节点。

举例:在 v-for 的时候,如果你用的是 ,每个 item 会生成它内部的一整组 DOM 元素,而不是一个额外的 标签。

<template v-for="item in list" :key="item.id">
  <p>{{ item.name }}</p>
  <span>{{ item.desc }}</span>
</template>

生成:

<p>...</p>
<span>...</span>
<p>...</p>
<span>...</span>
...

不会生成 元素。

🧩 使用场景深度理解

条件渲染多个元素时

Vue 不允许根节点下并列使用两个 v-if:

<!-- 错误:不能并列两个元素上 v-if -->
<div v-if="show1">A</div>
<div v-if="show2">B</div>

可以用 :

<template v-if="show">
  <div>A</div>
  <div>B</div>
</template>

这样是合法的,因为 Vue 在编译时可以识别 只是一个“包裹容器”,不会干扰逻辑。

插槽(Slot)系统的核心容器

作用域插槽是高级用法,必须配合 :

<!-- 子组件中 -->
<slot name="header" />

<!-- 父组件中 -->
<template #header>
  <h1>标题</h1>
</template>

为什么不用

呢?因为你不想因为结构上的需要而多生成一个标签。

高阶组件和逻辑抽象的“透明容器”

在写 renderless component(无渲染组件)时,组件的本质可能只输出 内容,这种场景下 也很适合控制结构但不污染渲染结果。

🔬 与 Fragment(片段)的关系(Vue 3 特有)

在 Vue 2 中,一个组件只能有一个根节点(你必须用一个 div 包起来),而 在组件模板中不能直接作为根节点,因为它不渲染。

但在 Vue 3 引入了 Fragment:允许组件返回多个根节点,Vue 运行时自动将多个子节点当作一个“片段”处理。这解放了 的束缚。

<!-- Vue 3 中合法 -->
<template>
  <h1>Title</h1>
  <p>Content</p>
</template>

这相当于内部使用了 Fragment 包裹。

⚠️ 常见误区

误以为 会渲染出元素:

  • 它不会。你不能给它加 class、style,它不会出现。

忘记为 v-for 中的 设置 key:

<template v-for="item in list" :key="item.id">
  <!-- 正确做法 -->
</template>

把 当成结构节点来传入 DOM 操作函数,结果找不到:

// 错误, 没有真实 DOM
this.$refs.myTemplate.style.color = ‘red’ // ❌ 会报错

✅ 总结精炼:

层级本质
语法包裹多个子节点,不渲染自身
编译被“解开”为多个子节点
运行没有虚拟 DOM 节点,只存在子节点
使用在条件渲染、插槽、循环中控制结构
特性语法糖、增强表达力、结构更清晰
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

layman0528

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值