Vue2和Vue3模板语法对比

Vue.js作为一款渐进式JavaScript框架,以其简洁优雅的模板语法著称。从Vue 2到Vue 3的演进过程中,模板语法经历了重要的改进和优化。Vue 3在保持核心语法兼容性的同时,引入了更强大的功能、更好的性能和更灵活的组织方式。通过详细对比Vue 2和Vue 3在模板语法上的主要差异,可以更好地理解和迁移

 

核心模板语法对比表(示例分列展示)

对比项

Vue 2语法

Vue 2示例

Vue 3语法

Vue 3示例

**多根节点**

必须单根节点

`<div><header/><main/></div>`

支持多根节点

`<header/><main/>`

**v-model绑定**

单一v-model

`<Comp v-model="val">`

v-model+参数

`<Comp v-model:title="t" v-model:content="c">`

**v-model修饰符**

仅内置修饰符

`<input v-model.lazy="txt">`

支持自定义修饰符

`<Comp v-model:title.capitalize="t">`

**插槽语法**

slot属性

`<template slot="header">`

v-slot/#缩写

`<template #header>`

**作用域插槽**

slot-scope

`<template slot-scope="{u}">`

v-slot参数

`<template #default="{u}">`

**动态插槽名**

不支持

支持#[expr]

`<template #[slotName]>`

**v-if与v-for**

v-for优先(可混用)

`<li v-for="u in list" v-if="u.show">`

v-if优先(不可混用)

用计算属性: `<li v-for="u in filtered">`

**动态指令参数**

不支持

支持:[expr]

`<a :[attrName]="url">`

**事件多处理器**

不支持

`<button @click="h">`

逗号分隔

`<button @click="h1(), h2()">`

**v-memo指令**

不存在

记忆化渲染

`<div v-memo="[val]">内容</div>`

**Teleport组件**

不存在

DOM渲染

`<Teleport to="body"><Modal/></Teleport>`

**Suspense组件**

不存在

异步加载状态

`<Suspense><Async/><template #fallback>Loading</template></Suspense>`

**事件修饰符**

`.stop/.prevent`

`@click.stop="h"`

相同+优化

`@click.stop.prevent="h"`

**按键修饰符**

`.enter/.esc`

`@keyup.enter="h"`

推荐-keyCode

`@keyup.enter="h"` 或 `@keyup.13="h"`

**v-bind.sync**

`.sync修饰符`

`<Comp :title.sync="t">`

废弃,用v-model

`<Comp v-model:title="t">`

 

核心差异详解

1. Fragment多根节点

对比示例:

<!-- Vue 2 -->
<template>
  <div>
    <header>Header</header>
    <main>Content</main>
  </div>
</template>

<!-- Vue 3 -->
<template>
  <header>Header</header>
  <main>Content</main>
</template>

关键点:

• Vue 2:必须单根节点包裹,否则报错

• Vue 3:支持多根节点,减少DOM层级

- 迁移:去除不必要的包裹div

 

2. v-model大幅增强

对比示例:

<!-- Vue 2 -->
<CustomInput v-model="value"/>
<!-- 组件:props:['value'], emit('input', newValue) -->

<!-- Vue 3 -->
<UserForm
  v-model:firstName="first"
  v-model:lastName="last"
  v-model:email.capitalize="email"
/>
<!-- 组件:props:{firstName,lastName,email}, emit('update:firstName',newValue) -->

关键点:

• Vue 2:单一v-model,默认`value`+`input`事件

• Vue 3:多v-model,自定义参数名+`update:xxx`事件

• Vue 3:支持自定义修饰符(如capitalize)

- 迁移:组件v-model需改用modelValue参数

 

3. 插槽语法标准化

对比示例:

<!-- Vue 2 -->
<template slot="header">
  <h1>Title</h1>
</template>
<template slot-scope="{ user }">
  {{ user.name }}
</template>

<!-- Vue 3 -->
<template #header>
  <h1>Title</h1>
</template>
<template #default="{ user }">
  {{ user.name }}
</template>

关键点:

• Vue 2:slot属性 + slot-scope语法

• Vue 3:v-slot指令 + #缩写

- 迁移:`slot="name"` → `#name`,`slot-scope` → `#default`

 

4. v-if与v-for优先级(必须重构)

对比示例:

<!-- Vue 2 -->
<li v-for="user in users" v-if="user.isActive">
  {{ user.name }}
</li>

<!-- Vue 3 - 报错 -->
<li v-for="user in users" v-if="user.isActive">
  {{ user.name }}
</li>

<!-- Vue 3 - 正确 -->
<script setup>
const activeUsers = computed(() => users.value.filter(u => u.isActive))
</script>
<template>
  <li v-for="user in activeUsers">
    {{ user.name }}
  </li>
</template>

关键点:

• Vue 2:v-for优先,可以混用(但性能差)

• Vue 3:v-if优先,无法访问v-for变量(报错)

- 迁移:必须用计算属性重构

 

5. 动态指令参数

对比示例:

<!-- Vue 2 - 不支持 -->
无动态参数功能

