Skip to content

指令

Vue 的指令(Directives)是带有 v- 前缀的特殊属性,用于动态操作 DOM。

v-bind(动态属性绑定)

作用

动态绑定 HTML 属性(如 idclassstyle)或组件 props

语法

html
<a v-bind:href="url">链接</a>
<!-- 简写(推荐) -->
<a :href="url">链接</a>

常见用法

  1. 绑定 class

    html
    <div :class="{ active: isActive, 'text-danger': hasError }"></div>
    javascript
    data() {
      return {
        isActive: true,
        hasError: false
      };
    }
  2. 绑定 style

    html
    <div :style="{ color: textColor, fontSize: size + 'px' }"></div>
  3. 绑定组件 props

    html
    <ChildComponent :title="parentTitle" />

特点

  • 属性值可以是动态变量或 JS 表达式。
  • 简写方式 : 更简洁。

v-model(双向数据绑定)

作用

在表单输入元素(如 <input><select>)和组件上实现双向数据绑定。

语法

html
<input v-model="message" />
<!-- 等价于 -->
<input :value="message" @input="message = $event.target.value" />

v-model 基础用法

表单元素绑定

vue
<template>
  <!-- 文本输入 -->
  <input v-model="message" placeholder="请输入">
  <p>输入的内容: {{ message }}</p>

  <!-- 复选框 -->
  <input type="checkbox" v-model="checked">
  <p>复选框状态: {{ checked }}</p>

  <!-- 单选按钮 -->
  <input type="radio" value="A" v-model="picked">
  <input type="radio" value="B" v-model="picked">
  <p>选择的值: {{ picked }}</p>

  <!-- 下拉选择 -->
  <select v-model="selected">
    <option value="apple">苹果</option>
    <option value="banana">香蕉</option>
  </select>
  <p>选择的水果: {{ selected }}</p>
</template>

<script setup>
import { ref } from 'vue'

const message = ref('')
const checked = ref(false)
const picked = ref('A')
const selected = ref('apple')
</script>

组件绑定

vue
<CustomInput v-model="inputValue" />

<!-- 等价于 -->
<CustomInput 
  :modelValue="inputValue"
  @update:modelValue="newValue => inputValue = newValue"
/>

内置修饰符

Vue 提供了以下常用修饰符:

.lazy

  • 作用:将 input 事件改为 change 事件
  • 使用场景:避免输入时频繁更新,失去焦点时更新
vue
<input v-model.lazy="message">
<!-- 等价于 -->
<input :value="message" @change="message = $event.target.value">

.number

  • 作用:自动将输入值转为数字类型
  • 注意:如果转换失败会返回原始字符串
vue
<input v-model.number="age" type="number">
<script setup>
const age = ref(0) // 确保初始值是数字类型
</script>

.trim

  • 作用:自动去除用户输入的首尾空格
vue
<input v-model.trim="username">

修饰符组合使用

可以同时使用多个修饰符:

vue
<input v-model.lazy.trim="searchText">

执行顺序:trimnumber (如果存在) → lazy

自定义组件的高级用法

多 v-model 绑定

Vue 3 支持在单个组件上绑定多个 v-model

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

<!-- 等价于 -->
<UserName
  :first-name="firstName"
  @update:first-name="firstName = $event"
  :last-name="lastName"
  @update:last-name="lastName = $event"
/>

自定义修饰符

可以通过 modelModifiers prop 实现自定义修饰符:

vue
<template>
  <MyComponent v-model.capitalize="text" />
</template>

<script setup>
const text = ref('')
</script>

组件实现:

vue
<script setup>
const props = defineProps({
  modelValue: String,
  modelModifiers: { default: () => ({}) }
})

const emit = defineEmits(['update:modelValue'])

function emitValue(e) {
  let value = e.target.value
  if (props.modelModifiers.capitalize) {
    value = value.charAt(0).toUpperCase() + value.slice(1)
  }
  emit('update:modelValue', value)
}
</script>

<template>
  <input :value="modelValue" @input="emitValue" />
</template>

修饰符原理剖析

v-model 本质上是语法糖,编译后的代码:

vue
<input v-model="message">

<!-- 编译为 -->
<input 
  :value="message"
  @input="message = $event.target.value"
>

当添加修饰符时:

vue
<input v-model.lazy.number="count">

<!-- 编译为 -->
<input
  :value="count"
  @change="count = Number($event.target.value)"
>

