Vue 指令(Directives)是 Vue.js 的一项核心功能,它们可以在 HTML 模板中以 v- 开头的特殊属性形式使用,用于将响应式数据绑定到 DOM 元素上或在 DOM 元素上进行一些操作。

Vue 指令是带有前缀 v- 的特殊 HTML 属性,它赋予 HTML 标签额外的功能。

与传统的 JavaScript 方法相比,使用 Vue 创建响应式页面要容易得多,并且需要的代码更少。

常用指令:

指令 描述
v-bind 用于将 Vue 实例的数据绑定到 HTML 元素的属性上。
v-if 用于根据表达式的值来条件性地渲染元素或组件。
v-show v-show 是 Vue.js 提供的一种指令,用于根据表达式的值来条件性地显示或隐藏元素。
v-for 用于根据数组或对象的属性值来循环渲染元素或组件。
v-on 用于在 HTML 元素上绑定事件监听器,使其能够触发 Vue 实例中的方法或函数。
v-model 用于在表单控件和 Vue 实例的数据之间创建双向数据绑定。

除了这些常用的指令,Vue 还提供了一些其他的指令,如 v-text、v-html 等,以及自定义指令,让开发者能够更加灵活地操作 DOM 元素。

一、属性绑定与事件绑定

1.属性绑定 (v-bind)

1.1基本概念

属性绑定是 Vue.js 的核心功能之一,通过 v-bind 指令实现数据到 HTML 属性的动态绑定,使属性值能够响应式更新。

1.2基本语法

<!-- 完整语法 -->
<img v-bind:src="imageSrc">

<!-- 简写语法 -->
<img :src="imageSrc">

1.3绑定到 class 属性

对象语法

通过对象动态切换 class,对象的键是类名,值是布尔值表达式:

<div :class="{ active: isActive, 'text-danger': hasError }"></div>
对应的数据:

javascript

data() {
  return {
    isActive: true,
    hasError: false
  }
}

数组语法

应用多个 class,数组中可以包含数据属性、对象或计算属性:

<div :class="[activeClass, errorClass]"></div>
对应的数据:

javascript

data() {
  return {
    activeClass: 'active',
    errorClass: 'text-danger'
  }
}

1.4绑定到 style 属性

对象语法

样式对象中的属性可以使用驼峰式或短横线分隔:

<div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
对应的数据:

javascript

data() {
  return {
    activeColor: 'red',
    fontSize: 30
  }
}

数组语法

将多个样式对象应用到同一个元素:

<div :style="[baseStyles, overridingStyles]"></div>

1.5绑定其他属性

属性绑定不仅限于 class 和 style,可以绑定到任何 HTML 属性:

<!-- 绑定 disabled 属性 -->
<button :disabled="isButtonDisabled">按钮</button>

<!-- 绑定动态属性名 -->
<div :[attributeName]="attributeValue"></div>

2.事件绑定 (v-on)

2.1基本概念

事件绑定通过 v-on 指令实现,用于监听 DOM 事件并执行相应的 JavaScript 代码。

2.2基本语法

<!-- 完整语法 -->
<button v-on:click="handleClick">点击</button>

<!-- 简写语法 -->
<button @click="handleClick">点击</button>

2.3事件处理方法

内联处理器

<button @click="count++">增加 {{ count }}</button>

方法处理器

<button @click="greet">问候</button>
对应的 JavaScript:

javascript

methods: {
  greet(event) {
    // event 是原生 DOM 事件
    alert('Hello!')
    console.log(event.target.tagName)
  }
}

传递参数

<button @click="say('hello', $event)">说 hello</button>
对应的 JavaScript:

javascript

methods: {
  say(message, event) {
    // 访问原生事件对象
    if (event) {
      event.preventDefault()
    }
    alert(message)
  }
}<button @click="say('hello', $event)">说 hello</button>
对应的 JavaScript:

javascript

methods: {
  say(message, event) {
    // 访问原生事件对象
    if (event) {
      event.preventDefault()
    }
    alert(message)
  }
}

2.4事件修饰符

事件修饰符是以点开头的特殊后缀,用于指示指令应该以特殊方式绑定:

.stop

阻止事件冒泡:

<a @click.stop="doThis"></a>

.prevent

阻止默认行为:

<form @submit.prevent="onSubmit"></form>

.capture

使用事件捕获模式:

<div @click.capture="doThis">...</div>

.self

只当事件是从侦听器绑定的元素本身触发时才触发回调:

<div @click.self="doThat">...</div>

.once

只触发一次:

<button @click.once="doThis"></button>

.passive