<!-- Vue 3 -->
<script setup>
const attrName = 'href'
const eventName = 'click'
</script>

<template>
  <a :[attrName]="url">Link</a>
  <button @[eventName]="handler">Button</button>
  <template #[slotName]>Dynamic Slot</template>
</template>

关键点:

• Vue 3新增:属性名、事件名、插槽名可动态化

• 语法:`:[expression]`、`@[expression]`、`#[expression]`

- 适用:属性名动态变化的场景

 

6. 事件处理增强

对比示例:

<!-- Vue 2 -->
<button @click="handleClick">Button</button>

<!-- Vue 3 -->
<button @click="handler1(), handler2()">
  Multiple Handlers
</button>
<button @click="count++, logEvent($event)">
  Inline + Method
</button>

关键点:

• Vue 2:单一处理器

• Vue 3:逗号分隔多处理器,支持混合内联和方法

- 适用:简化多操作触发场景

 

7. v-memo性能优化

对比示例:

<!-- Vue 2 - 不存在 -->
无记忆化功能

<!-- Vue 3 -->
<script setup>
const list = ref([...])  // 1000条数据
const selectedId = ref(1)
</script>

<template>
  <div
    v-for="item in list"
    :key="item.id"
    v-memo="[item.id, item.id === selectedId]"
  >
    {{ item.name }}
  </div>
</template>

关键点:

• Vue 3新增:记忆化渲染,跳过虚拟DOM diff

• 依赖数组:仅当依赖变化才更新

- 适用:大列表性能优化(最高10倍提升)

 

8. Teleport组件

对比示例:

<!-- Vue 2 - 不存在 -->
需要手动处理Modal定位问题

<!-- Vue 3 -->
<script setup>
const showModal = ref(false)
</script>

<template>
  <button @click="showModal = true">Open</button>

  <Teleport to="body">
    <div v-if="showModal" class="modal">
      <h2>Modal Title</h2>
      <button @click="showModal = false">Close</button>
    </div>
  </Teleport>
</template>

关键点:

• Vue 3新增:跨DOM树渲染组件

• 解决:z-index冲突、overflow遮挡问题

- 适用:Modal、Dropdown、Notification

 

9. Suspense异步加载

对比示例:

<!-- Vue 2 - 不存在 -->
<div v-if="loading">Loading...</div>
<AsyncComp v-else/>

<!-- Vue 3 -->
<script setup>
const AsyncComp = defineAsyncComponent(() =>
  import('./HeavyComponent.vue')
)
</script>

<template>
  <Suspense>
    <AsyncComp/>
    <template #fallback>
      <div>Loading...</div>
    </template>
  </Suspense>
</template>

关键点:

• Vue 3新增:异步组件加载状态管理

• 替代:手动v-if判断loading状态

- 适用:异步组件、数据加载

 

10. v-bind.sync废弃

对比示例:

<!-- Vue 2 -->
<CustomComponent :title.sync="pageTitle"/>
<!-- 组件:emit('update:title', newValue) -->

<!-- Vue 3 -->
<CustomComponent v-model:title="pageTitle"/>
<!-- 组件:emit('update:title', newValue) -->

关键点:

• Vue 2:`.sync`修饰符实现双向绑定

• Vue 3:废弃`.sync`,统一用v-model

- 迁移:`:prop.sync` → `v-model:prop`

 

11. 事件修饰符

对比示例:

<!-- Vue 2 -->
<form @submit.prevent="handleSubmit">
  <input @keyup.enter="handleEnter">
</form>

<!-- Vue 3 -->
<form @submit.prevent="handleSubmit">
  <input @keyup.enter="handleEnter">
  <!-- 支持链式修饰符 -->
  <button @click.stop.prevent="handleClick">
    Stop + Prevent
  </button>
</form>

关键点:

• Vue 2和Vue 3:基础修饰符相同(`.stop`、`.prevent`、`.capture`等)

• Vue 3:优化修饰符顺序和链式调用

- 无变化:日常使用保持一致

 

12. 按键修饰符

对比示例:

<!-- Vue 2 -->
<input @keyup.enter="handleEnter"/>
<input @keyup.13="handleEnter"/>  <!-- keyCode -->

<!-- Vue 3 -->
<input @keyup.enter="handleEnter"/>
<input @keyup.a="handleA"/>  <!-- 按键名推荐 -->
<!-- keyCode已废弃,推荐使用按键名 -->

关键点:

• Vue 2:支持keyCode数字和按键名

• Vue 3:推荐使用按键名,keyCode已废弃

- 迁移:`.13` → `.enter`(推荐)

 

13. 作用域插槽对比

对比示例:

<!-- Vue 2 -->
<template slot="default" slot-scope="{ user, index }">
  <div>{{ index }}: {{ user.name }}</div>
</template>

<!-- Vue 3 -->
<template #default="{ user, index }">
  <div>{{ index }}: {{ user.name }}</div>
</template>

关键点:

• Vue 2:`slot-scope`属性接收作用域数据

• Vue 3:`v-slot`参数接收,语法更简洁

