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

Vue.js 完全指南:从入门到精通

1. Vue.js 简介

1.1 什么是 Vue.js?

Vue.js(通常简称为 Vue)是一个用于构建用户界面的渐进式 JavaScript 框架。所谓"渐进式",意味着 Vue 的设计是由浅入深的,你可以根据自己的需求选择使用它的一部分或全部功能。

Vue 最初由尤雨溪(Evan You)在 2014 年创建,其设计灵感部分来源于 Angular,但更轻量级且更加灵活。Vue 专注于视图层(View Layer),易于与其他库或现有项目集成。

1.2 Vue.js 的核心特性

Vue.js 的核心特性包括:

  1. 声明式渲染:Vue 使用模板语法,允许我们以声明式的方式将数据渲染到 DOM。
  2. 响应式系统:Vue 自动追踪依赖关系并在数据变化时更新 DOM。
  3. 组件化开发:Vue 应用由独立、可复用的组件构建而成,每个组件都包含自己的 HTML、CSS 和 JavaScript。
  4. 虚拟 DOM:Vue 使用虚拟 DOM 来高效地更新实际 DOM。
  5. 指令系统:Vue 提供了一系列以 v- 开头的特殊属性,用于在 HTML 中实现各种功能。
  6. 过渡效果:Vue 提供了内置的过渡和动画系统。
  7. 状态管理:通过 Vuex 或 Pinia 提供集中式状态管理。
  8. 路由管理:通过 Vue Router 提供客户端路由管理。

1.3 Vue.js 的优势

Vue.js 相比其他框架具有以下优势:

  1. 易学易用:Vue 的 API 设计简洁直观,学习曲线平缓,特别适合初学者。
  2. 灵活渐进:可以逐步采用,从简单的 CDN 引入到完整的单页应用开发。
  3. 高性能:通过虚拟 DOM 和响应式系统实现高效的 DOM 更新。
  4. 轻量级:核心库非常小(约 20KB gzipped),不增加太多应用的加载时间。
  5. 生态系统:拥有丰富的插件、组件库和开发工具。
  6. 良好的文档:官方文档详细清晰,并有多语言版本。
  7. 活跃的社区:大量的开发者和企业支持,资源丰富。

1.4 Vue.js 的版本演进

Vue.js 的主要版本演进:

  1. Vue 1.x:初始版本,奠定了 Vue 的基础。
  2. Vue 2.x:引入虚拟 DOM,提升性能和稳定性,增加了服务端渲染支持。
  3. Vue 3.x:重写核心代码,使用 Proxy 代替 Object.defineProperty 实现响应式系统,引入 Composition API,支持 TypeScript,性能更佳。

2. 安装与环境搭建

2.1 Vue.js 的安装方式

Vue.js 提供了多种安装方式,可以根据不同的项目需求选择:

2.1.1 使用 CDN 直接引入

最简单的方式是通过 CDN 直接在 HTML 文件中引入 Vue.js:

<!-- 开发环境版本,包含有用的警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.js"></script>

<!-- 生产环境版本,优化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.prod.js"></script>

Vue 2.x 的 CDN 链接:

<!-- 开发环境版本 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>

<!-- 生产环境版本 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.min.js"></script>
2.1.2 使用 npm 或 yarn 安装

对于更复杂的项目,推荐使用 npm 或 yarn 安装:

# npm
npm install vue

# yarn
yarn add vue
2.1.3 使用 Vue CLI 创建项目

Vue CLI 是 Vue.js 的官方脚手架工具,用于快速搭建 Vue 项目:

# 安装 Vue CLI
npm install -g @vue/cli

# 创建一个新项目
vue create my-project

# 或者使用图形界面
vue ui
2.1.4 使用 Vite 创建项目

Vite 是一个现代化的构建工具,由 Vue 团队开发,特别适合 Vue 项目:

# npm
npm create vite@latest my-vue-app -- --template vue

# yarn
yarn create vite my-vue-app --template vue

2.2 项目结构解析

一个典型的 Vue CLI 创建的项目结构如下:

my-project/
├── node_modules/       # 依赖包
├── public/             # 静态资源,不会被 webpack 处理
│   ├── favicon.ico     # 网站图标
│   └── index.html      # 页面模板
├── src/                # 源代码目录
│   ├── assets/         # 资源文件,会被 webpack 处理
│   ├── components/     # Vue 组件
│   ├── views/          # 页面级别的组件
│   ├── router/         # Vue Router 配置
│   ├── store/          # Vuex 状态管理
│   ├── App.vue         # 根组件
│   └── main.js         # 入口文件
├── .gitignore          # Git 忽略文件
├── babel.config.js     # Babel 配置
├── package.json        # 项目依赖和脚本
├── README.md           # 项目说明
└── vue.config.js       # Vue CLI 配置文件

Vite 创建的项目结构稍有不同:

my-vue-app/
├── node_modules/       # 依赖包
├── public/             # 静态资源
├── src/                # 源代码目录
│   ├── assets/         # 资源文件
│   ├── components/     # Vue 组件
│   ├── App.vue         # 根组件
│   └── main.js         # 入口文件
├── .gitignore          # Git 忽略文件
├── index.html          # HTML 入口文件(注意位置不同)
├── package.json        # 项目依赖和脚本
├── README.md           # 项目说明
└── vite.config.js      # Vite 配置文件

2.3 开发工具配置

为了提高 Vue.js 开发效率,推荐使用以下工具:

2.3.1 编辑器推荐
  • Visual Studio Code:轻量级且功能强大的编辑器,有丰富的 Vue.js 插件支持。
2.3.2 推荐的 VS Code 插件
  • Volar:Vue 3 的官方 VS Code 插件,提供语法高亮、智能提示等功能。
  • ESLint:代码质量检查工具。
  • Prettier:代码格式化工具。
  • GitLens:Git 集成工具。
  • Auto Import:自动导入组件和函数。
2.3.3 浏览器扩展
  • Vue.js devtools:Chrome 和 Firefox 的浏览器扩展,用于调试 Vue 应用。可以查看组件层次结构、状态、事件等信息。

2.4 第一个 Vue 应用

创建一个简单的 Vue 应用,了解基本概念:

2.4.1 使用 CDN 创建
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>My First Vue App</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.js"></script>
</head>
<body>
    <div id="app">
        <h1>{
  { message }}</h1>
        <button @click="reverseMessage">反转消息</button>
    </div>

    <script>
        const { createApp } = Vue;
        
        createApp({
            data() {
                return {
                    message: 'Hello Vue!'
                }
            },
            methods: {
                reverseMessage() {
                    this.message = this.message.split('').reverse().join('')
                }
            }
        }).mount('#app');
    </script>
</body>
</html>
2.4.2 使用 Vue CLI 或 Vite 创建

创建项目后,修改 App.vue 文件:

<template>
  <div id="app">
    <h1>{
  { message }}</h1>
    <button @click="reverseMessage">反转消息</button>
  </div>
</template>