不阻止事件的默认行为,主要用于移动端性能优化:

<div @scroll.passive="onScroll">...</div>

2.5按键修饰符

用于监听特定键盘事件:

<!-- 只有在 key 是 Enter 时调用 vm.submit() -->
<input @keyup.enter="submit">

<!-- 处理 Ctrl + Click -->
<div @click.ctrl="doSomething">Do something</div>

常用按键修饰符:

.enter - 捕获"回车"键
.tab - 捕获"制表符"键
.delete - 捕获"删除"和"退格"键
.esc - 捕获"ESC"键
.space - 捕获"空格"键
.up - 捕获"上箭头"键
.down - 捕获"下箭头"键
.left - 捕获"左箭头"键
.right - 捕获"右箭头"键

二、条件与循环操作指令

1.条件指令

1.1v-if

工作原理:

  • v-if 是"真正"的条件渲染,在切换过程中条件块内的事件监听器和子组件会被销毁和重建
  • 当条件为 false 时,元素完全从 DOM 中移除
  • 支持 v-else-if 和 v-else 链式条件判断

性能特点:

  • 初始渲染条件为 false 时,不进行任何渲染操作
  • 切换开销较大,因为涉及 DOM 的添加和删除
<!-- 基础用法 -->
<div v-if="isVisible">可见内容</div>

<!-- 条件链 -->
<div v-if="type === 'A'">类型A</div>
<div v-else-if="type === 'B'">类型B</div>
<div v-else>其他类型</div>

<!-- 在 template 上使用 -->
<template v-if="showMultiple">
  <p>段落1</p>
  <p>段落2</p>
</template>

1.2v-show 

工作原理:

  • 元素始终会被渲染并保留在 DOM 中
  • 通过切换 CSS 的 display 属性来控制显示/隐藏
  • 不支持 <template> 元素

性能特点:

  • 初始渲染成本较高,无论条件如何都会渲染
  • 切换开销小,仅修改 CSS 属性
<div v-show="isActive">显示内容</div>

1.3使用场景对比

场景 推荐指令 理由
运行时很少改变的条件 v-if 避免不必要的初始渲染
频繁切换显示状态 v-show 切换性能更好
需要条件链判断 v-if 支持 else-if 和 else
初始状态多为隐藏 v-if 减少初始 DOM 节点

2.循环指令

2.1v-for 

遍历数组:

<!-- 基本数组遍历 -->
<ul>
  <li v-for="item in items" :key="item.id">
    {{ item.name }}
  </li>
</ul>

<!-- 带索引的遍历 -->
<ul>
  <li v-for="(item, index) in items" :key="item.id">
    {{ index }} - {{ item.name }}
  </li>
</ul>

遍历对象:

<!-- 对象属性遍历 -->
<ul>
  <li v-for="(value, key) in userObject" :key="key">
    {{ key }}: {{ value }}
  </li>
</ul>

<!-- 带索引的对象遍历 -->
<ul>
  <li v-for="(value, key, index) in userObject" :key="key">
    {{ index }}. {{ key }}: {{ value }}
  </li>
</ul>

遍历数值范围:

<!-- 从1开始到指定数字 -->
<span v-for="n in 5" :key="n">{{ n }} </span>
<!-- 输出:1 2 3 4 5 -->

2.1:key 属性的重要性

为什么需要 key:

  • 帮助 Vue 识别节点的唯一性
  • 优化虚拟 DOM 的 diff 算法
  • 维持组件状态和临时 DOM 状态

key 的选择原则:

  • 使用唯一标识符(如 id)
  • 避免使用索引作为 key(除非列表静态)
  • 确保 key 的稳定性
<!-- 好的实践 -->
<div v-for="user in users" :key="user.id">
  {{ user.name }}
</div>

<!-- 避免的做法 -->
<div v-for="(user, index) in users" :key="index">
  {{ user.name }}
</div>

2.3数组更新检测

响应式数组方法:
Vue 包装了以下数组方法,调用时会触发视图更新:push() - 末尾添加、pop() - 删除末尾、shift() - 删除开头、unshift() - 开头添加、splice() - 删除/添加、sort() - 排序、reverse() - 反转

// 这些操作会触发视图更新
this.items.push(newItem)
this.items.splice(0, 1) // 删除第一个元素

注意事项:

  • 直接通过索引修改不会触发更新:this.items[0] = newValue
  • 使用 Vue.set 或数组的 splice 方法解决

三、表单的双向绑定

1. v-model 基础概念

1.1 什么是 v-model

