Vue 3 内置指令完全指南
本文档专门讲解 Vue 3 的内置指令:Vue 自带的、以 v- 开头的所有指令的语法、用法、修饰符和示例,适合新手系统学习。自定义指令的写法见《Vue3自定义指令.md》。
一、什么叫做“内置指令”?
1.1 概念
内置指令是 Vue 框架自带的、不需要你安装或注册就能在模板里直接使用的特殊属性。
它们都以 v- 开头,写在标签上,用来绑定数据、控制显示、绑定事件、绑定表单等。
例如 v-if、v-for、v-model 都是内置指令。
1.2 指令的四个部分(语法结构)
一个完整的指令可能包含:
| 部分 | 说明 | 示例 |
|---|---|---|
| 名称 | v- 开头的指令名 | v-if、v-bind |
| 参数 | 冒号后面的部分(可选) | v-bind:href、v-on:click |
| 修饰符 | 点后面的部分(可选,可多个) | v-model.lazy、v-on:click.stop |
| 值 | 等号右边的表达式 | v-if=”count > 0“ |
示例:
<div v-bind:id="dynamicId"></div>
<a v-on:click.prevent="submit">提交</a>
<input v-model.lazy.trim="name" />
- v-bind:id:参数是 id,值是 dynamicId。
- v-on:click.prevent:参数是 click,修饰符是 prevent,值是 submit。
- v-model.lazy.trim:修饰符是 lazy 和 trim,值是 name。
二、内容渲染类内置指令
2.1 v-text —— 纯文本
作用: 把表达式的值以纯文本形式设为元素的 textContent,会覆盖该元素内原有内容。
语法: v-text="表达式"
<p v-text="message"></p>
<!-- 等价于 -->
<p>{{ message }}</p>
注意: 若内容里包含 HTML 标签,会原样显示成字符串,不会解析。需要解析 HTML 用 v-html(见下)。
2.2 v-html —— 原始 HTML
作用: 把表达式的值当作 HTML 插入到元素中,会覆盖该元素内原有内容。
语法: v-html="表达式"
<div v-html="rawHtml"></div>
const rawHtml = ref('<span style="color:red">红色</span>')
安全警告: 只对完全信任的内容使用 v-html,用户输入或第三方数据可能包含恶意脚本(XSS),不要直接塞进 v-html。
三、条件渲染类内置指令
3.1 v-show
作用: 根据表达式真假切换元素的 display(true 显示,false 隐藏)。元素始终在 DOM 中,只是被隐藏。
语法: v-show="表达式"
<p v-show="isVisible">看得见我</p>
- isVisible 为 true:元素正常显示。
- isVisible 为 false:元素被加上 style=”display: none;”。
特点: 切换成本低(只改 CSS),适合频繁切换的显示/隐藏。
3.2 v-if / v-else-if / v-else
作用: 根据条件是否渲染这块 DOM。为 false 时,对应节点不会出现在 DOM 里(不是隐藏,是移除)。
语法:
v-if="表达式"v-else-if="表达式"(可选,必须紧跟在 v-if 或 v-else-if 后)v-else(可选,无值,必须紧跟在 v-if 或 v-else-if 后)
<p v-if="score >= 90">优秀</p>
<p v-else-if="score >= 60">及格</p>
<p v-else>不及格</p>
v-if 与 v-show 对比:
| 对比 | v-if | v-show |
|---|---|---|
| 为假时 | 不渲染,从 DOM 移除 | 仍在 DOM,display: none |
| 切换成本 | 有创建/销毁成本 | 只改 CSS |
| 适用 | 很少切换的条件块 | 频繁切换 |
四、列表渲染:v-for
作用: 根据数据源循环渲染多个元素。
语法:
v-for="(项, 索引?) in 数组"v-for="(值, 键?, 索引?) in 对象"v-for="n in 数字"(从 1 到该数字)
必须配合 :key,且 key 要唯一、稳定,推荐用 id,避免用 index(列表增删时易错位)。
<li v-for="(item, index) in list" :key="item.id">
{{ index + 1 }}. {{ item.name }}
</li>
<li v-for="(value, key) in user" :key="key">{{ key }}: {{ value }}</li>
<span v-for="n in 5" :key="n">{{ n }}</span>
<!-- 渲染 1 2 3 4 5 -->
注意: 不要在同一元素上同时写 v-for 和 v-if;需要“循环+条件”时用 包一层,在子元素上写 v-if,或用计算属性先过滤再 v-for。
五、属性绑定:v-bind(:)
作用: 把表达式的值绑定到元素的属性上,属性会随数据变化而更新。
语法: v-bind:属性名="表达式" 或简写 :属性名="表达式"
<img :src="imgUrl" :alt="imgAlt" />
<a :href="url">链接</a>
<div :id="boxId">盒子</div>
绑定多个属性: 无参数的 v-bind 可传一个对象,键为属性名,值为属性值:
<div v-bind="attrObj"></div>
const attrObj = { id: 'a', class: 'box', 'data-x': '1' }
六、事件绑定:v-on(@)
作用: 给元素绑定事件(如 click、input、submit)。
语法: v-on:事件名="处理函数或内联语句" 或简写 @事件名="..."
<button @click="count++">+1</button>
<button @click="handleClick">点击</button>
<button @click="handleClick($event)">需要事件对象</button>
<button @click="submit(id, $event)">传参+事件对象</button>
常用事件修饰符:
| 修饰符 | 作用 |
|---|---|
| .prevent | 调用 event.preventDefault(),如阻止表单提交、链接跳转 |
| .stop | 调用 event.stopPropagation(),阻止冒泡 |
| .once | 事件最多触发一次 |
| .capture | 使用捕获阶段 |
| .self | 仅当 event.target 是当前元素时触发 |
<form @submit.prevent="onSubmit">...</form>
<div @click="onDiv">
<button @click.stop="onBtn">按钮</button>
</div>
<button @click.once="doOnce">只触发一次</button>
按键修饰符: @keyup.enter、@keyup.esc、@keydown.ctrl 等。
七、双向绑定:v-model
作用: 在表单控件上实现双向绑定:数据变→视图变,用户输入→数据变。
语法: v-model="变量",可加修饰符 .lazy、.number、.trim。
<input v-model="text" />
<textarea v-model="intro"></textarea>
<input v-model.number="age" type="number" />
<input v-model.trim="keyword" />
<input v-model.lazy="message" />
单选框、复选框、下拉框:
<input type="radio" v-model="gender" value="男" />
<input type="checkbox" v-model="agree" />
<input type="checkbox" v-model="hobbies" value="读书" />
<select v-model="selected">
<option value="">请选择</option>
<option value="a">A</option>
</select>
- 单个 checkbox 绑布尔值;多个 checkbox 绑数组。
- radio、select 单选绑单个值(字符串或数字)。
八、插槽:v-slot(#)
作用: 在父组件里为子组件的插槽提供内容;可接收子组件通过插槽传出的数据(作用域插槽)。
语法: v-slot:插槽名="作用域" 或简写 #插槽名="作用域";默认插槽可写 #default 或 v-slot。
<Child>
<template #header>标题</template>
<template #default>默认内容</template>
<template #footer>底部</template>
</Child>
作用域插槽(子传数据给父):
<Child>
<template #default="{ user }">
{{ user.name }} - {{ user.age }}
</template>
</Child>
详见《Vue3插槽.md》。
九、其它内置指令
9.1 v-pre
作用: 该元素及其子元素不参与编译,双花括号和指令会原样显示。
<div v-pre>{{ 这里不会编译 }}</div>
用途: 展示代码示例、避免误编译。
9.2 v-once
作用: 元素只渲染一次,之后数据再变也不会更新。
<p v-once>{{ msg }}</p>
用途: 静态、不需要响应的内容,可略省性能。
9.3 v-memo(Vue 3.2+)
作用: 只有依赖数组里的值变化时,才重新渲染该节点及其子节点;用于大列表等性能优化。
语法: v-memo="[依赖1, 依赖2, ...]"
<div v-for="item in list" :key="item.id" v-memo="[item.id, item.selected]">
{{ item.name }}
</div>
9.4 v-cloak
作用: 配合 CSS 使用,在 Vue 未完成编译前隐藏未编译的模板(如双花括号),避免闪烁。
<style>
[v-cloak] { display: none; }
</style>
<div v-cloak>{{ message }}</div>
十、内置指令总览表
| 指令 | 作用 | 常用修饰符/说明 |
|---|---|---|
| v-text | 设置元素文本内容 | 会覆盖子内容 |
| v-html | 插入原始 HTML | 仅信任内容使用,防 XSS |
| v-show | 按条件切换 display | 元素始终在 DOM |
| v-if | 条件为真才渲染 | 可与 v-else-if、v-else 连用 |
| v-else-if | 否则如果 | 紧跟 v-if / v-else-if |
| v-else | 否则 | 紧跟 v-if / v-else-if |
| v-for | 列表渲染 | 必须配合 :key,且唯一 |
| v-on / @ | 绑定事件 | .prevent、.stop、.once、.enter 等 |
| v-bind / : | 绑定属性 | 无参 v-bind 可传对象 |
| v-model | 表单双向绑定 | .lazy、.number、.trim |
| v-slot / # | 插槽内容 | #default、#名字、作用域插槽 |
| v-pre | 不编译 | 原样输出 |
| v-once | 只渲染一次 | 后续不更新 |
| v-memo | 依赖不变则跳过更新 | 数组依赖 |
| v-cloak | 配合 CSS 防未编译闪烁 | 需样式 [v-cloak] |
十一、学习建议
- 先练熟 v-if、v-for、v-bind、v-on、v-model,这些用得最多。
- v-for 一定加 :key,且用稳定唯一值(如 id),避免用 index。
- v-if 与 v-show 分清:少切换用 v-if,频繁切换用 v-show。
- 事件用 @、属性用 :、v-model 记 .lazy、.number、.trim。
- 插槽、自定义指令需要时再查《Vue3插槽.md》《Vue3自定义指令.md》。
把本文档里的示例在项目里敲一遍、改一改数据看效果,会掌握得更牢。祝你学习顺利。