Vue.js 2.x笔记:基本语法(2)

欢迎来到 Vue.js 2.x 系列笔记的第二部分!在第一部分中,我们学习了 Vue 实例的创建、数据绑定(如文本插值 {{ }}、v-bind 指令)、条件渲染(v-if/v-else)等基础语法。本文作为续篇,将深入讲解 Vue.js 2.x 中更核心的基础语法,包括事件处理、表单输入绑定、列表渲染、计算属性与侦听器以及类与样式绑定。这些内容是构建交互式 Vue 应用的基石,掌握它们将帮助你更高效地开发响应式界面。

目录#

  1. 事件处理(v-on)
    • 基本用法与简写
    • 事件修饰符
    • 按键修饰符
    • 实践与最佳实践
  2. 表单输入绑定(v-model)
    • 基础用法
    • 不同输入类型的绑定
    • v-model 修饰符
    • 实践与最佳实践
  3. 列表渲染(v-for)
    • 遍历数组与对象
    • 维护状态::key 属性
    • 数组更新检测
    • 实践与最佳实践
  4. 计算属性与侦听器
    • 计算属性(Computed)
    • 侦听器(Watch)
    • 计算属性 vs 侦听器
    • 实践与最佳实践
  5. 类与样式绑定
    • 绑定 HTML 类
    • 绑定内联样式
    • 实践与最佳实践
  6. 总结
  7. 参考资料

1. 事件处理(v-on)#

在 Vue 中,事件处理通过 v-on 指令实现,用于监听 DOM 事件(如点击、输入、提交等)并触发相应的方法。

1.1 基本用法与简写#

语法:
v-on:事件名="方法名" 或简写为 @事件名="方法名"。

示例:

<div id="app">
  <!-- 点击按钮触发 handleClick 方法 -->
  <button v-on:click="handleClick">点击我</button>
  <!-- 简写形式 -->
  <button @click="handleClick">点击我(简写)</button>
</div>
 
<script>
new Vue({
  el: '#app',
  methods: {
    handleClick() {
      alert('按钮被点击了!');
    }
  }
});
</script>

内联表达式:也可直接在指令中写简单表达式(不推荐复杂逻辑,建议抽离为方法):

<button @click="count += 1">计数器: {{ count }}</button>

1.2 事件修饰符#

DOM 事件有默认行为(如表单提交刷新页面、链接跳转)或冒泡机制,Vue 提供了事件修饰符简化这些操作,无需手动调用 event.preventDefault() 或 event.stopPropagation()。

常用修饰符:

  • .stop:阻止事件冒泡(event.stopPropagation())。
  • .prevent:阻止默认行为(event.preventDefault())。
  • .once:事件仅触发一次。
  • .self:仅当事件在元素本身触发时才执行(排除子元素冒泡)。

示例:

<!-- 阻止表单默认提交行为 -->
<form @submit.prevent="handleSubmit">
  <button type="submit">提交</button>
</form>
 
<!-- 阻止事件冒泡 -->
<div @click="parentClick">
  <button @click.stop="childClick">点击子元素</button>
</div>
 
<!-- 事件仅触发一次 -->
<button @click.once="handleOnce">只触发一次</button>

1.3 按键修饰符#

监听键盘事件时,可通过按键修饰符指定触发事件的按键(如 Enter、Esc)。

常用按键修饰符:

  • .enter:Enter 键。
  • .tab:Tab 键(需配合 keydown 事件)。
  • .esc:Esc 键。
  • .space:空格键。
  • 自定义按键码:通过 Vue.config.keyCodes 定义(Vue 2.x 特性)。

示例:

<!-- 按下 Enter 键触发提交 -->
<input @keyup.enter="submitForm" placeholder="按 Enter 提交">
 
<!-- 按下 Esc 键清空输入 -->
<input @keyup.esc="clearInput" v-model="inputValue">

1.4 实践与最佳实践#

  • 方法命名规范:事件处理方法建议以 handle 开头(如 handleSubmit、handleClick),明确其用途。
  • 避免内联复杂逻辑:内联表达式仅用于简单操作(如 count += 1),复杂逻辑应抽离为 methods 中的方法,提高可读性。
  • 优先使用事件修饰符:代替手动调用 event.preventDefault() 等,代码更简洁。
  • 传递事件对象:如需访问原生事件对象,可在方法中传入 $event:
    <button @click="handleClick($event, '参数')">点击</button>
    methods: {
      handleClick(event, param) {
        console.log(event.target, param); // 输出事件目标和参数
      }
    }

