当前位置: 首页 > news >正文

Vue.js 指令系统完全指南:深入理解 v- 指令

Vue.js 的指令系统是其最强大的特性之一,通过以 v- 开头的特殊属性,我们可以在模板中声明式地绑定底层Vue实例的数据。本文将深入讲解Vue中最重要的指令,帮助掌握Vue的核心功能。

文章目录

    • 1. v-model:双向数据绑定的核心
      • 基本用法
      • 修饰符
      • 自定义组件中的 v-model
    • 2. v-bind:属性绑定的万能钥匙
      • 基本用法
      • 动态属性名
    • 3. v-if / v-else-if / v-else:条件渲染
      • 基本用法
      • v-if vs v-show
    • 4. v-for:列表渲染
      • 基本用法
      • 维护状态(key的重要性)
    • 5. v-on:事件处理
      • 基本用法
      • 事件修饰符
      • 按键修饰符
    • 6. 其他重要指令
      • v-text 和 v-html
      • v-show
      • v-pre
      • v-once
      • v-cloak
    • 7. 自定义指令
      • 全局注册
      • 局部注册
      • 指令钩子函数
      • 高级自定义指令示例
    • 8. 实践
      • 指令实践
  • Vue.js 指令快速参考表
    • 核心指令对照表
    • 常用修饰符详解
      • v-model 修饰符
      • v-on 事件修饰符
      • v-on 按键修饰符
    • 使用场景对比
      • v-if vs v-show
      • v-for 使用要点
    • 最佳实践速查
      • ✅ 推荐做法
      • ❌ 避免做法
    • 自定义指令语法
      • 注册方式
      • 钩子函数
      • 参数说明


在这里插入图片描述

1. v-model:双向数据绑定的核心

基本用法

v-model 是Vue中实现双向数据绑定的指令,主要用于表单元素。

<template><div><!-- 文本输入 --><input v-model="message" placeholder="输入消息"><p>消息是: {{ message }}</p><!-- 多行文本 --><textarea v-model="text" placeholder="多行文本"></textarea><!-- 复选框 --><input type="checkbox" id="checkbox" v-model="checked"><label for="checkbox">{{ checked }}</label><!-- 单选按钮 --><input type="radio" id="one" value="One" v-model="picked"><label for="one">One</label><input type="radio" id="two" value="Two" v-model="picked"><label for="two">Two</label><!-- 选择框 --><select v-model="selected"><option disabled value="">请选择</option><option>A</option><option>B</option><option>C</option></select></div>
</template><script>
export default {data() {return {message: '',text: '',checked: false,picked: '',selected: ''}}
}
</script>

修饰符

v-model 提供了三个有用的修饰符:

<!-- .lazy - 在 change 事件而非 input 事件触发时更新 -->
<input v-model.lazy="msg"><!-- .number - 自动将用户输入转换为数值类型 -->
<input v-model.number="age" type="number"><!-- .trim - 自动过滤用户输入的首尾空白字符 -->
<input v-model.trim="msg">

自定义组件中的 v-model

<!-- 父组件 -->
<custom-input v-model="searchText"></custom-input><!-- 子组件 CustomInput.vue -->
<template><input:value="modelValue"@input="$emit('update:modelValue', $event.target.value)">
</template><script>
export default {props: ['modelValue'],emits: ['update:modelValue']
}
</script>

2. v-bind:属性绑定的万能钥匙

基本用法

v-bind 用于动态绑定一个或多个属性,或组件 prop 到表达式。

<template><div><!-- 绑定属性 --><img v-bind:src="imageSrc" v-bind:alt="imageAlt"><!-- 缩写语法 --><img :src="imageSrc" :alt="imageAlt"><!-- 绑定类名 --><div :class="{ active: isActive, 'text-danger': hasError }"></div><div :class="[activeClass, errorClass]"></div><div :class="classObject"></div><!-- 绑定样式 --><div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div><div :style="[baseStyles, overridingStyles]"></div><div :style="styleObject"></div></div>
</template><script>
export default {data() {return {imageSrc: 'https://example.com/image.jpg',imageAlt: '示例图片',isActive: true,hasError: false,activeClass: 'active',errorClass: 'text-danger',classObject: {active: true,'text-danger': false},activeColor: 'red',fontSize: 30,styleObject: {color: 'red',fontSize: '13px'},baseStyles: { color: 'blue' },overridingStyles: { fontSize: '20px' }}}
}
</script>

