Vue 指令详解笔记:从内置到自定义(初学者实战指南)
Vue 指令详解笔记:从内置到自定义(初学者实战指南)
各位小伙伴,之前我们学了插值({{ }}
)来绑定数据,今天要进阶学习 Vue 的 “指令”—— 这是 Vue 中用来操作 DOM、实现动态行为的核心工具(比如条件显示、循环渲染、事件绑定)。指令都带v-
前缀(比如v-if
、v-for
),能让我们不用写原生 JS,就能实现复杂的页面交互。
这篇笔记会从 “指令的核心概念” 讲起,逐个拆解常用内置指令(条件、列表、事件、双向绑定等),还会教大家写自定义指令,每个知识点都带实战代码、效果演示和易错点提醒,结合之前的组件、路由知识,让大家学完就能上手用!
一、先搞懂:什么是 Vue 指令?
Vue 指令是带有v-
前缀的特殊 HTML 属性,核心作用是 “响应式地给 DOM 添加行为”—— 当指令绑定的表达式值变化时,Vue 会自动更新 DOM。
比如v-if="isShow"
,如果isShow
从false
变成true
,Vue 会自动把元素渲染到 DOM 中;反之则删除元素。
1.1 指令的完整语法结构
一个指令的语法包含 5 个部分(其中参数、修饰符、值可选):
<element v-directive:argument.modifier="value">
我们用表格拆解每个部分:
组成部分 | 符号 / 示例 | 作用说明 |
---|---|---|
v- 前缀 | v- | 标识这是 Vue 指令(区别于普通 HTML 属性) |
指令名(directive) | if 、for 、bind | 指令的核心功能(比如if 是条件渲染,for 是列表渲染) |
参数(argument) | :click (v-on:click ) | 指令的具体操作目标(比如v-on:click 的click 是 “点击事件”) |
修饰符(modifier) | .prevent (v-on:submit.prevent ) | 给指令加额外规则(比如prevent 是 “阻止默认行为”) |
值(value) | "isShow" 、"handleClick" | 指令绑定的数据 / 表达式(比如v-if="isShow" 的isShow 是判断条件) |
示例:完整指令解析
<!-- v-on:指令名;click:参数;prevent:修饰符;handleSubmit:值(方法名) -->
<form v-on:submit.prevent="handleSubmit"></form>
<!-- 缩写后:@submit.prevent="handleSubmit"(v-on缩写@) -->
1.2 准备工作:创建指令测试组件
我们先创建directives.vue
组件,配置路由和导航,方便后续测试所有指令:
步骤 1:创建directives.vue
(核心测试组件)
在src/components
文件夹下新建directives.vue
,初始代码:
<template><div class="directives-container"><h1>Vue指令实战测试</h1><!-- 后续所有指令测试代码都写在这里 --></div>
</template><script>
// Vue3的setup中,响应式数据需要用ref(后面会讲)
import { ref } from 'vue'
export default {name: 'Directives', // 组件名setup() {// 后续在这里定义数据和方法return {// 数据/方法需要return,模板才能访问}}
}
</script><style scoped>
.directives-container {padding: 20px;border: 1px solid #eee;max-width: 800px;margin: 0 auto;
}
</style>
步骤 2:配置路由(让组件可访问)
修改src/router/index.js
,添加Directives
的路由:
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
// 导入指令测试组件
import Directives from '@/components/directives.vue'const routes = [{ path: '/', name: 'home', component: HomeView },{ path: '/about', name: 'about', component: () => import('../views/AboutView.vue') },// 新增指令测试路由{ path: '/directives', name: 'directives', component: Directives }
]const router = createRouter({history: createWebHistory(process.env.BASE_URL),routes
})export default router
步骤 3:添加导航链接(App.vue)
在App.vue
的导航栏中加 “指令测试” 链接,方便点击访问:
<template><nav><router-link to="/">Home</router-link> |<router-link to="/about">About</router-link> |<router-link to="/directives">指令测试</router-link> <!-- 新增 --></nav><router-view />
</template>
启动项目(npm run serve
),点击 “指令测试”,就能看到我们的测试页面 —— 接下来开始逐个学习指令!
二、常用内置指令详解(实战重点)
Vue 提供了很多 “内置指令”,覆盖了 90% 以上的开发场景,我们按 “使用频率” 排序讲解,每个指令都带代码、效果和易错点。
2.1 条件渲染指令:v-if /v-else-if/v-else
作用:根据表达式的 “真假”,条件性地渲染 / 销毁元素(真正的 “条件渲染”,元素会从 DOM 中添加 / 删除)。
实战代码(directives.vue 中添加)
<template><div class="directives-container"><h1>Vue指令实战测试</h1><!-- 1. 条件渲染:v-if / v-else-if / v-else --><div class="section"><h2>1. 条件渲染(v-if系列)</h2><p>当前类型:{{ type }}</p><p v-if="type === 'A'">这是A类型内容</p><p v-else-if="type === 'B'">这是B类型内容</p><p v-else>这是其他类型内容</p></div></div>
</template><script>
import { ref } from 'vue'
export default {name: 'Directives',setup() {// 定义条件变量(type为B时,显示“这是B类型内容”)const type = ref('B') // ref:Vue3中让普通数据变成响应式(值变了页面更)return { type }}
}
</script><style scoped>
/* 加样式区分不同模块 */
.section { margin: 20px 0; padding: 10px; border: 1px dashed #ccc; }
</style>
页面效果:
Vue指令实战测试
1. 条件渲染(v-if系列)
当前类型:B
这是B类型内容
关键规则:
v-if
、v-else-if
、v-else
必须连续相邻(中间不能插其他元素),否则v-else
会失效;v-if
可以单独用,但v-else-if
必须跟在v-if
后,v-else
必须跟在v-else-if
或v-if
后;- 表达式结果为 “假值”(
false
、0
、''
、null
、undefined
)时,元素会被销毁;真值则渲染。
2.2 显示切换指令:v-show
作用:根据表达式的 “真假”,切换元素的 “显示 / 隐藏”(元素始终在 DOM 中,只是用display: none
隐藏)。
实战代码(接上面添加)
<template><div class="directives-container"><!-- 2. 显示切换:v-show --><div class="section"><h2>2. 显示切换(v-show)</h2><p>用户是否登录:{{ user.username ? '是' : '否' }}</p><!-- 当user.username有值时显示按钮,否则隐藏 --><button v-show="user.username">您好,{{ user.username }}!</button></div></div>
</template><script>
import { ref } from 'vue'
export default {name: 'Directives',setup() {const type = ref('B')// 定义用户数据(有username则显示按钮,空则隐藏)const user = ref({ username: '张飞' }) // 改成ref('')则按钮隐藏return { type, user }}
}
</script>
页面效果:
2. 显示切换(v-show)
用户是否登录:是
您好,张飞!(按钮显示)
如果把user
改成ref('')
,按钮会隐藏(DOM 中仍存在,样式为display: none
)。
2.3 关键对比:v-if vs v-show(新手必懂)
很多新手会混淆v-if
和v-show
,我们用表格讲清区别,避免用错场景:
对比维度 | v-if | v-show |
---|---|---|
核心原理 | 元素从 DOM 中 “添加 / 销毁” | 元素始终在 DOM,用display: none 切换 |
切换开销 | 高(需要销毁 / 重建元素) | 低(只改样式) |
初始渲染开销 | 低(假值时不渲染元素) | 高(无论真假都渲染元素) |
适用场景 | 切换频率低(比如登录 / 未登录状态) | 切换频率高(比如按钮显示 / 隐藏) |
是否支持<template> | 支持(可以包裹多个元素) | 不支持(只能作用于单个元素) |
易错点:
- 用
v-show
控制 “一次性” 状态(比如登录后不再切换):会浪费初始渲染性能,不如用v-if
; - 用
v-if
控制 “频繁切换” 的元素(比如 tab 切换):会频繁销毁 / 重建,导致页面卡顿,不如用v-show
。
2.4 列表渲染指令:v-for(高频使用)
作用:根据 “数组 / 对象”,循环渲染多个元素(比如循环显示列表、表格数据)。
核心规则:
- 必须加
:key
属性:Vue 用key
跟踪每个元素的身份,实现高效更新(key
必须是 “唯一值”,比如 ID,不能用index
!); - 语法:
v-for="(item, index) in 数组"
或v-for="(value, key, index) in 对象"
。
实战 1:遍历数组(显示用户列表)
<template><div class="directives-container"><!-- 3. 列表渲染:v-for(遍历数组) --><div class="section"><h2>3. 列表渲染(v-for遍历数组)</h2><p>三国人物列表:</p><!-- 方式1:只拿元素(item) --><ul><li v-for="person in persons" :key="person.id">{{ person.name }}({{ person.role }})</li></ul><!-- 方式2:拿元素+索引(item, index) --><ul><li v-for="(person, index) in persons" :key="person.id">{{ index + 1 }}. {{ person.name }}({{ person.role }})</li></ul></div></div>
</template><script>
import { ref } from 'vue'
export default {name: 'Directives',setup() {// 定义数组(每个元素有唯一id,用于key)const persons = ref([{ id: 1, name: '刘备', role: '主公' },{ id: 2, name: '关羽', role: '武将' },{ id: 3, name: '张飞', role: '武将' }])return { persons }}
}
</script>
页面效果:
3. 列表渲染(v-for遍历数组)
三国人物列表:
- 刘备(主公)
- 关羽(武将)
- 张飞(武将)1. 刘备(主公)
2. 关羽(武将)
3. 张飞(武将)
实战 2:遍历对象(显示详情)
如果数据是对象(比如一本书的信息),可以用v-for
遍历它的 “键(key)、值(value)、索引(index)”:
<template><div class="directives-container"><!-- 4. 列表渲染:v-for(遍历对象) --><div class="section"><h2>4. 列表渲染(v-for遍历对象)</h2><p>书籍信息:</p><ul><li v-for="(value, key, index) in book" :key="index">{{ index + 1 }}. {{ key }}:{{ value }}</li></ul></div></div>
</template><script>
import { ref } from 'vue'
export default {name: 'Directives',setup() {// 定义对象const book = ref({title: 'Study Vue3',author: '张三',publishedAt: '2025-05-10'})return { book }}
}
</script>
页面效果:
4. 列表渲染(v-for遍历对象)
书籍信息:
1. title:Study Vue3
2. author:张三
3. publishedAt:2025-05-10
易错点:v-for 的 key 绝对不能用 index!
很多新手会写v-for="(item, index) in list" :key="index"
,这是错误的!
- 问题:如果数组发生 “删除、插入”(比如删除第 2 个元素),
index
会重新排序,导致 Vue 认错元素,出现渲染错乱; - 正确做法:用元素的 “唯一标识” 当
key
(比如后端返回的id
、uuid
)。
2.5 属性绑定指令:v-bind(缩写:
)
作用:动态绑定 HTML 属性(比如value
、src
、class
、style
),让属性值能跟随数据变化。
核心语法:
- 完整写法:
v-bind:属性名="表达式"
- 缩写写法:
:属性名="表达式"
(推荐,更简洁)
实战 1:绑定 input 的 value 属性
<template><div class="directives-container"><!-- 5. 属性绑定:v-bind(缩写:) --><div class="section"><h2>5. 属性绑定(v-bind/:)</h2><!-- 完整写法:v-bind:value --><input type="text" v-bind:value="inputValue" placeholder="完整写法"><!-- 缩写写法::value(推荐) --><input type="text" :value="inputValue" placeholder="缩写写法" style="margin-left: 10px;"></div></div>
</template><script>
import { ref } from 'vue'
export default {name: 'Directives',setup() {// 定义输入框的默认值const inputValue = ref('请输入用户名')return { inputValue }}
}
</script>
页面效果:
两个输入框都会显示 “请输入用户名”,如果inputValue
变化(比如改成ref('请输入密码')
),两个输入框的值会同步更新。
实战 2:绑定图片 src(扩展)
除了value
,还能绑定src
、class
等属性:
<template><div class="section"><!-- 绑定图片src --><img :src="imgUrl" alt="Vue logo" style="width: 100px;"></div>
</template><script>
import { ref } from 'vue'
export default {name: 'Directives',setup() {// 绑定图片路径(@代表src目录)const imgUrl = ref('@/assets/logo.png')return { imgUrl }}
}
</script>
2.6 事件绑定指令:v-on(缩写@
)
作用:给元素绑定事件监听器(比如点击、提交、输入),触发时执行方法或表达式。
核心语法:
- 完整写法:
v-on:事件名="方法名/表达式"
- 缩写写法:
@事件名="方法名/表达式"
(推荐)
实战 1:绑定点击事件(执行方法)
<template><div class="directives-container"><!-- 6. 事件绑定:v-on(缩写@) --><div class="section"><h2>6. 事件绑定(v-on/@)</h2><!-- 完整写法:v-on:click --><button v-on:click="showAlert" style="margin-right: 10px;">点击弹窗(完整写法)</button><!-- 缩写写法:@click --><button @click="showAlert">点击弹窗(缩写写法)</button></div></div>
</template><script>
import { ref } from 'vue'
export default {name: 'Directives',setup() {// 定义事件方法const showAlert = () => {alert('点击了按钮!这是v-on绑定的事件~')}return { showAlert }}
}
</script>
页面效果:
点击任意按钮,都会弹出 “点击了按钮!这是 v-on 绑定的事件~”。
实战 2:内联表达式(简单逻辑)
如果逻辑简单(比如计数 + 1),不用写单独方法,直接用 “内联表达式”
<template><div class="section"><!-- 内联表达式:点击时count+1 --><button @click="count++">点击计数:{{ count }}</button></div>
</template><script>
import { ref } from 'vue'
export default {name: 'Directives',setup() {// 响应式计数(必须用ref,否则值变了页面不更)const count = ref(0)return { count }}
}
</script>
页面效果:
点击按钮,count
会从 0 开始递增,页面实时更新。
实战 3:事件修饰符(常用!)
事件修饰符是给事件加 “额外规则”(比如阻止默认行为、阻止冒泡),不用写原生 JS(比如e.preventDefault()
)。
常用修饰符:
.prevent
:阻止默认行为(比如表单提交不刷新页面);.stop
:阻止事件冒泡;.once
:事件只触发一次;
示例代码:
<template><div class="section"><h3>事件修饰符</h3><!-- 1. .prevent:阻止表单提交默认刷新 --><form @submit.prevent="handleSubmit"><button type="submit">提交表单(不刷新)</button></form><!-- 2. .once:按钮只点击一次有效 --><button @click.once="showOnce">只点击一次</button></div>
</template><script>
import { ref } from 'vue'
export default {name: 'Directives',setup() {const handleSubmit = () => {alert('表单提交了,页面没刷新!')}const showOnce = () => {alert('这个按钮只能点一次~')}return { handleSubmit, showOnce }}
}
</script>
2.7 双向绑定指令:v-model(表单核心)
作用:在 “表单元素”(输入框、复选框、下拉框等)上实现 “数据 - 视图双向绑定”——
- 视图变(用户输入):数据自动同步;
- 数据变(代码修改):视图自动更新。
实战 1:文本输入框(单行 / 多行)
<template><div class="directives-container"><!-- 7. 双向绑定:v-model --><div class="section"><h2>7. 双向绑定(v-model)</h2><!-- 单行文本 --><div><label>单行文本:</label><input v-model="message" placeholder="输入内容"><p>你输入的是:{{ message }}</p></div><!-- 多行文本 --><div style="margin-top: 10px;"><label>多行文本:</label><textarea v-model="message" placeholder="输入多行内容" rows="3"></textarea></div></div></div>
</template><script>
import { ref } from 'vue'
export default {name: 'Directives',setup() {// 双向绑定的数据(初始值)const message = ref('13800066677')return { message }}
}
</script>
页面效果:
- 修改单行输入框,
{{ message }}
和多行文本框会同步更新; - 修改多行文本框,单行输入框和
{{ message }}
也会同步更新 —— 这就是 “双向绑定”!
实战 2:复选框、单选框、下拉框
v-model
还支持其他表单元素,我们用表格整理常用场景:
表单类型 | 代码示例 | 数据类型 |
---|---|---|
单个复选框 | <input type="checkbox" v-model="isAgree"> 同意协议 | Boolean(true/false) |
多个复选框 | <input type="checkbox" v-model="hobbies" value="篮球"> 篮球 | Array(数组) |
单选框 | <input type="radio" v-model="gender" value="男"> 男 | String(字符串) |
下拉框 | <select v-model="city"><option value="北京">北京</option></select> | String/Array |
完整代码示例:
<template><div class="section"><!-- 复选框(单个) --><div><input type="checkbox" v-model="isAgree"> 同意用户协议<p>是否同意:{{ isAgree ? '是' : '否' }}</p></div><!-- 复选框(多个) --><div style="margin-top: 10px;"><label>爱好:</label><input type="checkbox" v-model="hobbies" value="篮球"> 篮球<input type="checkbox" v-model="hobbies" value="游戏"> 游戏<input type="checkbox" v-model="hobbies" value="读书"> 读书<p>你的爱好:{{ hobbies }}</p></div><!-- 单选框 --><div style="margin-top: 10px;"><label>性别:</label><input type="radio" v-model="gender" value="男" name="gender"> 男<input type="radio" v-model="gender" value="女" name="gender"> 女<p>你的性别:{{ gender }}</p></div><!-- 下拉框 --><div style="margin-top: 10px;"><label>城市:</label><select v-model="city"><option disabled value="">请选择</option><option value="北京">北京</option><option value="上海">上海</option><option value="广州">广州</option></select><p>选择的城市:{{ city }}</p></div></div>
</template><script>
import { ref } from 'vue'
export default {name: 'Directives',setup() {const isAgree = ref(false) // 单个复选框(布尔)const hobbies = ref([]) // 多个复选框(数组)const gender = ref('') // 单选框(字符串)const city = ref('') // 下拉框(字符串)return { isAgree, hobbies, gender, city }}
}
</script>
v-model 修饰符(实用!)
和v-on
一样,v-model
也有修饰符,解决常见需求:
修饰符 | 作用说明 | 示例代码 |
---|---|---|
.lazy | 从 “input 事件” 同步改为 “change 事件” 同步(输入完失去焦点才更新) | <input v-model.lazy="msg"> |
.number | 自动将输入值转为 “数字类型”(避免输入数字却得到字符串) | <input v-model.number="age" type="number"> |
.trim | 自动过滤输入值的 “首尾空白字符”(避免用户误输入空格) | <input v-model.trim="msg"> |
2.8 其他常用指令(了解即可)
除了上面的高频指令,Vue 还有几个实用的辅助指令,我们快速过一遍:
1. v-text:文本渲染(替代插值)
作用:更新元素的textContent
,和{{ }}
效果一样,但不会有 “插值闪烁”(页面加载时先显示{{ msg }}
,再替换成值)。
<template><div class="section"><h2>8. 其他指令</h2><!-- v-text:等同于{{ msg }} --><p v-text="msg"></p><p>{{ msg }}</p> <!-- 和上面效果一致 --></div>
</template><script>
import { ref } from 'vue'
export default {name: 'Directives',setup() {const msg = ref('这是v-text渲染的文本')return { msg }}
}
</script>
2. v-html:渲染 HTML(慎用!)
作用:更新元素的innerHTML
,能渲染 HTML 代码({{ }}
会把 HTML 当文本显示)
<template><div class="section"><!-- v-html:渲染HTML --><p v-html="htmlContent"></p><!-- 插值:显示HTML文本 --><p>{{ htmlContent }}</p></div>
</template><script>
import { ref } from 'vue'
export default {name: 'Directives',setup() {const htmlContent = ref('<span style="color: red;">这行字是红色的(v-html渲染)</span>')return { htmlContent }}
}
</script>
安全提醒:
v-html
会执行传入的 HTML 代码,绝对不能用在用户输入的内容上(比如评论、留言),否则会导致 XSS 攻击(注入恶意脚本)!只能用在 “自己可控的可信内容” 上。
3. v-cloak:解决插值闪烁
作用:页面加载时,Vue 未编译完成前,隐藏{{ }}
表达式,避免用户看到 “{{ msg }}
” 这样的原始文本。
<template><!-- v-cloak:编译完成后自动移除 --><div v-cloak>{{ msg }}</div>
</template><style>
/* 未编译前隐藏元素 */
[v-cloak] {display: none;
}
</style><script>
import { ref } from 'vue'
export default {setup() {const msg = ref('解决插值闪烁')return { msg }}
}
</script>
4. v-pre:跳过编译
作用:跳过元素和子元素的 Vue 编译,直接显示原始内容(比如要显示{{ msg }}
这个文本,而不是渲染它的值)。
<template><div class="section"><!-- v-pre:不编译,直接显示{{ msg }} --><p v-pre>{{ msg }}</p><!-- 正常编译:显示msg的值 --><p>{{ msg }}</p></div>
</template><script>
import { ref } from 'vue'
export default {setup() {const msg = ref('这是要渲染的值')return { msg }}
}
</script>
页面效果:
- 第一个
p
显示:{{ msg }}
(未编译); - 第二个
p
显示:这是要渲染的值
(已编译)。
5. v-once:只渲染一次
作用:元素和组件只渲染一次,后续数据变化不会更新(用于固定不变的内容,优化性能)。
<template><div class="section"><!-- v-once:只渲染一次,count变了也不更 --><p v-once>初始计数:{{ count }}</p><!-- 正常渲染:count变了会更新 --><p>实时计数:{{ count }}</p><button @click="count++">count+1</button></div>
</template><script>
import { ref } from 'vue'
export default {setup() {const count = ref(0)return { count }}
}
</script>
页面效果:
点击按钮,“实时计数” 会递增,但 “初始计数” 始终显示0
(只渲染一次)。
三、进阶:自定义指令(自己写指令)
除了 Vue 自带的内置指令,我们还能根据需求 “自定义指令”(比如实现 “自动聚焦输入框”、“拖拽元素” 等功能)。
3.1 自定义指令的两种注册方式
1. 全局自定义指令(整个项目可用)
在main.js
中注册,所有组件都能使用:
// main.js(Vue3)
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'const app = createApp(App)// 注册全局指令v-focus:自动聚焦输入框
app.directive('focus', {// 钩子函数:元素挂载到DOM时执行mounted(el) {el.focus() // 原生JS的聚焦方法}
})app.use(router).mount('#app')
使用全局指令:
<template><!-- 页面加载时,输入框自动聚焦 --><input v-focus placeholder="自动聚焦">
</template>
2. 局部自定义指令(只有当前组件可用)
在组件的directives
选项中注册,只在当前组件生效:
<template><div class="directives-container"><h2>9. 自定义指令(v-focus)</h2><!-- 使用局部指令v-focus --><input v-focus placeholder="局部指令:自动聚焦"></div>
</template><script>
import { ref } from 'vue'
export default {name: 'Directives',// 注册局部指令directives: {focus: {// 元素挂载时执行mounted(el) {el.focus()}}},setup() {return {}}
}
</script>
页面效果:
输入框加载后会自动聚焦(光标在输入框内)。
3.2 指令的钩子函数(了解)
自定义指令有 7 个钩子函数,用于在不同阶段执行逻辑(初学者不用深入,了解常用的即可):
钩子函数 | 执行时机 |
---|---|
created | 指令绑定到元素时(DOM 还没挂载) |
beforeMount | 指令绑定的元素挂载前 |
mounted | 指令绑定的元素挂载后(最常用,比如初始化 DOM 行为) |
beforeUpdate | 元素更新前 |
updated | 元素和子元素更新后 |
beforeUnmount | 元素卸载前 |
unmounted | 元素卸载后(比如清理定时器) |
四、指令总结(速查表格)
为了方便大家查阅,我们把所有常用指令整理成表格:
指令 | 核心作用 | 缩写 | 适用场景 |
---|---|---|---|
v-if / v-else-if / v-else | 条件渲染(销毁 / 重建元素) | - | 切换频率低的状态(登录 / 未登录) |
v-show | 显示切换(display: none ) | - | 切换频率高的元素(按钮显示 / 隐藏) |
v-for | 列表渲染(遍历数组 / 对象) | - | 显示列表、表格数据 |
v-bind | 动态绑定 HTML 属性 | : | 绑定src 、value 、class 等 |
v-on | 绑定事件监听器 | @ | 点击、提交、输入等事件 |
v-model | 表单双向绑定 | - | 输入框、复选框、下拉框等表单元素 |
v-text | 文本渲染(替代插值) | - | 避免插值闪烁 |
v-html | 渲染 HTML 内容 | - | 显示可信的 HTML 内容(慎用) |
v-cloak | 解决插值闪烁 | - | 页面加载时隐藏未编译的表达式 |
v-pre | 跳过编译 | - | 显示原始{{ }} 文本 |
v-once | 只渲染一次 | - | 固定不变的内容(优化性能) |
五、实战:完整指令测试组件代码
最后,我们把上面所有指令整合到directives.vue
中,大家可以直接复制运行,体验每个指令的效果:
<template><div class="directives-container"><h1>Vue指令完整实战</h1><!-- 1. v-if / v-else-if / v-else --><div class="section"><h2>1. 条件渲染(v-if)</h2><p>当前类型:{{ type }}</p><p v-if="type === 'A'">这是A类型</p><p v-else-if="type === 'B'">这是B类型</p><p v-else>这是其他类型</p></div><!-- 2. v-show --><div class="section"><h2>2. 显示切换(v-show)</h2><button v-show="user.username">您好,{{ user.username }}!</button></div><!-- 3. v-for --><div class="section"><h2>3. 列表渲染(v-for)</h2><ul><li v-for="(person, index) in persons" :key="person.id">{{ index+1 }}. {{ person.name }}({{ person.role }})</li></ul></div><!-- 4. v-bind --><div class="section"><h2>4. 属性绑定(v-bind/:)</h2><input :value="inputValue" placeholder="v-bind绑定value"></div><!-- 5. v-on --><div class="section"><h2>5. 事件绑定(v-on/@)</h2><button @click="showAlert">点击弹窗</button><button @click="count++" style="margin-left: 10px;">count: {{ count }}</button></div><!-- 6. v-model --><div class="section"><h2>6. 双向绑定(v-model)</h2><input v-model="message" placeholder="输入内容"><p>你输入的:{{ message }}</p></div><!-- 7. 其他指令 --><div class="section"><h2>7. 其他指令</h2><p v-text="vTextMsg"></p> <!-- v-text --><p v-html="vHtmlMsg"></p> <!-- v-html --><p v-once>初始count:{{ count }}</p> <!-- v-once --></div><!-- 8. 自定义指令v-focus --><div class="section"><h2>8. 自定义指令(v-focus)</h2><input v-focus placeholder="自动聚焦"></div></div>
</template><script>
import { ref } from 'vue'
export default {name: 'Directives',// 局部自定义指令directives: {focus: {mounted(el) {el.focus()}}},setup() {// 1. v-if数据const type = ref('B')// 2. v-show数据const user = ref({ username: '张飞' })// 3. v-for数据const persons = ref([{ id: 1, name: '刘备', role: '主公' },{ id: 2, name: '关羽', role: '武将' },{ id: 3, name: '张飞', role: '武将' }])// 4. v-bind数据const inputValue = ref('v-bind绑定的值')// 5. v-on数据const count = ref(0)const showAlert = () => alert('v-on绑定的事件!')// 6. v-model数据const message = ref('初始内容')// 7. 其他指令数据const vTextMsg = ref('v-text渲染的文本')const vHtmlMsg = ref('<span style="color: red;">v-html渲染的红色文本</span>')return {type, user, persons, inputValue,count, showAlert, message,vTextMsg, vHtmlMsg}}
}
</script><style scoped>
.directives-container {padding: 20px;max-width: 1000px;margin: 0 auto;font-family: Arial, sans-serif;
}
.section {margin: 25px 0;padding: 15px;border: 1px dashed #ccc;border-radius: 4px;
}
h2 {margin-top: 0;font-size: 18px;color: #333;
}
button {padding: 6px 12px;cursor: pointer;border: 1px solid #42b983;background: #42b983;color: white;border-radius: 4px;
}
input {padding: 6px;border: 1px solid #ddd;border-radius: 4px;
}
</style>
六、新手常见坑点(避坑指南)
- v-for 忘记加:key:导致列表更新时渲染错乱,必须用唯一值(如 ID)当 key;
- v-if 和 v-for 一起用:Vue 会先执行 v-for 再执行 v-if,浪费性能,建议在外层用 v-if 包裹;
- v-model 用在非表单元素:v-model 只支持表单元素(input、select 等),用在 div 上会报错;
- v-html 用在用户输入内容:导致 XSS 攻击,只用于可信内容;
- Vue3 的 setup 中不用 ref:普通数据(如
let count = 0
)不是响应式的,必须用ref(count)
; - v-bind 和 v-model 混淆:v-bind 是 “单向绑定”(数据→视图),v-model 是 “双向绑定”(数据↔视图)。
掌握这些指令后,我们就能实现大部分页面交互需求了!后续我们会学习 Vue 的 “组件通信”“生命周期” 等进阶知识,继续加油~