2. 表单输入绑定(v-model)#

v-model 是 Vue 提供的双向数据绑定指令,用于在表单元素(如输入框、复选框、下拉框)与 Vue 实例的 data 之间建立关联:用户输入更新数据,数据变化同步更新视图。

2.1 基础用法#

语法:
v-model="data属性名"

示例:

<div id="app">
  <input v-model="message" placeholder="输入内容">
  <p>你输入的是:{{ message }}</p>
</div>
 
<script>
new Vue({
  el: '#app',
  data: {
    message: ''
  }
});
</script>

2.2 不同输入类型的绑定#

v-model 可适配不同表单元素,行为略有差异:

2.2.1 文本框(text)与多行文本框(textarea)#

  • 绑定字符串,输入内容实时同步。
<!-- 单行文本 -->
<input type="text" v-model="username">
 
<!-- 多行文本(无需使用 {{ }} 插值,v-model 直接绑定) -->
<textarea v-model="description"></textarea>

2.2.2 复选框(checkbox)#

  • 单个复选框:绑定布尔值(true/false)。
  • 多个复选框:绑定数组,选中的值会加入数组。
<!-- 单个复选框 -->
<input type="checkbox" v-model="agree"> 同意协议({{ agree }})
 
<!-- 多个复选框(值为数组) -->
<div>
  <input type="checkbox" v-model="hobbies" value="reading"> 阅读
  <input type="checkbox" v-model="hobbies" value="sports"> 运动
  <input type="checkbox" v-model="hobbies" value="coding"> 编程
  <p>爱好:{{ hobbies }}</p> <!-- 选中的值组成数组,如 ["reading", "coding"] -->
</div>

2.2.3 单选框(radio)#

  • 绑定单个值,选中的 value 会赋给数据属性。
<div>
  <input type="radio" v-model="gender" value="male"> 男
  <input type="radio" v-model="gender" value="female"> 女
  <p>性别:{{ gender }}</p> <!-- 选中的值,如 "male" -->
</div>

2.2.4 下拉框(select)#

  • 单选:绑定单个值;多选:绑定数组(需添加 multiple 属性)。
<!-- 单选下拉框 -->
<select v-model="city">
  <option value="">请选择城市</option>
  <option value="beijing">北京</option>
  <option value="shanghai">上海</option>
</select>
<p>城市:{{ city }}</p>
 
<!-- 多选下拉框(按住 Ctrl 选择多个) -->
<select v-model="cities" multiple>
  <option value="beijing">北京</option>
  <option value="shanghai">上海</option>
  <option value="guangzhou">广州</option>
</select>
<p>选中城市:{{ cities }}</p> <!-- 数组,如 ["beijing", "guangzhou"] -->

2.3 v-model 修饰符#

v-model 提供修饰符优化数据处理:

  • .lazy:默认 v-model 在 input 事件中同步数据,.lazy 改为在 change 事件(如失焦或回车)时同步。

    <input v-model.lazy="message"> <!-- 失焦后才更新 message -->
  • .number:自动将输入值转为数字(若无法转为数字则保留原始值)。

    <input v-model.number="age" type="number"> <!-- age 会被转为 Number 类型 -->
  • .trim:自动去除输入值首尾的空格。

    <input v-model.trim="username"> <!-- 输入 "  Tom  " 会变为 "Tom" -->

2.4 实践与最佳实践#

  • 表单验证:结合 v-model 与计算属性/侦听器实现实时验证(如检查用户名长度、密码强度)。
  • 初始值匹配:确保 v-model 绑定的数据初始值类型与表单元素匹配(如复选框数组初始值应为 [],单选框初始值应为字符串)。
  • 避免过度使用 v-model:对于复杂表单,可考虑拆分组件或使用状态管理(如 Vuex),避免单个实例数据过于臃肿。

3. 列表渲染(v-for)#

v-for 指令用于基于数组或对象渲染列表,语法类似 JavaScript 的 for...in 循环。

3.1 遍历数组与对象#

3.1.1 遍历数组#

语法:v-for="(item, index) in items",其中 item 是数组元素,index 是索引(可选)。

<div id="app">
  <ul>
    <li v-for="(item, index) in fruits" :key="item.id">
      {{ index + 1 }}. {{ item.name }} - 价格:{{ item.price }}元
    </li>
  </ul>
</div>
 