- 迁移:`slot-scope="{data}"` → `#default="{data}"`

 

14. 动态插槽名

对比示例:

<!-- Vue 2 - 不支持 -->
插槽名必须固定字符串

<!-- Vue 3 -->
<script setup>
const dynamicSlot = computed(() => isMobile ? 'mobile' : 'desktop')
</script>

<template>
  <template #[dynamicSlot]>
    Dynamic Content
  </template>
</template>

关键点:

• Vue 3新增:插槽名可动态化

• 语法:`#[expression]`

- 适用:响应式布局、条件插槽

 

15. class/style绑定(无变化)

对比示例:

<!-- Vue 2Vue 3完全相同 -->
<template>
  <!-- class对象语法 -->
  <div :class="{ active: isActive }">Active</div>

  <!-- class数组语法 -->
  <div :class="[baseClass, { error: hasError }]">Array</div>

  <!-- style对象语法 -->
  <div :style="{ color: textColor, fontSize: '14px' }">Styled</div>

  <!-- style数组语法 -->
  <div :style="[baseStyles, overrideStyles]">Array Style</div>
</template>

关键点:

• Vue 2和Vue 3:语法完全相同

• 支持:对象语法、数组语法、混合语法

- 无迁移:直接使用即可

 

无变化语法快速参考

语法

示例

说明

**数据绑定**

`{{ message }}`

Mustache语法,无变化

**v-text**

`<span v-text="msg">`

替换文本内容

**v-html**

`<div v-html="content">`

渲染HTML内容

**v-show**

`<div v-show="visible">`

显示/隐藏切换

**v-once**

`<div v-once>{{msg}}`

只渲染一次

**v-pre**

`<span v-pre>{{原始文本}}`

跳过编译

**v-for**

`<li v-for="item in list" :key="item.id">`

循环渲染

**v-if/v-else**

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

条件渲染

**v-else-if**

`<div v-if="a">A</div><div v-else-if="b">B</div>`

多条件分支

**ref引用**

`<input ref="inputRef">`

模板引用(访问方式不同)

**key属性**

`<div :key="id">`

唯一标识

**class绑定**

`:class="{ active: isActive }"`

对象/数组语法

**style绑定**

`:style="{ color: textColor }"`

对象/数组语法

 

必须修改清单

Vue 2写法

Vue 3修改

原因

`<li v-for="u in users" v-if="u.active">`

用计算属性过滤

v-if/v-for优先级变更,无法访问变量

`<template slot="header">`

`<template #header>`

插槽语法标准化

`<template slot-scope="{data}">`

`<template #default="{data}">`

作用域插槽语法更新

`<Comp :title.sync="t">`

`<Comp v-model:title="t">`

.sync修饰符废弃

`<div><header/><main/></div>`

`<header/><main/>`

Fragment支持,消除冗余包裹

`<Comp v-model="val">`

`<Comp v-model:modelValue="val">`

v-model参数化

 

可选优化清单

新特性

Vue 3示例

适用场景

**多v-model**

`<Form v-model:name="n" v-model:email="e">`

表单多字段双向绑定

**v-model自定义修饰符**

`<Input v-model:text.capitalize="t">`

自定义数据处理

**动态参数**

`<a :[attrName]="url">`

属性名/事件名动态变化

**v-memo**

`<div v-memo="[deps]">`

大列表性能优化

**Teleport**

`<Teleport to="body"><Modal/></Teleport>`

Modal、Dropdown定位

**Suspense**

`<Suspense><AsyncComp/></Suspense>`

异步组件加载状态

**多事件处理器**

`@click="h1(), h2()"`

简化多操作触发

**动态插槽名**

`<template #[slotName]>`

条件插槽、响应式布局

 

总结

Vue 3模板语法的15个核心差异:

必须掌握(5个)

1. Fragment - 多根节点,减少DOM嵌套

2. v-model增强 - 多绑定+自定义参数+修饰符

3. 插槽标准化 - v-slot/#缩写统一语法

4. v-if/v-for优先级 - 必须重构混用场景

5. .sync废弃 - 统一用v-model替代

可选优化(10个)

6. 动态指令参数 - 属性名/事件名动态化

7. 事件多处理器 - 逗号分隔简化操作

8. 动态插槽名 - 插槽名称动态化

9. v-memo - 记忆化渲染优化

10. Teleport - 跨DOM树渲染

11. Suspense - 异步加载状态管理

12. 按键修饰符优化 - 推荐按键名

13. 事件修饰符优化 - 链式调用

14. v-model修饰符 - 自定义修饰符

15. class/style绑定 - 无变化,快速参考

迁移优先级

• 必须修改:v-if+v-for混用、插槽旧语法、.sync语法

• 建议采用:Fragment多根节点、v-model参数化、动态参数

• 可选优化:v-memo、Teleport、Suspense、多处理器

掌握这15个核心差异点,即可快速完成Vue 2到Vue 3模板语法迁移,编写更简洁、性能更优的代码。

posted on 2026-06-02 08:38  JustItIs  阅读(2)  评论(0)    收藏  举报

导航