动态属性名

<template><!-- 动态属性名 --><a :[attributeName]="url">链接</a><!-- 当 attributeName 为 "href" 时,等价于 --><a :href="url">链接</a>
</template><script>
export default {data() {return {attributeName: 'href',url: 'https://www.example.com'}}
}
</script>

3. v-if / v-else-if / v-else:条件渲染

基本用法

这些指令用于条件性地渲染元素。

<template><div><h1 v-if="awesome">Vue is awesome!</h1><h1 v-else>Oh no 😢</h1><!-- 多条件判断 --><div v-if="type === 'A'">A</div><div v-else-if="type === 'B'">B</div><div v-else-if="type === 'C'">C</div><div v-else>Not A/B/C</div><!-- 使用 template 包装多个元素 --><template v-if="loginType === 'username'"><label>Username</label><input placeholder="Enter your username" key="username-input"></template><template v-else><label>Email</label><input placeholder="Enter your email address" key="email-input"></template></div>
</template><script>
export default {data() {return {awesome: true,type: 'A',loginType: 'username'}}
}
</script>

v-if vs v-show

<template><div><!-- v-if 是"真正"的条件渲染,会销毁和重建元素 --><p v-if="showIf">通过 v-if 显示</p><!-- v-show 只是简单地切换元素的 CSS display 属性 --><p v-show="showShow">通过 v-show 显示</p></div>
</template><script>
export default {data() {return {showIf: true,showShow: true}}
}
</script>

使用建议:

  • 如果需要非常频繁地切换,则使用 v-show
  • 如果在运行时条件很少改变,则使用 v-if

4. v-for:列表渲染

基本用法

v-for 指令用于基于源数据多次渲染元素或模板块。

<template><div><!-- 遍历数组 --><ul><li v-for="item in items" :key="item.id">{{ item.message }}</li></ul><!-- 带索引的遍历 --><ul><li v-for="(item, index) in items" :key="item.id">{{ index }} - {{ item.message }}</li></ul><!-- 遍历对象 --><ul><li v-for="value in object" :key="value">{{ value }}</li></ul><!-- 遍历对象,包含键名 --><ul><li v-for="(value, name) in object" :key="name">{{ name }}: {{ value }}</li></ul><!-- 遍历对象,包含键名和索引 --><ul><li v-for="(value, name, index) in object" :key="name">{{ index }}. {{ name }}: {{ value }}</li></ul><!-- 遍历数字 --><span v-for="n in 10" :key="n">{{ n }}</span></div>
</template><script>
export default {data() {return {items: [{ id: 1, message: 'Foo' },{ id: 2, message: 'Bar' }],object: {title: 'How to do lists in Vue',author: 'Jane Doe',publishedAt: '2016-04-10'}}}
}
</script>

维护状态(key的重要性)

<template><div><!-- 不推荐:没有key --><div v-for="item in items">{{ item.name }}</div><!-- 推荐:使用唯一的key --><div v-for="item in items" :key="item.id">{{ item.name }}</div><!-- 数组变更方法 --><button @click="addItem">添加项目</button><button @click="removeItem">删除项目</button><button @click="updateItem">更新项目</button></div>
</template><script>
export default {data() {return {items: [{ id: 1, name: '项目1' },{ id: 2, name: '项目2' }]}},methods: {addItem() {this.items.push({ id: Date.now(), name: `项目${this.items.length + 1}` })},removeItem() {this.items.pop()},updateItem() {if (this.items.length > 0) {this.items[0].name = '更新的项目1'}}}
}
</script>

5. v-on:事件处理

基本用法

v-on 指令用于监听DOM事件,并在触发时执行JavaScript代码。

<template><div><!-- 基本用法 --><button v-on:click="counter += 1">Add 1</button><p>按钮被点击了 {{ counter }} 次</p><!-- 缩写语法 --><button @click="greet">Greet</button><!-- 内联处理器中的方法 --><button @click="say('hi')">Say hi</button><button @click="say('what')">Say what</button><!-- 访问原始的DOM事件 --><button @click="warn('Form cannot be submitted yet.', $event)">Submit</button><!-- 多个事件处理器 --><button @click="one($event), two($event)">Submit</button></div>
</template><script>
export default {data() {return {counter: 0,name: 'Vue.js'}},methods: {greet(event) {alert('Hello ' + this.name + '!')if (event) {alert(event.target.tagName)}},say(message) {alert(message)},warn(message, event) {if (event) {event.preventDefault()}alert(message)},one(event) {console.log('第一个处理器')},two(event) {console.log('第二个处理器')}}
}
</script>