v-model 是 Vue 中用于实现表单元素和数据之间双向绑定的指令。当表单元素的值发生变化时,数据会自动更新;当数据发生变化时,表单元素的值也会相应更新。

1.2 v-model 的本质

v-model 实际上是语法糖,它结合了属性绑定和事件监听:

<!-- 以下两种写法是等价的 -->
<input v-model="message">

<input :value="message" @input="message = $event.target.value">

2. 不同类型表单元素的使用

2.1 文本输入框

单行文本输入框:

<input type="text" v-model="username">

多行文本域:

<textarea v-model="description"></textarea>

2.2 复选框

单个复选框:
绑定到布尔值,表示是否选中

<input type="checkbox" v-model="agree">

多个复选框:
绑定到数组,包含所有选中项的 value 值

<input type="checkbox" value="vue" v-model="skills">
<input type="checkbox" value="react" v-model="skills">

2.3 单选按钮

绑定到同一个变量,选中的按钮的 value 值会赋给该变量

<input type="radio" value="male" v-model="gender">
<input type="radio" value="female" v-model="gender">

2.4 选择框

单选下拉框:
绑定到选中的 option 的 value

<select v-model="selectedCity">
  <option value="beijing">北京</option>
  <option value="shanghai">上海</option>
</select>

多选下拉框:
绑定到数组,包含所有选中项的 value

<select v-model="selectedHobbies" multiple>
  <option value="reading">阅读</option>
  <option value="sports">运动</option>
</select>

3. v-model 修饰符

3.1 .lazy 修饰符

默认情况下,v-model 在 input 事件发生后同步数据。使用 .lazy 修饰符后,改为在 change 事件后同步。

<!-- 输入时不会立即更新,失去焦点时才更新 -->
<input v-model.lazy="message">

3.2 .number 修饰符

自动将用户输入的值转换为数字类型。如果无法解析,则返回原始值。

<input v-model.number="age" type="number">

3.3 .trim 修饰符

自动过滤用户输入的首尾空白字符。

<input v-model.trim="username">

4. 自定义组件中的 v-model

4.1 Vue3 中的变化

Vue3 对自定义组件的 v-model 进行了重大改进:

Vue3 中的写法:

<CustomComponent v-model="pageTitle" />

等价于:

<CustomComponent :modelValue="pageTitle" @update:modelValue="pageTitle = $event" />

4.2 在自定义组件中实现 v-model

子组件:

<template>
  <input
    :value="modelValue"
    @input="$emit('update:modelValue', $event.target.value)"
  >
</template>

<script>
export default {
  props: ['modelValue'],
  emits: ['update:modelValue']
}
</script>

4.3 多个 v-model 绑定

Vue3 支持在单个组件上使用多个 v-model:

<UserName
  v-model:first-name="first"
  v-model:last-name="last"
/>

对应的子组件:

<template>
  <input
    :value="firstName"
    @input="$emit('update:firstName', $event.target.value)"
  >
  <input
    :value="lastName"
    @input="$emit('update:lastName', $event.target.value)"
  >
</template>

<script>
export default {
  props: {
    firstName: String,
    lastName: String
  },
  emits: ['update:firstName', 'update:lastName']
}
</script>

5. 自定义修饰符

5.1 创建自定义修饰符

可以为组件的 v-model 添加自定义修饰符:

<MyComponent v-model.capitalize="myText" />

在组件中处理修饰符:

<script>
export default {
  props: {
    modelValue: String,
    modelModifiers: {
      default: () => ({})
    }
  },
  emits: ['update:modelValue'],
  methods: {
    emitValue(e) {
      let value = e.target.value
      if (this.modelModifiers.capitalize) {
        value = value.charAt(0).toUpperCase() + value.slice(1)
      }
      this.$emit('update:modelValue', value)
    }
  }
}
</script>

6. 实际应用注意事项

6.1 初始值设置

确保为 v-model 绑定的数据提供适当的初始值:

data() {
  return {
    // 文本输入框
    username: '',
    // 单个复选框
    agree: false,
    // 多个复选框
    skills: [],
    // 单选按钮
    gender: '',
    // 下拉选择
    selectedCity: ''
  }
}

6.2 性能考虑

  • 对于大型表单,考虑使用 .lazy 修饰符减少更新频率

  • 复杂表单建议使用 Vuex 或 Pinia 进行状态管理

6.3 表单验证

v-model 可以结合表单验证库使用,如 VeeValidate、Vuelidate 等,实现更强大的表单功能。

通过掌握这些 v-model 的使用技巧,可以更高效地处理 Vue3 应用中的表单交互,提升开发效率和用户体验。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