最佳实践

  1. 表单验证:结合 .lazy 减少验证频率

    vue
    <input v-model.lazy="email" @blur="validateEmail">
  2. 数字输入:始终使用 .number 配合 type="number"

    vue
    <input v-model.number="quantity" type="number" min="1">
  3. 性能优化:对大表单使用 .lazy 减少响应式更新

  4. 移动端适配:在移动设备上考虑使用 .trim 避免键盘空格问题

常见问题

为什么 v-model.number 有时无效?

  • 输入非数字字符时返回原始字符串
  • 解决方案:配合 type="number" 并处理边界情况

如何阻止无效输入?

vue
<input 
  v-model="numberInput"
  @keypress="isNumber($event)"
>

<script>
function isNumber(evt) {
  const charCode = evt.keyCode || evt.which
  if (charCode > 31 && (charCode < 48 || charCode > 57)) {
    evt.preventDefault()
  }
}
</script>

修饰符执行顺序

  1. trim:去除首尾空格
  2. number:尝试转换为数字
  3. lazy:改变触发事件

v-for(列表渲染)

作用

基于数组或对象循环渲染元素。

语法

html
<li v-for="(item, index) in items" :key="item.id">
  {{ index }} - {{ item.name }}
</li>

关键点

  1. 必须指定 :key

    • 提高 Diff 算法效率,避免渲染错误。
    • 推荐使用唯一 ID(如 item.id),而非 index
  2. 遍历对象

    html
    <div v-for="(value, key) in object" :key="key">
      {{ key }}: {{ value }}
    </div>
  3. 范围迭代

    html
    <span v-for="n in 10">{{ n }}</span> <!-- 1 到 10 -->

v-if / v-show(条件渲染)

v-if

  • 特点:条件为 false 时,元素从 DOM 中移除。
  • 适用场景:初始渲染条件较少变化时(如权限控制)。
html
<p v-if="isAdmin">管理员可见</p>
<p v-else-if="isUser">普通用户可见</p>
<p v-else>访客可见</p>

v-show

  • 特点:通过 display: none 切换可见性,DOM 始终存在。
  • 适用场景:频繁切换显示状态(如选项卡)。
html
<div v-show="isVisible">显示/隐藏内容</div>

对比

指令DOM 操作初始渲染开销切换开销
v-if销毁/重建
v-showdisplay: none高(需渲染)

v-on(事件绑定)

作用

监听 DOM 事件(如点击、输入)并执行方法。

语法

html
<button v-on:click="handleClick">点击</button>
<!-- 简写(推荐) -->
<button @click="handleClick">点击</button>

事件修饰符

修饰符作用示例
.stop阻止事件冒泡@click.stop="doThis"
.prevent阻止默认行为@submit.prevent="onSubmit"
.once只触发一次@click.once="doThis"
.native监听组件根元素原生事件<MyComponent @click.native="handleClick" />

按键修饰符

html
<input @keyup.enter="submit" />  <!-- 回车触发 -->
<input @keyup.esc="closeModal" /> <!-- ESC 键触发 -->

传递参数

html
<button @click="say('Hello')">打招呼</button>
<button @click="say('Hi', $event)">带事件对象</button>
javascript
methods: {
  say(message, event) {
    console.log(message, event);
  }
}

其他常用指令

v-html

渲染原始 HTML(注意 XSS 风险):

html
<div v-html="rawHtml"></div>

v-slot

用于插槽作用域(缩写为 #):

html
<template v-slot:header="slotProps">
  {{ slotProps.user.name }}
</template>
<!-- 简写 -->
<template #header="{ user }">
  {{ user.name }}
</template>

v-pre

跳过编译,直接输出原始内容:

html
<span v-pre>{{ 这里不会编译 }}</span> <!-- 输出 {{ 这里不会编译 }} -->

总结

指令核心用途关键注意点
v-bind动态绑定属性简写 :,支持对象/数组语法
v-model表单双向绑定修饰符:.lazy, .number, .trim
v-for列表渲染必须加 :key,避免用 index
v-if条件渲染(销毁 DOM)适合不频繁切换的场景
v-show条件渲染(CSS 隐藏)适合频繁切换
v-on事件绑定简写 @,修饰符丰富
编程洪同学服务平台是一个广泛收集编程相关内容和资源,旨在满足编程爱好者和专业开发人员的需求的网站。无论您是初学者还是经验丰富的开发者,都可以在这里找到有用的信息和资料,我们将助您提升编程技能和知识。
专业开发
高端定制
售后无忧
站内资源均为本站制作或收集于互联网等平台,如有侵权,请第一时间联系本站,敬请谅解!本站资源仅限于学习与参考,严禁用于各种非法活动,否则后果自行负责,本站概不承担!