<script>
new Vue({
  el: '#app',
  data: {
    fruits: [
      { id: 1, name: '苹果', price: 5 },
      { id: 2, name: '香蕉', price: 3 },
      { id: 3, name: '橙子', price: 4 }
    ]
  }
});
</script>

3.1.2 遍历对象#

语法:v-for="(value, key, index) in object",value 是属性值,key 是属性名,index 是索引(可选)。

<div v-for="(value, key) in user" :key="key">
  {{ key }}: {{ value }}
</div>
 
<script>
data: {
  user: { name: '张三', age: 25, gender: '男' }
}
</script>
<!-- 输出:
name: 张三
age: 25
gender: 男
-->

3.2 维护状态::key 属性#

Vue 在更新使用 v-for 渲染的列表时,默认使用“就地复用”策略(即不重新创建 DOM 元素,仅更新内容)。为确保列表项的唯一性和正确的 DOM 复用,必须为 v-for 提供 :key 属性,值需为唯一标识(如 ID)。

注意:

  • 避免使用 index 作为 :key(若数组排序或过滤,index 会变化,导致 DOM 复用错误)。
  • :key 的值需为字符串或数字,且在列表中唯一。

正确示例:

<li v-for="item in fruits" :key="item.id">...</li> <!-- 使用唯一 ID 作为 key -->

3.3 数组更新检测#

Vue 能够检测数组的变更方法并触发视图更新,这些方法包括:

  • push():添加元素到末尾
  • pop():删除末尾元素
  • shift():删除第一个元素
  • unshift():添加元素到开头
  • splice():修改/删除/添加元素(splice(index, deleteCount, ...items))
  • sort():排序
  • reverse():反转

非响应式操作:直接修改数组索引或长度(如 arr[0] = 'new'、arr.length = 0),Vue 无法检测。需使用 Vue.set(arr, index, value) 或 splice 替代:

// 错误(非响应式)
this.fruits[0] = { id: 1, name: '红苹果', price: 6 };
 
// 正确(响应式)
Vue.set(this.fruits, 0, { id: 1, name: '红苹果', price: 6 });
// 或
this.fruits.splice(0, 1, { id: 1, name: '红苹果', price: 6 });

3.4 实践与最佳实践#

  • 始终使用 :key:确保列表项的唯一性,避免渲染错误。
  • 避免在 v-for 中使用 v-if:两者优先级冲突(v-for 比 v-if 优先级高),如需条件渲染列表项,可先通过计算属性过滤数组。
    computed: {
      filteredFruits() {
        return this.fruits.filter(item => item.price < 5); // 过滤价格 <5 的水果
      }
    }
  • 长列表优化:对于大数据列表,考虑使用虚拟滚动(如 vue-virtual-scroller)减少 DOM 节点数量。

4. 计算属性与侦听器#

在 Vue 中,处理数据逻辑时,常用计算属性(Computed) 和侦听器(Watch)。两者用途不同,但都用于响应数据变化。

4.1 计算属性(Computed)#

定义:基于现有数据派生新数据,类似于“动态属性”,依赖数据变化时自动更新。

语法:在 Vue 实例的 computed 选项中定义,返回计算后的值。

示例:计算购物车总价

<div id="app">
  <p>商品总价:{{ totalPrice }}元</p>
</div>
 
<script>
new Vue({
  el: '#app',
  data: {
    cart: [
      { name: '商品A', price: 100, quantity: 2 },
      { name: '商品B', price: 50, quantity: 3 }
    ]
  },
  computed: {
    totalPrice() {
      // 计算总价:价格 × 数量 之和
      return this.cart.reduce((sum, item) => sum + item.price * item.quantity, 0);
    }
  }
});
</script>

特点:

  • 缓存性:计算属性会缓存结果,依赖数据未变化时,多次访问不会重复计算(提升性能)。
  • getter 与 setter:默认是 getter,可定义 setter 实现双向绑定:
    computed: {
      fullName: {
        get() {
          return this.firstName + ' ' + this.lastName;
        },
        set(newValue) {
          const [first, last] = newValue.split(' ');
          this.firstName = first;
          this.lastName = last;
        }
      }
    }

4.2 侦听器(Watch)#

定义:监听指定数据的变化,触发自定义逻辑(如异步操作、复杂数据处理)。

语法:在 Vue 实例的 watch 选项中定义,键是监听的数据名,值是处理函数。

示例:监听搜索关键词变化并调用 API

<div id="app">
  <input v-model="searchQuery" placeholder="搜索...">
</div>
 