<script>
export default {
  name: 'App',
  data() {
    return {
      message: 'Hello Vue!'
    }
  },
  methods: {
    reverseMessage() {
      this.message = this.message.split('').reverse().join('')
    }
  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  text-align: center;
  margin-top: 60px;
}
</style>

3. Vue 实例与生命周期

3.1 Vue 实例

在 Vue 2 中,每个 Vue 应用都是通过创建一个 Vue 实例开始的:

const vm = new Vue({
  // 选项
})

在 Vue 3 中,我们使用 createApp 函数创建应用实例:

const app = Vue.createApp({
  // 选项
})

// 挂载到 DOM 元素
app.mount('#app')

3.2 Vue 实例选项

Vue 实例接受许多选项,常用的包括:

3.2.1 数据选项
  • data:Vue 实例的数据对象,在组件中是一个返回对象的函数。
  • props:接收来自父组件的数据。
  • computed:计算属性,基于依赖进行缓存。
  • methods:实例的方法。
  • watch:监听数据变化的回调函数。
3.2.2 DOM 相关选项
  • el:指定挂载的 DOM 元素(Vue 2)。
  • template:字符串模板。
  • render:渲染函数,代替模板。
3.2.3 生命周期钩子
  • beforeCreatecreated
  • beforeMountmounted
  • beforeUpdateupdated
  • beforeDestroydestroyed(Vue 2)/ beforeUnmountunmounted(Vue 3)
3.2.4 资源选项
  • directives:自定义指令。
  • filters(Vue 2):自定义过滤器。
  • components:注册组件。
3.2.5 组合选项
  • mixins:混入对象。
  • extends:扩展另一个组件。
  • provide/inject:依赖注入。

3.3 Vue 实例属性和方法

Vue 实例暴露了一些有用的实例属性和方法,以 $ 前缀标识:

const vm = new Vue({
  data: {
    message: 'Hello'
  }
})

// 实例属性
console.log(vm.$data.message) // 'Hello'
console.log(vm.$el) // DOM 元素

// 实例方法
vm.$watch('message', function(newValue, oldValue) {
  // 当 message 变化时调用
})
vm.$set(object, key, value) // 响应式地设置属性
vm.$delete(object, key) // 响应式地删除属性

3.4 Vue 生命周期详解

Vue 组件实例有一个完整的生命周期,从创建到销毁,可以在特定阶段执行自定义代码。

3.4.1 生命周期图示
          创建阶段                  挂载阶段                   更新阶段                     销毁阶段
┌─────────────────────┐  ┌───────────────────────┐  ┌───────────────────────┐  ┌───────────────────────┐
│                     │  │                       │  │                       │  │                       │
│  beforeCreate       │  │  beforeMount          │  │  beforeUpdate         │  │  beforeDestroy        │
│                     │  │                       │  │                       │  │  (Vue 2)              │
│  ↓                  │  │  ↓                    │  │  ↓                    │  │  or                   │
│                     │  │                       │  │                       │  │  beforeUnmount        │
│  created            │  │  mounted              │  │  updated              │  │  (Vue 3)              │
│                     │  │                       │  │                       │  │                       │
│                     │  │                       │  │                       │  │  ↓                    │
│                     │  │                       │  │                       │  │                       │
│                     │  │                       │  │                       │  │  destroyed            │
│                     │  │                       │  │                       │  │  (Vue 2)              │
│                     │  │                       │  │                       │  │  or                   │
│                     │  │                       │  │                       │  │  unmounted            │
│                     │  │                       │  │                       │  │  (Vue 3)              │
└─────────────────────┘  └───────────────────────┘  └───────────────────────┘  └───────────────────────┘
3.4.2 生命周期钩子函数详解
  1. beforeCreate

    • 实例初始化后,数据观测和事件配置之前调用。
    • 此时无法访问 data、computed、methods 等选项。
  2. created

    • 实例创建完成后立即调用。
    • 可以访问 data、computed、methods 等,但尚未挂载到 DOM。
    • 适合执行初始化数据获取。
  3. beforeMount

    • 挂载开始前调用。
    • 相关的 render 函数首次被调用。
  4. mounted

    • 实例挂载到 DOM 后调用。
    • 可以访问 DOM 元素,适合执行需要访问 DOM 的操作。
    • 不能保证所有子组件也都已经挂载完成。
  5. beforeUpdate

    • 数据更新时,虚拟 DOM 重新渲染前调用。
    • 适合在更新前访问现有的 DOM。
  6. updated

    • 数据更改导致的虚拟 DOM 重新渲染后调用。
    • 应避免在此钩子中修改数据,可能导致无限循环。
  7. beforeDestroy(Vue 2)/ beforeUnmount(Vue 3):

    • 实例销毁前调用。
    • 实例仍然完全可用,适合清理事件监听器、定时器等资源。
  8. destroyed(Vue 2)/ unmounted(Vue 3):

    • 实例销毁后调用。
    • 所有指令解绑,事件监听器移除,子实例也被销毁。
3.4.3 其他生命周期钩子
  1. activated

    • 被 keep-alive 缓存的组件激活时调用。
  2. deactivated

    • 被 keep-alive 缓存的组件停用时调用。
  3. errorCaptured

    • 捕获一个来自后代组件的错误时调用。
  4. renderTracked(Vue 3):

    • 跟踪虚拟 DOM 重新渲染时调用。
  5. renderTriggered(Vue 3):

    • 虚拟 DOM 重新渲染被触发时调用。
3.4.4 生命周期钩子使用示例
export default {
  data() {
    return {
      message: 'Hello Vue'
    }
  },
  beforeCreate() {
    console.log('beforeCreate: 实例初始化')
    // 此时无法访问 data
    console.log('this.message:', this.message) // undefined
  },
  created() {
    console.log('created: 实例已创建')
    // 可以访问 data
    console.log('this.message:', this.message) // 'Hello Vue'
    // 可以执行异步操作
    this.fetchData()
  },
  beforeMount() {
    console.log('beforeMount: 挂载前')
    // DOM 尚未创建
    console.log(this.$el) // 尚未挂载的元素
  },
  mounted() {
    console.log('mounted: 已挂载')
    // 可以访问 DOM
    console.log(this.$el) // 实际 DOM 元素
    // 适合执行需要访问 DOM 的操作
    this.setupChart()
  },
  beforeUpdate() {
    console.log('beforeUpdate: 数据更新前')
    // 可以在更新前访问现有的 DOM
  },
  updated() {
    console.log('updated: 数据更新后')
    // DOM 已更新
  },
  beforeUnmount() { // Vue 3 使用 beforeUnmount,Vue 2 使用 beforeDestroy
    console.log('beforeUnmount: 卸载前')
    // 清理资源
    this.cleanupResources()
  },
  unmounted() { // Vue 3 使用 unmounted,Vue 2 使用 destroyed
    console.log('unmounted: 已卸载')
    // 实例已销毁
  },
  // 辅助方法
  methods: {
    fetchData() {
      // 获取初始数据
    },
    setupChart() {
      // 设置图表
    },
    cleanupResources() {
      // 清理资源
    }
  }
}

4. 模板语法与数据绑定

Vue 使用基于 HTML 的模板语法,允许开发者声明式地将 DOM 绑定到底层组件实例的数据。

4.1 插值

4.1.1 文本插值

最基本的数据绑定形式是使用"Mustache"语法(双大括号):

<span>消息:{
  { message }}</span>

{ { message }} 会被替换为对应数据对象上 message 属性的值。每当 message 属性变化时,插值内容也会更新。

4.1.2 原始 HTML

双大括号会将数据解释为普通文本,如果要输出 HTML,需要使用 v-html 指令:

<p>使用文本插值:{
  { rawHtml }}</p>
<p>使用 v-html 指令:<span v-html="rawHtml"></span></p>

注意:在网站上动态渲染任意 HTML 可能会导致 XSS 攻击。请只对可信内容使用 HTML 插值,绝不要对用户提供的内容使用插值。

4.1.3 属性绑定

Mustache 语法不能用在 HTML 属性上,应该使用 v-bind 指令:

<div v-bind:id="dynamicId"></div>

简写形式(推荐使用):

<div :id="dynamicId"></div>

对于布尔属性,如果条件是 truthy 值,则属性会被包含;否则会被省略:

<button :disabled="isButtonDisabled">按钮</button>
4.1.4 使用 JavaScript 表达式

Vue 支持在绑定表达式中使用完整的 JavaScript 表达式:

{
  { number + 1 }}

{
  { ok ? 'YES' : 'NO' }}

{
  { message.split('').reverse().join('') }}

<div :id="`list-${id}`"></div>

每个绑定只能包含单个表达式,以下内容不会生效:

<!-- 这是语句,不是表达式 -->
{
  { var a = 1 }}

<!-- 流控制也不会生效,使用三元表达式 -->
{
  { if (ok) { return message } }}

4.2 指令

指令是带有 v- 前缀的特殊属性,用于在表达式的值改变时响应式地作用于 DOM。

4.2.1 指令基础
<p v-if="seen">现在你看到我了</p>

seen 的值为 true 时,<p> 元素会被渲染;否则会被移除。

4.2.2 指令参数

一些指令可以接收一个"参数",在指令名后以冒号表示:

<a v-bind:href="url">链接</a>
<a v-on:click="doSomething">点击</a>
4.2.3 动态参数

可以使用方括号括起来的 JavaScript 表达式作为指令的参数:

<a v-bind:[attributeName]="url">链接</a>
<a v-on:[eventName]="doSomething">点击</a>

这里的 attributeName 会被作为一个 JavaScript 表达式进行动态求值,求值结果作为最终的参数使用。

4.2.4 修饰符

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

<form v-on:submit.prevent="onSubmit">提交</form>

这里 .prevent 修饰符表示调用 event.preventDefault() 方法,阻止表单的默认提交行为。

4.3 常用内置指令

Vue 提供了许多内置指令,以下是一些最常用的:

4.3.1 v-bind

绑定 HTML 属性或组件 prop 到表达式:

<img v-bind:src="imageSrc">
<!-- 简写 -->
<img :src="imageSrc">

<!-- 动态属性名 -->
<button :[key]="value"></button>

<!-- 绑定多个属性 -->
<div v-bind="{ id: 'container', class: 'wrapper' }"></div>
4.3.2 v-on

绑定事件监听器:

<button v-on:click="doThis"></button>
<!-- 简写 -->
<button @click="doThis"></button>

<!-- 动态事件名 -->
<button @[event]="doThis"></button>

<!-- 内联语句 -->
<button @click="count++"></button>

<!-- 对象语法 -->
<button v-on="{ click: onClick, mouseover: onMouseOver }"></button>
4.3.3 v-model

创建双向数据绑定:

<input v-model="message">
<textarea v-model="message"></textarea>
<select v-model="selected">
  <option value="">请选择</option>
  <option value="1">选项 1</option>
  <option value="2">选项 2</option>
</select>
4.3.4 v-if, v-else-if, v-else

条件性渲染元素:

<div v-if="type === 'A'">A</div>
<div v-else-if="type === 'B'">B</div>
<div v-else>Not A/B</div>
4.3.5 v-show

根据条件显示/隐藏元素(元素始终会被渲染):

<div v-show="isVisible">内容</div>
4.3.6 v-for

基于数组/对象渲染列表:

<ul>
  <li v-for="item in items" :key="item.id">{
  { item.text }}</li>
</ul>

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

<div v-for="(value, key, index) in object">
  {
  { index }}. {
  { key }}: {
  { value }}
</div>
4.3.7 v-once

只渲染元素和组件一次:

<span v-once>这个将不会改变: {
  { message }}</span>
4.3.8 v-html

更新元素的 innerHTML:

<div v-html="htmlContent"></div>
4.3.9 v-text

更新元素的文本内容:

<span v-text="message"></span>
<!-- 等同于 -->
<span>{
  { message }}</span>
4.3.10 v-cloak

用于隐藏尚未编译的 Mustache 标签,直到组件实例准备完毕:

<div v-cloak>{
  { message }}</div>

需要配合 CSS 规则使用:

[v-cloak] {
  display: none;
}
4.3.11 v-pre

跳过这个元素和它的子元素的编译过程:

<span v-pre>{
  { 这里的内容不会被编译 }}</span>

4.4 数据绑定的响应式原理

Vue 的响应式系统是其核心特性之一,使得数据和视图之间保持同步。

4.4.1 Vue 2 响应式原理

Vue 2 使用 Object.defineProperty 劫持对象属性的 getter 和 setter,在访问或修改属性时进行依赖收集和通知更新。

基本流程:

  1. 将普通 JavaScript 对象传入 Vue 实例作为 data 选项。
  2. Vue 遍历该对象所有属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter。
  3. 这些 getter/setter 使 Vue 能够追踪依赖,在属性被访问和修改时通知变更。
  4. 每个组件实例都对应一个 watcher 实例,在组件渲染的过程中记录被访问的属性。
  5. 当 setter 被调用时,会通知 watcher,从而使它关联的组件重新渲染。

限制:

  • 无法检测对象属性的添加或删除。
  • 无法直接检测数组的变化,如通过索引设置值或修改数组长度。
4.4.2 Vue 3 响应式原理

Vue 3 使用 ES6 的 Proxy 代替 Object.defineProperty,可以监听整个对象而不是个别属性,解决了 Vue 2 中的限制。

基本流程:

  1. 将普通 JavaScript 对象传入 reactive 函数。
  2. Vue 3 使用 Proxy 包装该对象,拦截对该对象的所有操作。
  3. 在渲染过程中,会自动建立依赖关系。
  4. 当对象被修改时,会触发相关组件的重新渲染。

优势:

  • 可以检测到对象和数组的所有变化。
  • 可以检测属性的添加和删除。
  • 可以检测数组索引和长度的变化。
  • 性能更好,不需要递归遍历对象的所有属性。

5. 计算属性与侦听器

5.1 计算属性

计算属性用于声明依赖于其他属性的复杂逻辑。计算属性是基于它们的依赖进行缓存的,只有在依赖变化时才会重新计算。

5.1.1 基本用法
export default {
  data() {
    return {
      firstName: 'John',
      lastName: 'Doe'
    }
  },
  computed: {
    fullName() {
      return this.firstName + ' ' + this.lastName
    }
  }
}

在模板中使用:

<p>{
  { fullName }}</p>
5.1.2 计算属性 vs 方法

计算属性会基于其依赖进行缓存,只有在依赖发生变化时才会重新计算。而方法在每次重新渲染时都会执行。

// 计算属性
computed: {
  expensiveComputation() {
    console.log('计算属性被执行')
    return this.items.filter(item => item.active).map(item => item.value)
  }
}

// 方法
methods: {
  expensiveMethod() {
    console.log('方法被执行')
    return this.items.filter(item => item.active).map(item => item.value)
  }
}

当多次访问 expensiveComputation 时,如果依赖没有变化,计算结果会从缓存中返回,而不会重新执行过滤和映射操作。而每次访问 expensiveMethod() 都会导致函数重新执行。

5.1.3 计算属性的 setter

计算属性默认只有 getter,但我们也可以提供 setter:

computed: {
  fullName: {
    // getter
    get() {
      return this.firstName + ' ' + this.lastName
    },
    // setter
    set(newValue) {
      const names = newValue.split(' ')
      this.firstName = names[0]
      this.lastName = names[names.length - 1]
    }
  }
}

现在当我们运行 this.fullName = 'Jane Smith' 时,setter 会被调用,this.firstNamethis.lastName 会被相应地更新。

5.1.4 Composition API 中的计算属性

在 Vue 3 的 Composition API 中,计算属性通过 computed 函数创建:

import { ref, computed } from 'vue'

export default {
  setup() {
    const firstName = ref('John')
    const lastName = ref('Doe')
    
    const fullName = computed(() => {
      return firstName.value + ' ' + lastName.value
    })
    
    // 带有 setter 的计算属性
    const fullNameWithSetter = computed({
      get: () => firstName.value + ' ' + lastName.value,
      set: (newValue) => {
        const names = newValue.split(' ')
        firstName.value = names[0]
        lastName.value = names[names.length - 1]
      }
    })
    
    return {
      firstName,
      lastName,
      fullName,
      fullNameWithSetter
    }
  }
}

5.2 侦听器

侦听器(watch)用于在数据变化时执行异步或开销较大的操作。

5.2.1 基本用法
export default {
  data() {
    return {
      question: '',
      answer: '问题包含问号(?)才能得到答案。'
    }
  },
  watch: {
    // 监听 question 变化
    question(newQuestion, oldQuestion) {
      if (newQuestion.includes('?')) {
        this.getAnswer()
      }
    }
  },
  methods: {
    async getAnswer() {
      this.answer = '思考中...'
      try {
        const response = await fetch('https://yesno.wtf/api')
        const data = await response.json()
        this.answer = data.answer
      } catch (error) {
        this.answer = '错误!无法获取答案。'
      }
    }
  }
}
5.2.2 侦听复杂数据

对于复杂数据类型(对象、数组),默认只检测引用变化,要检测内部变化需要使用深度侦听:

watch: {
  // 对象深度监听
  userProfile: {
    handler(newValue, oldValue) {
      console.log('用户资料变化了')
    },
    deep: true
  },
  
  // 监听对象的特定属性
  'userProfile.name'(newValue, oldValue) {
    console.log('用户名变化了')
  }
}
5.2.3 侦听器选项

侦听器支持以下选项:

  • deep:深度监听对象或数组内部变化。
  • immediate:侦听器创建后立即执行一次回调。
  • flush(Vue 3):控制侦听器回调的时机('pre''post''sync')。
watch: {
  searchQuery: {
    handler(newQuery, oldQuery) {
      // 执行搜索
      this.fetchResults(newQuery)
    },
    // 立即执行一次
    immediate: true,
    // 在组件更新后调用
    flush: 'post' // Vue 3 特有
  }
}
5.2.4 $watch 方法

除了在组件选项中定义侦听器外,还可以使用实例方法 $watch 命令式地创建侦听器:

// 创建侦听器
const unwatch = this.$watch('question', function(newQuestion, oldQuestion) {
  // 执行操作
  if (newQuestion.includes('?')) {
    this.getAnswer()
  }
}, {
  immediate: true,
  deep: true
})

// 停止侦听
unwatch() // 当不再需要时
5.2.5 Composition API 中的侦听器

在 Vue 3 的 Composition API 中,侦听器通过 watchwatchEffect 函数创建:

import { ref, watch, watchEffect } from 'vue'

export default {
  setup() {
    const question = ref('')
    const answer = ref('问题包含问号(?)才能得到答案。')
    
    // 基本侦听
    watch(question, (newQuestion, oldQuestion) => {
      if (newQuestion.includes('?')) {
        getAnswer()
      }
    })
    
    // 侦听多个来源
    const firstName = ref('John')
    const lastName = ref('Doe')
    
    watch([firstName, lastName], ([newFirst, newLast], [oldFirst, oldLast]) => {
      console.log('名字变化了')
    })
    
    // 深度侦听
    const userProfile = ref({
      name: 'John',
      age: 30
    })
    
    watch(userProfile, (newProfile, oldProfile) => {
      console.log('用户资料变化了')
    }, { deep: true })
    
    // watchEffect 会自动跟踪所有依赖,并在依赖变化时重新执行
    watchEffect(() => {
      console.log(`问题是: ${question.value}`)
      console.log(`回答是: ${answer.value}`)
    })
    
    async function getAnswer() {
      answer.value = '思考中...'
      try {
        const response = await fetch('https://yesno.wtf/api')
        const data = await response.json()
        answer.value = data.answer
      } catch (error) {
        answer.value = '错误!无法获取答案。'
      }
    }
    
    return {
      question,
      answer
    }
  }
}

5.3 计算属性 vs 侦听器

虽然计算属性和侦听器在很多情况下可以互换使用,但它们有不同的用途:

  • 计算属性:适用于根据其他属性派生值的场景,自动缓存结果。适合同步转换数据。
  • 侦听器:适用于需要在数据变化时执行异步或开销较大操作的场景。适合需要副作用的操作。

选择合适工具的基本原则:

  • 需要派生/组合值 → 计算属性
  • 需要执行副作用 → 侦听器

6. Class 与 Style 绑定

6.1 绑定 HTML Class

6.1.1 对象语法

通过传递对象给 :class 来动态切换 class:

<div :class="{ active: isActive, 'text-danger': hasError }"></div>

上面的语法表示 active 这个 class 存在与否将取决于数据属性 isActive 的真假值,text-danger 同理。

也可以绑定一个返回对象的计算属性:

data() {
  return {
    isActive: true,
    error: null
  }
},
computed: {
  classObject() {
    return {

http://www.kler.cn/a/610915.html

相关文章:

  • 【HTML 基础教程】HTML 元素
  • 如何使用 CSS 实现多列布局,有哪些注意事项
  • 3. 轴指令(omron 机器自动化控制器)——>MC_GearIn
  • 开启TCP-SYNcookie保护缓解网络洪水攻击,增强服务器运行的稳定性。将 TMOUT=300 添加到 /etc/profile 文件提高安全
  • centos 7 LVM管理命令
  • 预编译能否 100%防 sql 注入?
  • 图书管理系统系统-Java、SpringBoot、Vue和MySQL开发的图书馆管理系统
  • 《Matplotlib三维可视化工业实践——从分子模拟到流体力学》
  • 高效团队开发的工具与方法 引言
  • AJAX(Asynchronous JavaScript and XML)详解与应用
  • 安装 pgsql 将gis数据入库
  • Unity脚本编程:C#脚本中的常用组件详解
  • AI搜索的终极预测:从技术颠覆到生态重构
  • 【多学科稳定EI会议大合集】计算机应用、通信信号、电气能源工程、社科经管教育、光学光电、遥感测绘、生物医学等多学科征稿!
  • Python + Chrome 爬虫:如何抓取 AJAX 动态加载数据?
  • AIDD-人工智能药物设计-深度学习驱动的酶动力学参数预测模型CataPro助力高效酶挖掘与改造
  • 使用Python爬虫按图搜索1688商品(拍立淘)
  • 架构思维:如何设计一个支持海量数据存储的高扩展性架构_数据分片、存储、复制与一致性的原理性问题
  • Unity3D 动态遮挡剔除(Occlusion Culling)
  • 3个版本的Unity项目的异同