事件修饰符

Vue为 v-on 提供了事件修饰符来处理DOM事件细节。

<template><div><!-- 阻止单击事件继续传播 --><a @click.stop="doThis"></a><!-- 提交事件不再重载页面 --><form @submit.prevent="onSubmit"></form><!-- 修饰符可以串联 --><a @click.stop.prevent="doThat"></a><!-- 只有修饰符 --><form @submit.prevent></form><!-- 添加事件监听器时使用事件捕获模式 --><div @click.capture="doThis">...</div><!-- 只当在 event.target 是当前元素自身时触发处理函数 --><div @click.self="doThat">...</div><!-- 点击事件将只会触发一次 --><a @click.once="doThis"></a><!-- 滚动事件的默认行为将会立即触发,而不会等待onScroll完成 --><div @scroll.passive="onScroll">...</div></div>
</template>

按键修饰符

<template><div><!-- 只有在 key 是 Enter 时调用 vm.submit() --><input @keyup.enter="submit"><!-- 其他按键修饰符 --><input @keyup.tab="tabHandler"><input @keyup.delete="deleteHandler"><input @keyup.esc="escHandler"><input @keyup.space="spaceHandler"><input @keyup.up="upHandler"><input @keyup.down="downHandler"><input @keyup.left="leftHandler"><input @keyup.right="rightHandler"><!-- 系统修饰键 --><input @keyup.ctrl="ctrlHandler"><input @keyup.alt="altHandler"><input @keyup.shift="shiftHandler"><input @keyup.meta="metaHandler"><!-- 组合使用 --><input @keyup.ctrl.enter="ctrlEnterHandler"><!-- 鼠标按钮修饰符 --><button @click.left="leftClick">左键</button><button @click.right="rightClick">右键</button><button @click.middle="middleClick">中键</button></div>
</template>

6. 其他重要指令

v-text 和 v-html

<template><div><!-- v-text:更新元素的textContent --><span v-text="msg"></span><!-- 等价于 --><span>{{ msg }}</span><!-- v-html:更新元素的innerHTML --><p v-html="html"></p></div>
</template><script>
export default {data() {return {msg: 'Hello World',html: '<strong>粗体文本</strong>'}}
}
</script>

v-show

<template><div><!-- 根据表达式的真假值,切换元素的display CSS属性 --><h1 v-show="ok">Hello!</h1></div>
</template><script>
export default {data() {return {ok: true}}
}
</script>

v-pre

<template><div><!-- 跳过这个元素和它的子元素的编译过程 --><span v-pre>{{ this will not be compiled }}</span></div>
</template>

v-once

<template><div><!-- 只渲染元素和组件一次 --><h1 v-once>{{ title }}</h1><!-- 这也适用于子组件 --><my-component v-once :comment="msg"></my-component><!-- 带有v-for的v-once --><ul><li v-for="i in list" v-once :key="i">{{ i }}</li></ul></div>
</template><script>
export default {data() {return {title: '只渲染一次的标题',msg: '这是一条消息',list: [1, 2, 3]}}
}
</script>

v-cloak

<template><!-- 防止页面加载时显示未编译的Mustache标签 --><div v-cloak>{{ message }}</div>
</template><style>
[v-cloak] {display: none;
}
</style><script>
export default {data() {return {message: 'Hello World'}}
}
</script>

7. 自定义指令

全局注册

// main.js
const app = createApp({})// 注册一个全局自定义指令 v-focus
app.directive('focus', {// 当被绑定的元素挂载到DOM中时...mounted(el) {// 聚焦元素el.focus()}
})

局部注册