<script>
new Vue({
  el: '#app',
  data: {
    searchQuery: '',
    searchResult: []
  },
  watch: {
    // 监听 searchQuery 的变化
    searchQuery(newVal, oldVal) {
      // 防抖:300ms 内输入停止后再调用 API
      clearTimeout(this.timer);
      this.timer = setTimeout(() => {
        this.fetchSearchResult(newVal);
      }, 300);
    }
  },
  methods: {
    fetchSearchResult(query) {
      // 调用 API 获取搜索结果
      console.log('搜索:', query);
      // this.searchResult = 接口返回数据;
    }
  }
});
</script>

高级选项:

  • deep: true:深度监听对象内部属性变化(默认仅监听引用变化)。
    watch: {
      user: {
        handler(newVal) {
          console.log('用户信息变化:', newVal);
        },
        deep: true // 监听 user 对象的所有属性
      }
    }
  • immediate: true:初始化时立即执行一次处理函数。

4.3 计算属性 vs 侦听器#

场景计算属性(Computed)侦听器(Watch)
用途派生数据(同步、简单逻辑)复杂逻辑(异步操作、副作用)
缓存有(依赖不变则不重新计算)无(每次数据变化都执行)
写法函数返回值(或 getter/setter)回调函数(接收新/旧值)

最佳实践:

  • 优先使用计算属性处理同步、简单的派生数据(如过滤列表、格式化文本)。
  • 使用侦听器处理异步操作(如 API 请求)或复杂副作用(如操作 DOM、定时器)。

5. 类与样式绑定#

Vue 允许通过 v-bind 动态绑定 HTML 类(class)和内联样式(style),实现样式的条件化或动态化。

5.1 绑定 HTML 类#

5.1.1 对象语法#

通过对象控制类的“存在与否”(值为 true 则添加类,false 则移除)。

<div :class="{ active: isActive, 'text-danger': hasError }"></div>
 
<script>
data: {
  isActive: true,
  hasError: false
}
</script>
<!-- 渲染结果:<div class="active"></div> -->

5.1.2 数组语法#

通过数组指定多个类名。

<div :class="[activeClass, errorClass]"></div>
 
<script>
data: {
  activeClass: 'active',
  errorClass: 'text-danger'
}
</script>
<!-- 渲染结果:<div class="active text-danger"></div> -->

5.1.3 混合语法#

数组中嵌套对象,实现条件与固定类的结合。

<div :class="[isActive ? activeClass : '', { 'text-danger': hasError }]"></div>

5.2 绑定内联样式#

5.2.1 对象语法#

直接绑定样式对象,键是 CSS 属性(可用 camelCase 或 kebab-case,推荐 camelCase)。

<div :style="{ color: textColor, fontSize: fontSize + 'px' }"></div>
 
<script>
data: {
  textColor: 'red',
  fontSize: 16
}
</script>
<!-- 渲染结果:<div style="color: red; font-size: 16px;"></div> -->

5.2.2 数组语法#

绑定多个样式对象,合并生效。

<div :style="[baseStyle, activeStyle]"></div>
 
<script>
data: {
  baseStyle: { color: 'black', fontSize: '14px' },
  activeStyle: { backgroundColor: 'yellow' }
}
</script>

5.2.3 自动前缀#

Vue 会自动为某些 CSS 属性添加浏览器前缀(如 transform),无需手动处理兼容性。

5.3 实践与最佳实践#

  • 优先使用类绑定:相比内联样式,类绑定更利于维护(将样式写在 CSS 文件中,支持复用和主题切换)。
  • 复杂条件逻辑抽离:若类的条件判断复杂,可将逻辑抽离为计算属性:
    computed: {
      classObject() {
        return {
          active: this.isActive && !this.error,
          'text-danger': this.error && this.error.type === 'fatal'
        };
      }
    }
  • 避免过度动态样式:频繁切换的样式(如动画)可使用 CSS 类结合 transition 实现,性能优于动态内联样式。

总结#

本文详细介绍了 Vue.js 2.x 的核心基础语法,包括事件处理(v-on)、表单输入绑定(v-model)、列表渲染(v-for)、计算属性与侦听器,以及类与样式绑定。这些内容是 Vue 开发的基石,掌握它们能帮助你构建交互丰富、响应式的前端应用。

建议结合实际项目练习,例如:

  • 使用 v-for 和 v-model 实现一个待办事项列表(Todo List)。
  • 用计算属性处理数据过滤或格式化。
  • 通过事件修饰符优化表单提交和事件冒泡逻辑。

参考资料#