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">Adiv>
<span v-if="show">Bspan>

正确写法:

<template v-if="show">
  <div>Adiv>
  <span>Bspan>
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>Ap>
  <p>Bp>
div>

渲染结果:

<div>
  <p>Ap>
  <p>Bp>
div>

使用 包裹(无 DOM 输出):

<template v-if="isVisible">
  <p>Ap>
  <p>Bp>
template>

渲染结果:

<p>Ap>
<p>Bp>

️ 编译阶段发生了什么?

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

例如:

<template v-if="ok">
  <div>Adiv>
  <div>Bdiv>
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:


<div v-if="show1">Adiv>
<div v-if="show2">Bdiv>

可以用 :

<template v-if="show">
  <div>Adiv>
  <div>Bdiv>
template>

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

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

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


<slot name="header" />


<template #header>
  <h1>标题h1>
template>

为什么不用

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

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

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

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

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

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


<template>
  <h1>Titleh1>
  <p>Contentp>
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 节点,只存在子节点
使用 在条件渲染、插槽、循环中控制结构
特性 语法糖、增强表达力、结构更清晰

你可能感兴趣的:(vue.js,vue.js,前端,javascript)