<template><input v-focus />
</template><script>
export default {directives: {// 在模板中启用v-focusfocus: {// 指令的定义mounted(el) {el.focus()}}}
}
</script>

指令钩子函数

const myDirective = {// 在绑定元素的父组件被挂载前调用beforeMount(el, binding, vnode, prevVnode) {},// 在元素被插入到DOM前调用mounted(el, binding, vnode, prevVnode) {},// 绑定元素的父组件更新前调用beforeUpdate(el, binding, vnode, prevVnode) {},// 在绑定元素的父组件及他自己的所有子节点都更新后调用updated(el, binding, vnode, prevVnode) {},// 绑定元素的父组件卸载前调用beforeUnmount(el, binding, vnode, prevVnode) {},// 绑定元素的父组件卸载后调用unmounted(el, binding, vnode, prevVnode) {}
}

高级自定义指令示例

// 颜色指令
app.directive('color', {mounted(el, binding) {el.style.color = binding.value},updated(el, binding) {el.style.color = binding.value}
})// 权限指令
app.directive('permission', {mounted(el, binding) {const { value } = bindingconst roles = ['admin', 'user'] // 从store或其他地方获取用户角色if (value && value instanceof Array && value.length > 0) {const permissionRoles = valueconst hasPermission = roles.some(role => {return permissionRoles.includes(role)})if (!hasPermission) {el.parentNode && el.parentNode.removeChild(el)}}}
})

8. 实践

指令实践

  1. 合理选择v-if和v-show

    • 频繁切换使用v-show
    • 条件很少改变使用v-if
  2. v-for必须使用key

    <!-- 推荐 -->
    <li v-for="item in items" :key="item.id">{{ item.name }}</li><!-- 不推荐 -->
    <li v-for="item in items">{{ item.name }}</li>
    
  3. 避免v-if和v-for同时使用

    <!-- 不推荐 -->
    <li v-for="user in users" v-if="user.isActive" :key="user.id">{{ user.name }}
    </li><!-- 推荐:使用computed -->
    <li v-for="user in activeUsers" :key="user.id">{{ user.name }}
    </li>
    
  4. 事件处理器优化

    <!-- 推荐:使用方法 -->
    <button @click="handleClick">点击</button><!-- 不推荐:复杂的内联表达式 -->
    <button @click="items.push({ id: Date.now(), name: 'new' }), updateCount++">添加
    </button>
    

Vue.js 指令快速参考表

核心指令对照表

指令作用语法示例修饰符使用场景
v-model双向数据绑定<input v-model="message">.lazy .number .trim表单输入、自定义组件
v-bind单向属性绑定:src="url" :class="{active: isActive}"动态属性、样式、类名
v-if条件渲染(销毁/创建)<div v-if="show">content</div>条件很少改变的元素
v-else-if多条件渲染<div v-else-if="type === 'A'">A</div>多分支条件判断
v-else否则渲染<div v-else>default</div>条件渲染的最后分支
v-show条件显示(CSS display)<div v-show="visible">content</div>频繁切换显示/隐藏
v-for列表渲染<li v-for="item in items" :key="item.id">数组、对象、数字遍历
v-on事件监听@click="handler" @keyup.enter="submit".stop .prevent .once用户交互事件处理
v-text更新文本内容<span v-text="message"></span>纯文本显示
v-html更新HTML内容<div v-html="htmlContent"></div>动态HTML内容
v-pre跳过编译<span v-pre>{{ raw }}</span>显示原始模板语法
v-once只渲染一次<h1 v-once>{{ title }}</h1>静态内容性能优化
v-cloak隐藏未编译模板<div v-cloak>{{ message }}</div>防止模板闪烁

常用修饰符详解

v-model 修饰符

修饰符说明示例
.lazy在 change 事件触发时同步<input v-model.lazy="msg">
.number自动转换为数字类型<input v-model.number="age">
.trim自动去除首尾空格<input v-model.trim="msg">

v-on 事件修饰符

修饰符说明示例
.stop阻止事件冒泡@click.stop="doThis"
.prevent阻止默认行为@submit.prevent="onSubmit"
.capture使用事件捕获模式@click.capture="doThis"
.self只在事件目标是元素自身时触发@click.self="doThat"
.once事件只触发一次@click.once="doThis"
.passive立即触发默认行为@scroll.passive="onScroll"

v-on 按键修饰符

修饰符说明示例
.enter回车键@keyup.enter="submit"
.tabTab键@keyup.tab="nextField"
.delete删除键@keyup.delete="deleteItem"
.escEscape键@keyup.esc="cancel"
.space空格键@keyup.space="play"
.up/.down/.left/.right方向键@keyup.up="moveUp"
.ctrl/.alt/.shift/.meta系统修饰键@keyup.ctrl.enter="save"

使用场景对比

v-if vs v-show

特性v-ifv-show
渲染方式条件性渲染(真正的删除/创建)基于CSS display切换
切换开销高(重新渲染)低(只改变CSS)
初始开销低(条件为假时不渲染)高(总是渲染)
适用场景条件很少改变频繁切换
生命周期会触发组件的生命周期不会触发生命周期

v-for 使用要点

遍历类型语法参数说明
数组v-for="item in items"item: 数组元素
数组+索引v-for="(item, index) in items"item: 元素, index: 索引
对象v-for="value in object"value: 属性值
对象+键名v-for="(value, key) in object"value: 值, key: 键名
对象+键名+索引v-for="(value, key, index) in object"value: 值, key: 键名, index: 索引
数字v-for="n in 10"n: 1到10的数字

最佳实践速查

✅ 推荐做法

  • v-for 必须使用 :key
  • 使用计算属性代替复杂的模板表达式
  • 事件处理器使用方法而非内联表达式
  • 合理选择 v-if 和 v-show
  • 使用缩写语法(: 代替 v-bind:@ 代替 v-on:

❌ 避免做法

  • v-for 和 v-if 在同一元素上使用
  • 使用数组索引作为 key(除非必要)
  • 在模板中编写复杂逻辑
  • 忘记使用事件修饰符优化性能
  • 滥用 v-html(XSS风险)

自定义指令语法

注册方式

// 全局注册
app.directive('focus', {mounted(el) { el.focus() }
})// 局部注册
directives: {focus: {mounted(el) { el.focus() }}
}

钩子函数

钩子触发时机
beforeMount绑定元素的父组件被挂载前
mounted元素被插入到DOM后
beforeUpdate绑定元素的父组件更新前
updated父组件及所有子节点都更新后
beforeUnmount绑定元素的父组件卸载前
unmounted绑定元素的父组件卸载后

参数说明

directive(el, binding, vnode, prevVnode) {// el: 绑定的元素// binding: { value, oldValue, arg, modifiers, instance, dir }// vnode: 虚拟节点// prevVnode: 之前的虚拟节点
}
http://www.lryc.cn/news/603370.html

相关文章:

  • 智能图书馆管理系统开发实战系列(一):项目架构设计与技术选型
  • Ubuntu上开通Samba网络共享
  • Ambari 3.0.0 全网首发支持 Ubuntu 22!
  • Kafka——消费者组重平衡全流程解析
  • cpolar 内网穿透 ubuntu 使用石
  • Spark SQL 数组函数合集:array_agg、array_contains、array_sort…详解
  • 【MySQL】从连接数据库开始:JDBC 编程入门指南
  • Vim与VS Code
  • 【CodeTop】每日练习 2025.7.29
  • LibTorch使用-基础版
  • Jetpack - Room(Room 引入、Room 优化)
  • Spring Boot 自动配置:从 2.x 到 3.x 的进化之路
  • 牛顿拉夫逊法PQ分解法计算潮流MATLAB程序计算模型。
  • 微信小程序私密消息
  • GaussDB 数据库架构师修炼(十) 性能诊断常用视图
  • 原生html+js+jq+less 实现时间区间下拉弹窗选择器
  • 鸿蒙网络编程系列59-仓颉版TLS回声服务器示例
  • 42、鸿蒙HarmonyOS Next开发:应用上下文Context
  • Apache Ignite 的分布式原子类型(Atomic Types)
  • 专业Python爬虫实战教程:逆向加密接口与验证码突破完整案例
  • 【NLP舆情分析】基于python微博舆情分析可视化系统(flask+pandas+echarts) 视频教程 - 微博文章数据可视化分析-文章评论量分析实现
  • Apache Ignite Cluster Groups的介绍
  • U3D中的package
  • 【PHP】Swoole:CentOS安装Composer+Hyperf
  • vue2 使用liveplayer加载视频
  • .NET Core 3.1 升级到 .NET 8
  • 自学嵌入式 day37 HTML
  • 前端代码格式化工具HTML离线版
  • LangChain学习笔记01---基本概念及使用
  • SkSurface---像素的容器:表面