当前位置:   article > 正文

vue的基础知识大全,一篇文章就够了!_vue基础知识

vue基础知识

vue全家桶

一、vue是什么

Vue.js(通常简称为Vue)是一个流行的JavaScript前端框架,用于构建用户界面。它的主要目标是使前端开发变得更加简单和高效。以下是一些关键特点和概念:

  1. 响应式数据绑定: Vue允许你将数据与DOM元素进行绑定,当数据发生变化时,DOM会自动更新以反映这些变化。这使得开发交互式的界面变得更加容易。

  2. 组件化开发: Vue将应用程序分解为可重用的组件,每个组件都有自己的模板、逻辑和样式。这使得大型应用程序的开发和维护更加简单。

  3. 指令: Vue提供了一系列指令,如v-ifv-forv-bind等,用于处理DOM元素和数据之间的交互。这些指令使你可以在模板中轻松地执行各种操作。

  4. 路由管理: Vue有一个名为Vue Router的官方路由管理库,用于处理单页面应用程序(SPA)的导航。它允许你创建多个页面并在它们之间进行导航,而无需刷新整个页面。

  5. 状态管理: Vue也提供了一个名为Vuex的官方状态管理库,用于管理应用程序的状态(如用户身份验证信息、购物车内容等)。这对于大型应用程序中的数据共享和管理非常有用。

  6. 生态系统: Vue拥有庞大的生态系统,包括第三方库和插件,可以帮助你处理诸如国际化、表单验证、动画等各种需求。

总之,Vue是一个灵活、易学且功能强大的前端框架,适用于各种规模的项目。它的文档和社区支持也非常丰富,这使得学习和使用Vue变得更加愉快和高效。

二、vue的实例对象

在Vue中,你可以创建Vue实例对象,这是Vue应用的核心。Vue实例对象可以控制一个特定的DOM元素,并与该元素关联,以实现响应式数据绑定、事件处理和其他功能。下面是创建一个Vue实例对象的基本示例:

// 创建一个Vue实例对象
var app = new Vue({
  // 选项对象
  el: '#app', // 指定关联的DOM元素,这里的'#app'是一个DOM选择器
  data: {
    message: 'Hello, Vue!' // 数据属性
  },
  methods: {
    // 定义方法
    changeMessage: function () {
      this.message = 'Vue is awesome!'; // 修改数据属性
    }
  }
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

在上面的示例中,我们首先使用new Vue({ ... })创建了一个Vue实例对象,并传递了一个选项对象。这个选项对象包含了一些重要的属性:

  • el:这是一个DOM选择器,它指定了Vue实例控制的DOM元素。在示例中,我们使用#app来选择id为app的DOM元素。

  • data:这是一个包含数据属性的对象。在示例中,我们有一个名为message的数据属性,其初始值为’Hello, Vue!'。

  • methods:这是一个包含方法的对象。在示例中,我们定义了一个名为changeMessage的方法,用于修改message数据属性的值。

一旦创建了Vue实例对象,它就会自动将el元素的内容与data中的数据属性进行关联,这意味着在模板中使用{{ message }}会显示数据属性的值,并且通过v-on指令可以调用方法。

例如,在HTML中的模板中可以这样使用:

<div id="app">
  <p>{{ message }}</p>
  <button v-on:click="changeMessage">Change Message</button>
</div>
  • 1
  • 2
  • 3
  • 4

这样,当用户点击按钮时,changeMessage方法会被调用,从而修改message的值,因为数据属性和DOM元素之间建立了响应式绑定,所以页面会自动更新以反映这一变化。

这只是Vue实例对象的一个简单示例,Vue还有许多其他选项和功能,可以根据你的项目需求进行配置和扩展。

el和data的其他写法

在Vue实例对象中,eldata是两个重要的属性,它们用于定义Vue实例的挂载点和数据。以下是两种常见的写法:

方式一:使用对象字面量

var app = new Vue({
  el: '#app', // 挂载点,将Vue实例与具有id="app"的DOM元素关联
  data: {
    message: 'Hello, Vue!' // 数据属性
  }
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • el:指定Vue实例要挂载的DOM元素,这里使用id选择器#app来选择要挂载的元素。
  • data:定义Vue实例中的数据属性,例如message

方式二:使用函数返回对象

你还可以使用一个函数来返回Vue实例的选项对象,这种方式在需要复用Vue实例或有更复杂的逻辑时非常有用:

var app = new Vue({
  el: function () {
    return document.getElementById('app'); // 挂载点,将Vue实例与具有id="app"的DOM元素关联
  },
  data: function () {
    return {
      message: 'Hello, Vue!' // 数据属性
    };
  }
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

这两种写法都可以创建一个Vue实例对象,并将其挂载到指定的DOM元素上。你可以根据你的项目需求选择其中的一种写法。方式二的函数写法在某些情况下更灵活,因为你可以在函数中编写更复杂的逻辑,而不仅仅是返回一个固定的选项对象。

在Vue 3 中,el属性已经不再使用,而是使用$mount方法来手动挂载Vue实例到DOM元素上。这是因为Vue 3 引入了 Composition API 和更加灵活的组合式编程方式,不再依赖传统的el属性。

以下是如何使用mount方法来挂载Vue实例到DOM元素上的示例:

import { createApp } from 'vue';

const app = createApp({
  data() {
    return {
      message: 'Hello, Vue 3!'
    };
  }
});

// 使用 mount 方法来挂载实例到 DOM 元素上
app.$mount('#app');
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

在这个示例中,我们首先通过createApp方法创建了一个Vue 3实例。然后,使用$mount方法将该实例挂载到具有id为app的DOM元素上。

这种方式与传统的el属性在功能上是相同的,但它更符合Vue 3 的新特性和 API 设计,同时也更加灵活,允许你在不同的生命周期阶段进行挂载和卸载操作。因此,如果你正在使用Vue 3,建议使用mount方法来挂载Vue实例。

三、vue的模板语法

Vue的模板语法是一种用于声明视图的简单和表达力强的HTML模板语言。它允许你将Vue实例中的数据绑定到DOM元素上,并在模板中使用一些特殊的指令来实现数据的渲染和交互。以下是Vue模板语法的一些关键概念和示例:

  1. 数据绑定: 你可以使用双大括号{{ }}将Vue实例中的数据属性绑定到DOM元素中,这样数据的变化会自动反映在DOM中。
<div id="app">
  <p>{{ message }}</p>
</div>
  • 1
  • 2
  • 3

在上面的例子中,{{ message }}将显示Vue实例中的message数据属性的值。

  1. 指令: Vue提供了一系列特殊的指令,以v-开头,用于在模板中添加特定的行为或响应。以下是一些常用指令的示例:

    • v-bind:将元素属性与Vue实例中的数据属性绑定在一起。

      <a v-bind:href="url">Link</a>
      
      • 1
    • v-model:实现双向数据绑定,将表单元素的值绑定到数据属性,以便在用户输入时更新数据。

      <input v-model="message">
      
      • 1
    • v-for:用于循环渲染列表。

      <ul>
        <li v-for="item in items">{{ item }}</li>
      </ul>
      
      • 1
      • 2
      • 3
    • v-on:用于绑定事件监听器。

      <button v-on:click="doSomething">Click me</button>
      
      • 1
  2. 条件渲染: 使用v-ifv-else指令可以根据条件来渲染不同的内容。

<div v-if="loggedIn">
  Welcome, {{ username }}!
</div>
<div v-else>
  Please log in.
</div>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  1. 模板语法中的表达式: 你可以在双大括号或指令中使用JavaScript表达式。
<p>{{ message + ' world' }}</p>
<button v-on:click="counter++">Increment</button>
  • 1
  • 2

总之,Vue的模板语法使你能够以声明性的方式构建用户界面,同时利用Vue的响应式系统来管理数据和界面之间的关系。这些只是Vue模板语法的基础,Vue还有更多高级特性和指令,可根据项目的需求进行使用。

四、Vue的单向数据绑定与双向数据绑定

Vue提供了单向数据绑定和双向数据绑定两种数据绑定方式,这些方式决定了数据在Vue实例和DOM元素之间的流动。

1. 单向数据绑定(One-Way Data Binding):

单向数据绑定是指数据只能从Vue实例流向DOM元素,但不能反向流动。这意味着当Vue实例中的数据属性发生变化时,相关的DOM元素会自动更新以反映这些变化,但如果用户在DOM元素上进行了交互操作(例如在表单输入框中输入文本),这些变化不会自动反映到Vue实例中的数据属性上。

单向数据绑定的主要特点包括:

  • 数据从Vue实例流向DOM元素。
  • 常见的单向数据绑定方式包括使用插值表达式({{ }})和v-bind指令(或其简写形式:)。

示例:

<div id="app">
  <p>{{ message }}</p>
  <a :href="url">Link</a>
</div>
  • 1
  • 2
  • 3
  • 4

2. 双向数据绑定(Two-Way Data Binding):

双向数据绑定允许数据在Vue实例和DOM元素之间双向流动。这意味着不仅可以将数据从Vue实例流向DOM元素,还可以将数据从DOM元素反向流回Vue实例。

双向数据绑定的主要特点包括:

  • 数据既能从Vue实例流向DOM元素,又能从DOM元素反向流回Vue实例。
  • 双向数据绑定通常使用v-model指令,主要用于表单元素,以实现用户输入的数据与Vue实例中的数据属性之间的同步。

示例:

<div id="app">
  <input v-model="message">
</div>
  • 1
  • 2
  • 3

需要注意的是,虽然Vue提供了双向数据绑定的能力,但它通常用于处理用户输入的表单元素,而其他元素的数据绑定仍然是单向的。这有助于维护数据的一致性和可控性。

总结:

  • 单向数据绑定是数据从Vue实例流向DOM元素,常见方式包括插值表达式和v-bind指令。
  • 双向数据绑定允许数据在Vue实例和DOM元素之间双向流动,通常使用v-model指令,主要用于处理表单输入元素。

v-model在收集表单中的应用

文本输入框
<input type="text" v-model="message">
  • 1
  • v-model 用于双向绑定输入框的值和 Vue 实例中的数据。
  • 用户输入的文本将自动更新到 message 数据属性中,并在页面上显示。
复选框
<input type="checkbox" v-model="checked">
  • 1
  • v-model 用于处理复选框的状态。
  • 若没有配置 value 属性,v-model 收集的是 checked,即勾选或未勾选状态。
<input type="checkbox" :value="value" v-model="selectedValues">
  • 1
  • 若配置了 value 属性,根据 v-model 初始值的类型,收集的可能是 checkedvalue 组成的数组。
  • 初始值非数组时,收集的是 checked 布尔值。
  • 初始值为数组时,收集的是 value 组成的数组。
单选按钮
<input type="radio" id="option1" value="option1" v-model="selectedOption">
<input type="radio" id="option2" value="option2" v-model="selectedOption">
  • 1
  • 2
  • v-model 用于处理单选按钮的选择。
  • 用户选择单选按钮时,selectedOption 数据属性会自动更新为所选的选项。
修饰符

v-model 还提供了一些修饰符,以满足不同的数据处理需求:

  • lazy:在失去焦点时才收集数据,适用于需要延迟收集的情况。
  • number:将输入字符串转换为有效的数字,有助于确保数据类型一致性。
  • trim:自动过滤输入首尾的空格,提高数据的质量和一致性。

五、vue中的MVVM模型

Vue是一个基于MVVM(Model-View-ViewModel)模型的JavaScript框架,它的设计灵感来自于MVVM模型。MVVM是一种用于构建交互式的Web应用程序的软件架构模式,它将应用程序分为三个主要部分:

  1. Model(模型): Model代表应用程序的数据和业务逻辑。它负责管理数据的获取、存储和处理。在Vue中,Model通常是Vue实例中的data属性,包含了应用程序的数据。

  2. View(视图): View代表用户界面,它负责将数据渲染到屏幕上,同时响应用户的交互。在Vue中,View通常是Vue模板,使用Vue的模板语法来声明界面。

  3. ViewModel(视图模型): ViewModel是连接Model和View的桥梁。它负责将Model中的数据映射到View上,并监听用户的交互操作。ViewModel也负责处理用户输入并更新Model中的数据。在Vue中,ViewModel由Vue实例来扮演,Vue实例包含了data属性(Model)、模板(View),以及一系列的指令和事件处理器来建立Model和View之间的关联。

Vue的MVVM模型工作流程如下:

  1. Vue实例的data属性包含了应用程序的数据。

  2. Vue模板使用Vue的模板语法将这些数据渲染到页面上,形成View。

  3. Vue的指令(例如v-bindv-modelv-on)和事件处理器建立了Model和View之间的数据绑定和交互。

  4. 当用户与界面交互时,ViewModel负责监听用户的操作并更新Model中的数据。

  5. 当Model中的数据发生变化时,ViewModel负责自动更新View,使界面保持与数据同步。

这种双向数据绑定和响应式的机制使得开发者能够以更直观和声明性的方式构建交互式的Web应用程序,而不必手动处理DOM操作和数据同步的复杂性。Vue的MVVM模型是Vue框架的核心,为前端开发提供了一种高效、灵活且易于维护的开发方式。它使开发者能够专注于业务逻辑和用户体验,而不必担心底层细节。

六、数据代理

6.1回顾Object.defindProperty方法

Object.defineProperty 是 JavaScript 中的一个内置方法,用于定义或修改对象的属性。通过这个方法,你可以精确地控制一个对象的某个属性的行为,包括属性的值、可枚举性、可配置性以及可写性。

这是 Object.defineProperty 方法的语法:

Object.defineProperty(obj, prop, descriptor)
  • 1
  • obj:要定义属性的对象。
  • prop:要定义或修改的属性的名称。
  • descriptor:属性的描述符对象,包含属性的各种特性。

descriptor 对象可以包含以下属性:

  • value:属性的值,默认为 undefined
  • writable:是否可写,默认为 false
  • enumerable:是否可枚举,默认为 false
  • configurable:是否可配置,默认为 false

以下是一些示例:

  1. 定义一个只读属性:
var obj = {};
Object.defineProperty(obj, 'readOnly', {
  value: 'This is read-only',
  writable: false
});

console.log(obj.readOnly); // 输出:'This is read-only'
obj.readOnly = 'New value'; // 不会改变属性值
console.log(obj.readOnly); // 输出:'This is read-only'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  1. 定义一个可配置但不可枚举的属性:
var obj = {};
Object.defineProperty(obj, 'configurableProp', {
  value: 'I can be configured, but not enumerated',
  writable: true,
  enumerable: false,
  configurable: true
});

for (var key in obj) {
  console.log(key); // 不会输出属性名
}

delete obj.configurableProp; // 可以删除属性
console.log(obj.configurableProp); // 输出:undefined
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

Object.defineProperty 主要用于高级对象属性的定义,例如在定义自定义对象的 getter 和 setter 方法时,或者在实现特定的属性行为时。它是 JavaScript 中对象属性管理的强大工具,但在一般情况下,你可以使用更简单的方式来定义和修改对象的属性,例如直接使用点操作符来设置属性的值。

当需要更复杂的属性定义和控制时,Object.defineProperty 可以派上用场。以下是更多示例:

  1. 定义一个具有 getter 和 setter 方法的属性:
var person = {
  firstName: 'John',
  lastName: 'Doe'
};

Object.defineProperty(person, 'fullName', {
  get: function () {
    return this.firstName + ' ' + this.lastName;
  },
  set: function (value) {
    var parts = value.split(' ');
    this.firstName = parts[0];
    this.lastName = parts[1];
  },
  enumerable: true,
  configurable: true
});

console.log(person.fullName); // 输出:'John Doe'
person.fullName = 'Jane Smith';
console.log(person.firstName); // 输出:'Jane'
console.log(person.lastName); // 输出:'Smith'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

在这个示例中,我们定义了一个 fullName 属性,它具有 getter 和 setter 方法,允许我们以更高级的方式操作 firstNamelastName 属性。

  1. 使用 Object.defineProperty 在对象上定义新属性:
var car = {};
Object.defineProperty(car, 'color', {
  value: 'red',
  writable: true,
  enumerable: true,
  configurable: true
});

console.log(car.color); // 输出:'red'
car.color = 'blue'; // 可以修改属性值
console.log(car.color); // 输出:'blue'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

在这个示例中,我们在一个空对象上定义了一个新属性 color,并设置了其默认值以及可写、可枚举和可配置等属性特性。

Object.defineProperty 是 JavaScript 中高级对象属性定义和控制的有力工具,它使你可以更精确地管理对象的属性行为。然而,在日常开发中,通常更常见的是使用对象字面量语法或点操作符来定义和修改属性,因为它们更简洁和直观。但了解 Object.defineProperty 可以帮助你理解 JavaScript 对象属性的内部工作原理,并在需要时使用它来实现更高级的需求。

6.2 vue中的数据代理

数据代理是一种编程模式,通常用于对象或类中,其中一个对象(代理对象)充当另一个对象(目标对象)的代理,允许代理对象访问和操作目标对象的属性和方法。这个模式常常用于简化代码、提高可维护性、增加安全性或实现其他特定的行为。

在Vue中,数据代理是一种重要的机制,它允许你通过Vue实例来访问和修改组件中的数据属性,而这些数据属性通常被定义在组件的data选项中。数据代理的目的是为了提供更方便的数据访问方式,并且确保数据的响应性(Reactivity)以便于视图的更新。

以下是Vue中的数据代理示例:

new Vue({
  data: {
    message: 'Hello, Vue!'
  },
  methods: {
    showMessage: function () {
      alert(this.message); // 通过数据代理访问message属性
    }
  }
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

在上面的示例中,this.message 中的 this 实际上是Vue实例,通过数据代理,你可以直接访问message属性,而不必使用this.data.message

Vue会自动进行数据代理,将data选项中的属性代理到Vue实例上。这意味着你可以像访问Vue实例自身属性一样访问和修改data中的属性。

数据代理的好处包括:

  1. 方便的数据访问和修改: 不需要额外的语法或方法,可以直接使用this来访问数据属性。

  2. 数据响应性: 当数据属性发生变化时,Vue会自动触发视图的更新,确保视图与数据保持同步。

  3. 避免了深度嵌套: 在传统JavaScript中,深度嵌套的对象访问可能会变得复杂,而Vue的数据代理将属性扁平化,使访问更容易。

  4. 更好的代码结构: 将数据属性代理到Vue实例上可以更好地组织代码,使代码结构更清晰和易于维护。

需要注意的是,在Vue组件中,数据代理只会代理data选项中的属性。如果需要代理计算属性(computed)或方法(methods)中的属性,你仍然需要使用相应的方法或语法来访问它们。

总结而言,Vue中的数据代理是一种使数据访问更方便、提高代码可读性的机制,同时也确保了数据的响应性。这是Vue框架的核心之一,有助于构建交互式的前端应用程序。

七、vue事件处理

在Vue中,事件处理是一种用于监听和响应DOM事件的重要机制,它允许你在Vue组件中定义和处理事件。Vue提供了一些指令和语法来实现事件处理,以下是一些常见的用法:

  1. v-on 指令: v-on 是Vue中用于监听DOM事件的指令。你可以将它添加到任何支持事件的HTML元素上,然后指定要监听的事件名称以及触发事件时要执行的方法。

    <button v-on:click="handleClick">点击我</button>
    
    • 1
    new Vue({
      methods: {
        handleClick: function() {
          alert('按钮被点击了!');
        }
      }
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在上面的示例中,当按钮被点击时,handleClick方法会被调用。

  2. 事件修饰符: Vue允许你使用事件修饰符来修改事件监听的行为。例如,可以使用 .stop 修饰符来停止事件冒泡,或使用 .prevent 修饰符来阻止默认事件行为。

    <a v-on:click.stop="doSomething">阻止冒泡</a>
    <form v-on:submit.prevent="onSubmit">阻止表单提交</form>
    
    • 1
    • 2
  3. 内联事件处理程序: 你还可以在模板中直接使用内联事件处理程序,而不必在方法中定义事件处理函数。这通常用于简单的事件处理。

    <button v-on:click="alert('按钮被点击了!')">点击我</button>
    
    • 1

    在上面的示例中,点击按钮时会直接触发alert函数。

  4. 传递参数: 有时你需要将参数传递给事件处理函数。你可以使用$event来访问事件对象,或者使用 v-bind 来绑定事件参数。

    <button v-on:click="sayHello('Vue', $event)">点击我</button>
    
    • 1
    new Vue({
      methods: {
        sayHello: function(name, event) {
          alert('Hello, ' + name + '! Event type: ' + event.type);
        }
      }
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
  5. 自定义事件: Vue允许你在组件中自定义事件,并在需要时触发这些事件。这在组件之间进行通信时非常有用。

    <!-- 子组件 -->
    <button @click="notifyParent">通知父组件</button>
    
    <script>
    export default {
      methods: {
        notifyParent() {
          this.$emit('custom-event', '自定义数据');
        }
      }
    };
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    <!-- 父组件 -->
    <child-component @custom-event="handleCustomEvent"></child-component>
    
    <script>
    export default {
      methods: {
        handleCustomEvent(data) {
          console.log('父组件收到自定义事件,数据为:', data);
        }
      }
    };
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

通过这些方式,Vue提供了丰富的事件处理功能,使你能够轻松地管理和响应DOM事件,实现互动和通信。无论是简单的点击事件还是自定义事件,Vue都提供了相应的工具来满足不同的需求。

7.1 事件处理的简写

Vue中的事件处理有一种简写方式,通常使用@符号,用于监听DOM事件并触发Vue实例中的方法。这个简写方式也称为事件绑定的缩写。

以下是一个示例,演示了如何使用@符号进行事件处理的简写:

<template>
  <button @click="handleClick">点击我</button>
</template>

<script>
export default {
  methods: {
    handleClick() {
      alert('按钮被点击了!');
    }
  }
};
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

在上面的示例中,我们在<button>元素上使用了@click来监听点击事件,当按钮被点击时,handleClick方法会被触发。

这个简写方式更加简洁和直观,使得事件处理代码更容易理解和维护。当你需要监听其他DOM事件时,只需使用相应的事件名来替代click即可。例如,要监听鼠标移入事件,可以使用@mouseenter

这个事件处理的简写方式是Vue中常用的一种方式,特别适合在模板中处理用户交互。它与传统的JavaScript事件处理方式相比,更具Vue的声明性和易用性。

7.2 监听的事件

在Vue中,你可以监听和处理各种不同类型的DOM事件以及Vue自定义事件。以下是一些常见的事件类型:

  1. 鼠标事件:

    • click:当元素被点击时触发。
    • mousedown:鼠标按钮按下时触发。
    • mouseup:鼠标按钮释放时触发。
    • mousemove:鼠标在元素上移动时触发。
    • mouseentermouseleave:鼠标进入或离开元素时触发(不冒泡)。
    • mouseovermouseout:鼠标进入或离开元素时触发(冒泡)。
  2. 键盘事件:

    • keydown:按下键盘按键时触发。
    • keyup:释放键盘按键时触发。
    • keypress:按下并释放键盘按键时触发。
  3. 表单事件:

    • input:输入框的值发生变化时触发。
    • submit:表单提交时触发。
    • focusblur:元素获得或失去焦点时触发。
    • change:表单元素的值发生变化时触发(适用于<input><select><textarea>等)。
  4. 窗口事件:

    • resize:浏览器窗口大小变化时触发。
    • scroll:窗口或元素滚动时触发。
  5. 自定义事件: 你可以在Vue组件中自定义事件,并使用 $emit 来触发这些事件,用于组件间通信。

    <!-- 子组件 -->
    <button @click="$emit('custom-event', '自定义数据')">通知父组件</button>
    
    • 1
    • 2
    <!-- 父组件 -->
    <child-component @custom-event="handleCustomEvent"></child-component>
    
    • 1
    • 2
  6. 路由事件: 如果你在Vue项目中使用了Vue Router,你可以监听路由相关事件,例如 beforeRouteEnterbeforeRouteLeave 等。

这只是一些常见的事件类型,实际上,你可以监听和处理任何DOM事件,具体取决于你的应用程序需求。使用Vue的v-on指令,你可以将事件处理程序绑定到任何支持事件的DOM元素上,以响应用户交互和应用程序的需求。这些事件用于与用户互动、处理表单输入、监听页面大小变化等各种情况。

7.2.1 鼠标事件修饰符

让我们通过一些示例来说明Vue中的常见事件修饰符的用法:

  1. .stop修饰符: 阻止事件冒泡。

    <div @click="outerDivClick">
      <button @click.stop="innerButtonClick">按钮</button>
    </div>
    
    • 1
    • 2
    • 3
    new Vue({
      methods: {
        outerDivClick() {
          console.log('外部div被点击');
        },
        innerButtonClick() {
          console.log('按钮被点击,但不会触发外部div的点击事件');
        }
      }
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    当点击按钮时,虽然按钮的点击事件会被触发,但外部div的点击事件不会被触发,因为.stop修饰符阻止了事件冒泡。

  2. .prevent修饰符: 阻止事件的默认行为。

    <a @click.prevent="doNothing" href="https://www.example.com">点击链接</a>
    
    • 1
    new Vue({
      methods: {
        doNothing() {
          console.log('链接被点击,但不会跳转到页面 https://www.example.com');
        }
      }
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    当点击链接时,虽然点击事件会触发,但由于.prevent修饰符,不会跳转到链接的目标页面。

  3. .once修饰符: 事件只会触发一次。

    <button @click.once="showMessage">点击一次</button>
    
    • 1
    new Vue({
      methods: {
        showMessage() {
          console.log('按钮被点击,但只会触发一次');
        }
      }
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    当点击按钮后,事件处理函数showMessage只会执行一次。再次点击按钮不会再次触发它。

  4. .self修饰符: 只有事件是从元素本身触发时才会执行。

    <div @click.self="doThis">点击我</div>
    
    • 1
    new Vue({
      methods: {
        doThis() {
          console.log('点击了div本身');
        }
      }
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    只有直接点击<div>元素本身时,事件处理函数doThis才会执行。如果点击了<div>内部的子元素,事件处理函数不会执行。

继续探讨一些常见的Vue事件修饰符的用法:

  1. .capture修饰符: 使用事件捕获模式。

    <div @click.capture="doThis">点击我</div>
    
    • 1
    new Vue({
      methods: {
        doThis() {
          console.log('点击事件在捕获阶段触发');
        }
      }
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    当设置了.capture修饰符时,事件将在捕获阶段(从最外层元素向目标元素传播)触发,而不是在冒泡阶段触发。这可以用于处理某些特定需求,例如在外部容器中捕获所有点击事件。

  2. .native修饰符: 监听组件根元素的原生事件。

    <my-component @click.native="doThis"></my-component>
    
    • 1
    new Vue({
      methods: {
        doThis() {
          console.log('点击了my-component组件的根元素的原生事件');
        }
      }
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    通常,Vue组件会封装其内部的DOM结构,但如果你想监听组件根元素上的原生事件,可以使用.native修饰符。

  3. .passive修饰符: 声明事件的默认行为不会被取消。

    <div @touchstart.passive="onTouchStart">滑动我</div>
    
    • 1
    new Vue({
      methods: {
        onTouchStart() {
          console.log('滑动事件,但不会取消默认行为');
        }
      }
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    当使用.passive修饰符时,你告诉浏览器事件处理函数不会取消事件的默认行为,这对于提高性能非常有用,尤其是在处理滚动等性能敏感的事件时。

7.2.2 键盘事件修饰符
  1. 常用的按键别名和修饰符:
  • 回车键 (enter):

    <input @keyup.enter="submitForm" />
    
    • 1

    当用户按下回车键时,submitForm方法会被触发。

  • 删除键 (delete):

    <input @keydown.delete="deleteItem" />
    
    • 1

    当用户按下删除键或退格键时,deleteItem方法会被触发。

  • 退出键 (esc):

    <button @keydown.esc="closeModal">关闭模态框</button>
    
    • 1

    当用户按下Escape键时,closeModal方法会被触发。

  • 空格键 (space):

    <button @keydown.space="startPlayback">开始播放</button>
    
    • 1

    当用户按下空格键时,startPlayback方法会被触发。

  • 换行键 (tab):

    <input @keydown.tab="focusNextField" />
    
    • 1

    当用户按下Tab键时,focusNextField方法会被触发。需要注意,.tab修饰符必须配合keydown事件使用。

  • 上箭头键 (up):

    <input @keyup.up="increaseValue" />
    
    • 1

    当用户按下上箭头键时,increaseValue方法会被触发。

  • 下箭头键 (down):

    <input @keydown.down="decreaseValue" />
    
    • 1

    当用户按下下箭头键时,decreaseValue方法会被触发。

  • 左箭头键 (left) 和右箭头键 (right) 的用法与上面类似,可以通过相应的修饰符监听这些键的事件。

  1. 使用按键的原始 key 值:

如果Vue没有提供别名的按键,你可以使用按键的原始 key 值,并确保将其转为 kebab-case(短横线命名)。

<input @keydown.page-down="scrollDown" />
  • 1

在这个示例中,page-down 是原始 keyPageDownkebab-case 表示。

  1. 系统修饰键:

系统修饰键包括 ctrlaltshiftmeta。它们的使用方式有一些特殊情况:

  • 配合 keyup 使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才会被触发。
<input @keyup.ctrl="ctrlKeyReleased" />
  • 1

在这个示例中,ctrlKeyReleased 方法只在释放Ctrl键时触发。

  • 配合 keydown 使用:正常触发事件,不需要同时释放其他键。
<input @keydown.alt="altKeyPressed" />
  • 1

在这个示例中,altKeyPressed 方法在按下Alt键时触发。

  1. 使用 keyCode

虽然不推荐使用,但你也可以使用 keyCode 来指定具体的按键。这种方式已经被废弃,不建议使用,因为它依赖于底层浏览器的实现。

<input @keydown.13="handleEnterKey" />
  • 1

在这个示例中,13 是回车键的键码。

  1. 自定义键名:

你可以通过 Vue.config.keyCodes 来自定义按键别名和它们对应的键码。这可以用于定制自己的按键别名。

Vue.config.keyCodes.myKey = 42;
  • 1

然后,你可以使用 myKey 作为按键别名。

<input @keydown.myKey="customKeyHandler" />
  • 1

这些示例详细展示了不同按键别名和修饰符的用法,以及如何处理键盘事件和定制按键别名。根据你的具体需求,选择适当的方式来处理键盘事件可以让你的Vue应用更加灵活和强大。

八、 计算属性

8.1计算属性的定义:

计算属性是一种在Vue组件中定义的特殊属性,它的值是根据已有的响应式数据计算而来的,通常用于处理复杂的数据逻辑。你可以使用computed选项来声明计算属性。

computed: {
  // 计算属性的名称
  computedProperty: function() {
    // 计算逻辑
    return someCalculationBasedOnData; //返回值作为computedProperty的值
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

8.2计算属性的原理:

计算属性的实现借助了Object.defineProperty方法提供的gettersetter。通过getter函数,你可以定义计算属性的值如何计算,并且当依赖的数据发生变化时,Vue会自动调用getter来重新计算计算属性的值。同时,你也可以提供setter函数来响应对计算属性的修改。

8.3 访问计算属性:

在模板中,你可以像访问普通属性一样访问计算属性,Vue会自动处理计算属性的计算和缓存。

<div>{{ computedProperty }}</div>
  • 1

8.4 计算属性的get函数执行时机:

  • 初次读取时会执行一次: 当你第一次访问计算属性时,它的get函数会被调用,计算并返回值。
  • 当依赖的数据发生改变时会被再次调用: 如果计算属性依赖的响应式数据发生变化,Vue会自动重新计算计算属性的值,并在需要时将新值返回。

8.5 计算属性的优势:

  • 缓存机制: 计算属性内部有缓存机制,只有在依赖的响应式数据发生变化时才会重新计算,这提高了性能。
  • 效率高: 与使用methods实现相比,计算属性更高效,因为它们只在需要时计算,不会多次重复执行。
  • 调试方便: 计算属性将复杂的计算逻辑封装在一个地方,使代码更易读和维护。

8.6 计算属性的set方法:

如果你希望修改计算属性的值,必须提供一个set方法来响应修改,并在set方法中更新计算时依赖的数据。

computed: {
  fullName: {
    // 计算属性的getter
    get: function() {
      return this.firstName + ' ' + this.lastName;
    },
    // 计算属性的setter
    set: function(newValue) {
      // 解析newValue并更新firstName和lastName
      const names = newValue.split(' ');
      this.firstName = names[0];
      this.lastName = names[1];
    }
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

这个例子中,fullName 计算属性的get方法返回firstNamelastName的合并值,而set方法接受一个新的值,解析出名字并更新firstNamelastName

通过提供set方法,你可以使计算属性变成可写的,并通过计算属性修改依赖数据。

计算属性是Vue中处理派生数据的强大工具,它们提高了性能和代码的可读性,使你能够以一种声明式的方式处理复杂的数据逻辑。

8.7计算属性的简写

完整的计算属性定义方式:

new Vue({
  data: {
    basePrice: 100,
    discount: 10
  },
  computed: {
    // 完整的计算属性定义
    finalPrice: {
      get: function() {
        return this.basePrice - this.discount;
      },
      set: function(newPrice) {
        this.discount = this.basePrice - newPrice;
      }
    }
  }
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

上面的示例中,finalPrice 计算属性有一个完整的定义,包括 get 方法和 set 方法,可以用于获取和设置 finalPrice 的值。

计算属性的简写方式

new Vue({
  data: {
    basePrice: 100,
    discount: 10
  },
  computed: {
    // 使用简写方式定义计算属性
    finalPrice() {
      return this.basePrice - this.discount;
    }
  }
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

在上面的示例中,finalPrice 计算属性使用了简写方式,只包括 get 方法,用于获取 finalPrice 的值。这是一种更简洁的方式,特别适用于没有需要设置的情况。

总结来说,使用完整的计算属性定义方式需要提供 getset 方法,允许你读取和设置计算属性的值。而使用简写方式只需要提供 get 方法,适用于只需要读取计算属性值的情况。选择哪种方式取决于你的需求和是否需要设置计算属性的值。

九、 监视属性

9.1监视属性(watch)的基本概念:

  1. 触发时机: 监视属性允许你在某个数据属性变化时自动执行回调函数,这对于需要在特定数据变化时采取一些操作非常有用。

  2. 监视属性的存在性: 你只能监视已经存在的数据属性,无法监视未定义的属性。

9.2 监视属性的两种写法:

  1. 通过watch选项配置: 在Vue组件中,你可以在watch选项中配置要监视的属性以及相应的回调函数。明确需要监视的属性时用这种方法。

    new Vue({
      data: {
        someData: 'initial value'
      },
      watch: {
        someData: function(newValue, oldValue) {
          // 在 someData 属性变化时执行回调
          console.log('someData 发生变化:', newValue, oldValue);
        }
      }
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
  2. 通过vm.$watch方法: 你还可以使用Vue实例的$watch方法来动态添加监视属性。后期根据需求添加监视属性的时候用这种方法

    const vm = new Vue({
      data: {
        someData: 'initial value'
      }
    });
    
    // 使用 $watch 方法监视 someData 属性
    vm.$watch('someData',
        function(newValue, oldValue) {
      // 在 someData 属性变化时执行回调
      console.log('someData 发生变化:', newValue, oldValue
                  );
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

这两种写法都允许你在监视的属性发生变化时执行自定义的回调函数,以便处理数据的变化和执行相关操作。

总之,监视属性是Vue中一种用于跟踪数据变化并执行自定义操作的机制,它有助于处理数据的特殊情况和执行异步操作。

9.3 深度监视属性

深度监视(Deep Watch):

  1. 默认不监测对象内部值的改变: 在Vue.js中,默认情况下,watch不会监测对象内部值的改变,只会监测对象的引用是否发生变化。

  2. 配置deep: true可以监测对象内部值改变: 如果你想要监测对象内部值的改变,你可以在watch选项中将deep设置为true。这样Vue会递归地深度监测对象内部的所有属性和值的变化。

备注:

  1. Vue自身可以监测对象内部值的改变: Vue实例本身具有能力监测对象内部值的改变,这意味着当你直接修改对象内部的属性值时,Vue会自动触发视图的更新。但是,使用watch选项时,默认情况下不会监测对象内部值的改变,除非显式启用深度监视。

  2. 根据数据结构决定是否采用深度监视: 是否使用深度监视取决于数据的结构和你的需求。如果你需要监测对象内部值的变化,可以使用深度监视。但请注意,深度监视可能会引入性能开销,因此要谨慎使用。

深度监视是Vue.js提供的一项强大功能,可确保你能够捕捉到对象内部值的变化,从而更精确地响应数据的改变。

让我为你提供一个更具体的例子,以展示深度监视的效果。在这个示例中,我们将创建一个包含嵌套对象的数据结构,并使用深度监视来监听内部值的变化。

<!DOCTYPE html>
<html>
<head>
  <title>Vue Deep Watch Example</title>
</head>
<body>

<div id="app">
  <h2>深度监视属性示例</h2>
  <p>User Name: {{ user.name }}</p>
  <p>User Age: {{ user.age }}</p>
  <button @click="changeUserName">修改用户姓名</button>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>
new Vue({
  el: '#app',
  data: {
    user: {
      name: 'John',
      age: 30
    }
  },
  methods: {
    changeUserName: function() {
      // 模拟修改用户对象内部值
      this.user.name = 'Alice';
    }
  },
  watch: {
    // 使用深度监视属性来监测 user 对象的内部值变化
    'user': {
      handler: function(newValue, oldValue) {
        console.log('user 对象发生变化', newValue, oldValue);
      },
      deep: true // 启用深度监视
    }
  }
});
</script>

</body>
</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

在这个示例中,我们有一个user对象,其中包含nameage属性。我们使用深度监视属性来监测整个user对象的变化。当点击按钮以模拟修改user对象内部的name属性时,深度监视能够捕捉到这个内部值的变化,并触发watch中的回调函数。

9.4 深度监视的简写

只有当监视属性只需要一个回调函数的时候,才可以简写。(只需要handler属性时)

使用监视属性的简写方式

<!DOCTYPE html>
<html>
<head>
  <title>Vue Watch Shorthand Example</title>
</head>
<body>

<div id="app">
  <p>当前计数:{{ count }}</p>
  <button @click="increment">增加计数</button>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>
new Vue({
  el: '#app',
  data: {
    count: 0
  },
  methods: {
    increment: function() {
      this.count++;
    }
  },
  watch: {
    // 使用监视属性的简写方式
    count(newValue, oldValue) {
      console.log('count 属性发生变化,新值为:', newValue, '旧值为:', oldValue);
    }
  }
});
</script>

</body>
</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

在这个示例中,我们使用了监视属性的简写方式。在watch选项中,我们直接将count作为键,然后在函数参数中接收新值(newValue)和旧值(oldValue)。这是一种更简洁的方式来定义监视属性。

使用监视属性的完整写法:

<!DOCTYPE html>
<html>
<head>
  <title>Vue Watch Full Example</title>
</head>
<body>

<div id="app">
  <p>当前计数:{{ count }}</p>
  <button @click="increment">增加计数</button>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<script>
new Vue({
  el: '#app',
  data: {
    count: 0
  },
  methods: {
    increment: function() {
      this.count++;
    }
  },
  watch: {
    // 使用监视属性的完整写法
    count: {
      handler(newValue, oldValue) {
        console.log('count 属性发生变化,新值为:', newValue, '旧值为:', oldValue);
      },
      deep: false, // 深度监视,默认为false
      immediate: false // 立即执行,默认为false
    }
  }
});
</script>

</body>
</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

在这个示例中,我们使用了监视属性的完整写法。在watch选项中,我们将count作为键,然后使用对象字面量的形式定义监视属性。这允许我们配置更多的选项,如深度监视和立即执行。

总的来说,简写方式更简洁,适用于简单的监视属性情况,而完整写法允许你更灵活地配置监视属性的行为,以满足特定需求。根据你的需求和代码的复杂性,可以选择使用其中之一。

9.5 computed 和 watch 属性对比

computedwatch都是用于监听数据变化并执行相应操作的Vue.js功能,但它们在用途和实现方式上有一些不同:

Computed 属性:

  1. 计算属性computed属性是基于其依赖的数据进行计算得出的属性,它的值会被缓存,只有依赖的数据发生变化时才会重新计算。

  2. 自动更新:计算属性会自动响应数据的变化,当依赖的数据发生改变时,计算属性的值会自动更新。

  3. 缓存:计算属性的值在同一依赖数据的情况下只会计算一次,之后会从缓存中获取,这有助于提高性能。

  4. 适用于处理派生数据:适用于需要根据其他数据计算得出的数据,例如对数据的过滤、排序或格式化等操作。

  5. 没有副作用:通常情况下,计算属性用于返回一个计算值,不用于执行副作用或异步操作。

Watch 监视属性:

  1. 监视数据变化watch用于监视特定数据的变化,当指定的数据发生变化时,执行指定的回调函数。

  2. 更灵活watch更灵活,可以执行任意操作,包括异步操作和副作用,因为你可以在回调函数中执行任意代码。

  3. 无缓存:与计算属性不同,watch没有缓存,每次数据变化都会触发回调函数。

  4. 手动停止监视:你可以手动停止监视某个属性的变化,通过调用vm.$watch返回的函数来取消监视。

总结:

  1. 功能重叠

    • computed可以完成的功能,watch都可以完成。
    • watch可以完成的功能,computed不一定能够完成,特别是在需要执行异步操作时。
  2. 原则性建议

    • 所有由Vue管理的函数,最好写成普通函数,以确保this指向Vue实例对象或组件实例对象。
    • 所有不由Vue管理的函数(例如定时器回调、Ajax回调、Promise回调等),最好写成箭头函数,以确保this指向Vue实例对象或组件实例对象。

十、绑定样式

10.1 class样式 - 字符串写法:

适用于类名不确定,需要动态获取的情况。

<div :class="className">这是一个示例文本</div>
  • 1
data: {
  className: 'active'
}
  • 1
  • 2
  • 3

在这个示例中,className是一个数据属性,它的值是一个字符串'active',该字符串作为CSS类名动态绑定到<div>元素上。

10.2 class样式 - 对象写法:

适用于需要绑定多个样式,个数不确定,名字也不确定的情况

<div :class="{ active: isActive, 'text-danger': hasError }">这是一个示例文本</div>
  • 1
data: {
  isActive: true,
  hasError: false
}
  • 1
  • 2
  • 3
  • 4

在这个示例中,我们使用了对象语法来绑定CSS类。根据isActivehasError的值,activetext-danger类会被动态添加或移除。

10.3 class样式 - 数组写法:

适用于需要绑定多个样式,个数确定,名字也确定,但不确定是否都要绑定的情况。

<div :class="[classA, classB]">这是一个示例文本</div>
  • 1
data: {
  classA: 'classA',
  classB: 'classB'
}
  • 1
  • 2
  • 3
  • 4

在这个示例中,我们使用了数组语法来绑定CSS类。classAclassB是数据属性,它们的值会作为CSS类应用在<div>元素上。

10.4 style样式 - 对象写法:

适用于根据数据的变化动态设置内联样式属性。

<div :style="styleObj">这是一个示例文本</div>
  • 1
data: {
  styleObj:{
      // 样式与css里的一样,这里要用驼峰命名法
        color:'red',
        fontSize:16px
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在这个示例中,我们使用对象语法来绑定内联样式。根据textColortextSize的值,文本的颜色和字体大小会动态设置。

10.5 style样式 - 数组写法:

适用于动态生成多个内联样式属性的情况。

<div :style="styleArr">这是一个示例文本</div>
  • 1
data: {
  styleArr: [
    color: 'blue',
    fontWeight: 'bold'
  },
 {
    backgroundColor: 'yellow',
    borderRadius: '4px'
  }
]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

在这个示例中,我们使用了数组语法来绑定内联样式。styleObjectAstyleObjectB是样式对象,它们的样式属性会合并应用在<div>元素上。

这些示例演示了每种绑定样式的写法以及它们在Vue.js应用中的使用方式。你可以根据具体的需求和场景选择适合的方式来管理元素的样式。

十一、条件渲染

条件渲染是Vue.js中的一项重要功能,允许你根据数据的条件来决定是否渲染(显示)某个元素或组件,或者渲染不同的内容。在Vue.js中,我们通常使用以下指令和技巧来实现条件渲染:

11.1 v-ifv-else-ifv-else

  • v-if:通过 v-if 指令,你可以根据条件来渲染元素。写法如下:

    <div v-if="expression">显示内容</div>
    
    • 1

    适用于切换频率较低的场景。特点是不展示的DOM元素直接被移除。

  • v-else-ifv-else:你还可以使用 v-else-ifv-else 来实现多个条件分支,写法如下:

    <div v-else-if="expression2">显示内容2</div>
    <div v-else>显示其他内容</div>
    
    • 1
    • 2

    这些指令适用于多个条件之间的切换,但要求它们在结构上不能被“打断”。

11.2 v-show

  • v-show 指令适用于切换频率较高的场景,写法如下:

    <div v-show="expression">显示内容</div>
    
    • 1

    v-if 不同,v-show 不会移除不显示的DOM元素,它仅仅使用样式隐藏元素。

当涉及到v-ifv-else-ifv-elsev-show时,它们在实现和执行上有一些区别,而<template>可以用于解决结构不能被“打断”的问题。以下是详细整理的内容:

11.3 区别和使用场景:

v-ifv-else-ifv-else:

  • 这些指令用于根据条件来决定是否渲染元素。它们在结构上互相关联,只有一个条件为真时才会渲染相应的元素。

  • 适用于切换频率较低的场景,因为它们会在不满足条件时移除整个DOM元素。

v-show

  • v-show 用于根据条件来切换元素的可见性,而不会移除元素。它在结构上不会打断,适用于需要频繁切换可见性的元素。

11.4 使用 <template> 解决结构问题:

有时,使用 v-ifv-else-ifv-else 可能会在结构上引发问题,因为它们要求在条件语句内部包含一个根元素。这时可以使用 <template> 元素来包裹条件渲染的内容,以解决这个问题。

<template v-if="conditionA">
  <!-- 这里是条件A为真时渲染的内容 -->
</template>
<template v-else-if="conditionB">
  <!-- 这里是条件B为真时渲染的内容 -->
</template>
<template v-else>
  <!-- 这里是其他情况下渲染的内容 -->
</template>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

使用 <template> 元素可以让条件渲染的内容不再要求包含在一个单独的根元素内,从而避免了结构上的问题。

综上所述,v-ifv-else-ifv-elsev-show 在实现和执行上有区别,可以根据具体的需求选择合适的方式。当涉及到结构问题时,可以使用 <template> 元素来解决。这些工具使得Vue.js能够根据数据状态动态渲染不同的用户界面,增加了页面的灵活性和交互性。

注意点:

  • 当使用 v-if 时,可能导致不展示的元素无法获取,而使用 v-show 时,元素始终存在并可以获取。

这些指令和技巧使得Vue.js能够根据数据状态动态地渲染不同的用户界面,从而实现了更灵活和交互性强的Web应用程序。你可以根据具体需求选择适合的条件渲染方式。

十二、 列表渲染

当使用 v-for 指令时,你可以用它来展示列表数据,不仅仅是数组,还可以遍历对象、字符串,甚至指定次数。

12.1v-for 指令

  • v-for 指令用于在模板中进行循环遍历,通常用于展示列表数据。

  • 语法:v-for="(item, index) in xxx" :key="yyy",其中:

    • (item, index) 是循环中的形参,用于表示当前项和索引(可选)。
    • xxx 是要遍历的数据源,可以是数组、对象、字符串或指定次数。
    • :key 是必须的,用于提供唯一键,以便Vue能够高效地跟踪每个项的变化。

12.2 可遍历的数据类型

  1. 数组:常见用法,用于遍历数组中的元素。
  2. 对象:可以用于遍历对象的属性和值。
  3. 字符串:用得较少,但你可以遍历字符串的字符。
  4. 指定次数:有时你只需要循环特定次数,可以使用整数范围。

当使用 v-for 指令遍历不同的数据类型时,输出结果会根据数据类型和循环内容而异。

12.2.1 遍历数组

示例:

适用场景:

  • 展示数组中的数据,例如商品列表、评论列表等。
<template>
  <div>
    <ul>
      <li v-for="(item, index) in items" :key="index">
        {{ index }}: {{ item }}
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  data() {
    return {
      items: ['Apple', 'Banana', 'Cherry', 'Date']
    };
  }
};
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

输出结果:

  • 0: Apple
  • 1: Banana
  • 2: Cherry
  • 3: Date
12.2.2 遍历对象

示例:

适用场景:

  • 展示对象的属性和值,例如用户信息、产品属性等。
<template>
  <div>
    <ul>
      <li v-for="(value, key) in object" :key="key">
        {{ key }}: {{ value }}
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  data() {
    return {
      object: {
        name: 'John',
        age: 30,
        country: 'USA'
      }
    };
  }
};
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

输出结果:

  • name: John
  • age: 30
  • country: USA
12.2.3 遍历字符串

示例:

适用场景:

  • 遍历字符串的字符,例如字符串动画效果、标签云等。
<template>
  <div>
    <ul>
      <li v-for="char in str" :key="char">
        {{ char }}
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  data() {
    return {
      str: 'Vue.js'
    };
  }
};
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

输出结果:

  • V
  • u
  • e
  • .
  • j
  • s
###12.2.4 指定次数

示例:

适用场景:

  • 在特定情况下,需要指定次数来生成重复的内容,例如轮播图、分页器等。
<template>
  <div>
    <ul>
      <li v-for="n in 5" :key="n">
        Item {{ n }}
      </li>
    </ul>
  </div>
</template>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

输出结果:

  • Item 1
  • Item 2
  • Item 3
  • Item 4
  • Item 5

这些输出结果展示了不同可遍历数据类型的 v-for 指令的应用,你可以根据你的具体需求和数据类型来选择使用。

12.3 key的原理(重点)

12.3.1 key` 在虚拟 DOM 中的作用:
  • key 是虚拟 DOM 对象的标识,用于在数据发生变化时识别和管理虚拟 DOM 元素。
  • Vue 使用 key 来进行新虚拟 DOM 与旧虚拟 DOM 的差异比较,从而高效地更新真实 DOM。
12.3.2 对比规则:
  • 当进行虚拟 DOM 对比时,Vue 将按照以下规则处理 key
    • 如果在旧虚拟 DOM 中找到了与新虚拟 DOM 相同的 key
      • 如果虚拟 DOM 中内容没有变化,直接复用之前的真实 DOM。
      • 如果虚拟 DOM 中内容发生变化,生成新的真实 DOM 并替换页面中的旧真实 DOM。
    • 如果在旧虚拟 DOM 中未找到与新虚拟 DOM 相同的 key,则创建新的真实 DOM 并进行渲染。
12.3.3 使用索引(index)作为 key 的潜在问题:
  • 使用索引作为 key 有时可能会导致性能问题和不稳定的渲染行为,特别是在以下情况下:
    1. 当对数据进行逆序添加或逆序删除等破坏顺序的操作时,可能会产生不必要的真实 DOM 更新,效率低。
    2. 如果虚拟 DOM 结构中包含输入类的 DOM 元素,可能会导致错误的 DOM 更新,从而导致界面问题。
12.3.4 如何选择 key
  • 最好使用每条数据的唯一标识作为 key,例如 id、手机号、身份证号、学号`等唯一值。
  • 如果你确定不会对数据进行逆序添加或逆序删除等破坏顺序操作,仅用于渲染列表展示,使用索引作为 key 是可以接受的。

十三 、数据监测的原理

  1. 监测对象的数据

    • Vue会在初始化时通过 Object.defineProperty 或 ES6 的 Proxy 来设置对象属性的 getter 和 setter,实现属性的监测。
    • Vue会递归遍历对象的所有属性,包括嵌套对象,确保所有数据都被监测。
    • 如果需要给对象后添加属性并使其具有响应性,可以使用 Vue.set()vm.$set()
  2. 监测数组的数据

    • Vue会包装数组的一些方法,这些方法都会改变原数组(例如:push()pop()shift()unshift()splice()sort()reverse())以实现响应式。
    • 当使用这些方法修改数组时,Vue会检测到变化并重新解析模板,从而更新页面。
  3. 注意事项

    • 对于对象属性,Vue默认只监测初始化时存在的属性。后续添加的属性需要使用 Vue.set()vm.$set() 来实现响应性。
    • 对于数组元素,只有通过 Vue 包装过的方法或上述的数组修改方法才会触发响应式更新。
    • 需要注意的是,Vue.set()vm.$set() 不能用于给Vue实例对象或根数据对象添加属性。

Vue的数据监测原理,它确保数据的响应性和自动更新。这是Vue实现响应式框架的核心机制之一,使得数据和视图之间的同步变得更加容易和高效。

13.1 set的使用

当你需要向Vue响应式对象中添加属性或使后添加的属性具有响应性时,可以使用 Vue.setthis.$set。以下是有关这两种方法的笔记总结:

13.1.1 Vue.set 方法
Vue.set(target, propertyName, value)
  • 1
  • target:目标对象,即要添加属性的对象。通常是一个响应式对象。
  • propertyName:要添加或修改的属性名。
  • value:要设置的属性值。

注意事项

  • target 应该是一个响应式对象,可以是Vue组件的 data的 属性,或嵌套在 data 中的对象,或任何已经具有响应性的对象。(不可以为vm或者vm的跟属性data
  • propertyName 是要添加或修改的属性名,必须是一个字符串或表达式。
  • 避免在已有的响应式属性上调用 Vue.set
13.1.2 this.$set 方法
this.$set(target, propertyName, value)
  • 1
  • this:Vue 实例。
  • target:目标对象,即要添加属性的对象。通常是一个响应式对象。
  • propertyName:要添加或修改的属性名。
  • value:要设置的属性值。

注意事项

  • this.$set 主要用于在 Vue 组件内部添加响应式属性,更方便地访问 Vue 实例。
  • 遵循与 Vue.set 相同的注意事项,确保目标对象是响应式的。

使用场景

  • 主要用于向响应式对象添加属性,特别是在组件内部的数据对象上添加属性。
  • 避免频繁使用,最好在初始化数据时就定义好数据结构,以提高性能。

这些方法使你能够在需要时向响应式对象添加属性,确保数据和视图的同步,并避免潜在的问题。

十四、过滤器

14.1 局部过滤器和全局过滤器

局部过滤器:

局部过滤器只在单个 Vue 实例内部可用。你可以在该实例的 filters 属性中定义和使用它们。这些过滤器仅在当前 Vue 实例的模板中可见。

new Vue({
  el: '#app',
  data: {
    message: 'hello, world!',
  },
  filters: {
    customFilter: function (value) {
      return value.toUpperCase();
    },
  },
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

全局过滤器:

全局过滤器在所有 Vue 实例中都可用。你可以通过 Vue 构造函数的 filter 方法来注册全局过滤器。

Vue.filter('customFilter', function (value) {
  return value.toUpperCase();
});
  • 1
  • 2
  • 3

14.2 过滤器的用法

过滤器可以用在插值表达式 {{ }} 中,也可以用在 v-bindv-modelv-for 等指令中。例如:

{{ message | customFilter }}
<div v-bind:class="classObject | customFilter"></div>
<input v-model="message | customFilter">
<div v-for="item in items | customFilter">{{ item }}</div>
  • 1
  • 2
  • 3
  • 4

14.3 过滤器如何接收参数以及多个过滤器串联

过滤器可以接收参数,参数可以在过滤器名称后用单引号 ‘ ’ 指定。多个过滤器可以通过管道符 | 进行串联。

过滤器的参数是逐层传递的

{{ message | customFilter('arg1', 'arg2') | anotherFilter }}
// message作为customFilter的参数,customFilter的返回结果又作为anotherFilter的参数
  • 1
  • 2

在自定义过滤器中,可以通过函数的参数接收这些参数:

Vue.filter('customFilter', function (value, arg1, arg2) {
  // 这里可以使用 value、arg1 和 arg2 来处理数据
});
  • 1
  • 2
  • 3

14.4 是否改变原数据

Vue 的过滤器默认不会改变原始数据,它们是纯粹的函数式。过滤器的目的是将输入值转换为输出值,而不修改输入值。如果需要修改原始数据,通常应该在数据绑定或组件方法中进行操作,而不是在过滤器中。

十五、Vue指令

15.1 Vue 内置指令

Vue.js 提供了一系列内置指令,用于处理视图层的渲染和交互逻辑。这些指令以 v- 开头,可以直接应用于模板中的 HTML 元素。以下是各个内置指令的详细介绍和示例:

  1. v-bind:用于绑定 DOM 元素的属性、CSS 类名和内联样式,实现数据和视图之间的绑定。

    示例:

    <!-- 绑定 href 属性 -->
    <a v-bind:href="url">Link</a>
    
    <!-- 使用简写语法 -->
    <a :href="url">Link</a>
    
    <!-- 动态生成 class -->
    <div v-bind:class="{ active: isActive, 'text-danger': hasError }"></div>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  2. v-model:主要用于表单元素,实现双向数据绑定,将表单输入的值和数据进行同步。

    示例:

    <!-- 文本输入框双向绑定 -->
    <input v-model="message" type="text">
    
    <!-- 复选框绑定 -->
    <input v-model="isChecked" type="checkbox">
    
    <!-- 单选按钮绑定 -->
    <input v-model="selected" type="radio" value="A">
    <input v-model="selected" type="radio" value="B">
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
  3. v-for:用于循环渲染元素列表,根据数组或对象的内容生成多个元素。

    示例:

    <!-- 遍历数组 -->
    <ul>
      <li v-for="item in items">{{ item }}</li>
    </ul>
    
    <!-- 遍历对象 -->
    <ul>
      <li v-for="(value, key) in object">{{ key }}: {{ value }}</li>
    </ul>
    
    <!-- 遍历字符串 -->
    <div v-for="char in 'Vue.js'">{{ char }}</div>
    
    <!-- 指定次数遍历 -->
    <div v-for="n in 5">{{ n }}</div>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
  4. v-if / v-else-if / v-else:条件性地渲染元素,根据表达式的值来决定是否显示元素。

    示例:

    <!-- 条件渲染 -->
    <p v-if="isShow">This is shown</p>
    <p v-else>This is hidden</p>
    
    <!-- 多条件渲染 -->
    <p v-if="status === 'success'">Request succeeded</p>
    <p v-else-if="status === 'error'">Request failed</p>
    <p v-else>Request pending</p>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  5. v-show:条件性显示元素,通过 CSS 控制显示或隐藏,不会销毁元素。

    示例:

    <!-- 条件显示 -->
    <div v-show="isVisible">This is shown or hidden</div>
    
    • 1
    • 2
  6. v-on:绑定事件监听器,触发指定事件时执行相应的方法。

    示例:

    <!-- 点击事件 -->
    <button v-on:click="doSomething">Click me</button>
    
    <!-- 使用简写语法 -->
    <button @click="doSomething">Click me</button>
    
    <!-- 传递参数 -->
    <button @click="doSomething('parameter')">Click me</button>
    
    <!-- 监听自定义事件 -->
    <custom-component @custom-event="handleCustomEvent"></custom-component>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
  7. v-pre:跳过当前元素及其子元素的编译过程,用于静态内容不需要 Vue 处理的情况。

    示例:

    <!-- 使用 v-pre 跳过编译 -->
    <div v-pre>{{ message }}</div>
    
    • 1
    • 2
  8. v-cloak:确保 Vue 实例初始化完成前不显示绑定的元素,通常与 CSS 配合使用。

    示例:

    <!-- 使用 v-cloak 隐藏未编译内容 -->
    <div v-cloak>
      {{ message }}
    </div>
    
    • 1
    • 2
    • 3
    • 4
  9. v-html:用于输出 HTML 片段,而不是纯文本,潜在的安全风险需要注意。

    示例:

    <!-- 渲染 HTML 片段(慎用) -->
    <div v-html="htmlContent"></div>
    
    • 1
    • 2
  10. v-once:执行一次性插值,确保元素或组件只渲染一次,适用于静态内容不会改变的情况。

    示例:

    <!-- 渲染静态内容,只渲染一次 -->
    <p v-once>{{ staticMessage }}</p>
    
    • 1
    • 2
  11. v-slot:用于具名插槽的分发,通常在复杂组件中用于父组件向子组件传递内容。

    示例:

    <!-- 具名插槽分发内容 -->
    <custom-component>
      <template v-slot:header>
        <h1>This is the header</h1>
      </template>
      <template v-slot:
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

15.2 Vue自定义指令

自定义指令是 Vue 中用于扩展 DOM 元素行为的灵活机制,通过定义和应用指令,可以实现特定的 DOM 操作和交互逻辑,以满足项目需求。自定义指令允许你在 Vue 应用中添加自定义行为,例如修改元素样式、监听事件、处理输入等,以提供更灵活的交互和视图控制。

15.2.1 定义自定义指令
  1. 局部指令:在组件内部定义自定义指令。

    new Vue({
      directives: {
        自定义指令名: 配置对象
      }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5

    或者

    new Vue({
      directives: {
        自定义指令名(el, binding) {
          // 自定义指令的逻辑
        }
      }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
  2. 全局指令:在应用程序的任何地方定义自定义指令。

    Vue.directive(自定义指令名, 配置对象)
    
    • 1

    或者

    Vue.directive(自定义指令名, function(el, binding) {
      // 自定义指令的逻辑
    })
    
    • 1
    • 2
    • 3
15.2.2 自定义指令的配置对象

配置对象中常用的三个回调函数:

  1. bind:指令与元素成功绑定时调用,用于一次性的初始化设置。

  2. inserted:指令所在元素被插入页面时调用,可以用来操作 DOM 元素。

  3. update:指令所在模板结构被重新解析时调用,通常用于更新指令绑定的值。

15.2.3 使用自定义指令

当在模板中使用自定义指令时,确实需要在指令名前加上 v- 前缀。以下是一个简单的例子:

假设我们定义了一个名为 v-color 的自定义指令,它用于改变元素的文本颜色。首先,在 Vue 实例中注册这个自定义指令:

// 注册全局自定义指令 v-color
Vue.directive('color', {
  // 指令的生命周期钩子
  bind(el, binding) {
    // binding.value 包含传递给指令的值
    el.style.color = binding.value;
  }
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

现在,我们可以在模板中使用这个自定义指令,注意要加上 v- 前缀:

<template>
  <div>
    <!-- 使用自定义指令 v-color,传递颜色值 'red' -->
    <p v-color="'red'">This text is red.</p>
  </div>
</template>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在上面的例子中,我们使用了自定义指令 v-color 并传递了颜色值 'red',它会将元素的文本颜色设置为红色。这是一个简单的示例,说明了在模板中如何使用自定义指令,并在指令名前加上 v- 前缀。

15.2.4 指令命名规范

指令名如果是多个单词,应该使用 kebab-case 命名方式,而不是 camelCase。例如,v-my-directive

15.2.5 自定义指令的执行时机

自定义指令的执行时机与配置对象中的回调函数相关:

  • bind:在指令与元素成功绑定时调用,一次性的初始化设置。
  • inserted:在指令所在元素被插入页面时调用,可以用来操作 DOM 元素。
  • update:在指令所在模板结构被重新解析时调用,通常用于更新指令绑定的值。

十六、生命周期

Vue.js 中的生命周期函数是一组特殊命名的函数,它们允许您在不同的阶段添加自定义代码,以便在组件的生命周期中执行特定的操作。这些函数的名称是固定的,但函数内部的内容是由程序员编写的,用于定义在特定时刻执行的操作

Vue.js 的生命周期可以分为以下主要阶段和生命周期函数:

16.1 创建阶段

  • beforeCreate:在实例初始化之后,数据观测 (data observer) 和事件配置(数据代理)之前调用。在这个阶段,组件的数据和事件还没有初始化。(无法访问vm实例
  • created:在实例创建完成后调用。在这个阶段,组件的数据已经初始化,但 DOM 元素还没有挂载到页面上。

16.2 挂载阶段

  • beforeMount:在挂载开始之前被调用。在这个阶段,模板编译已经完成,但挂载的 DOM 元素还没有渲染到页面上。(虚拟DOM已经生成
  • mounted:在挂载完成后被调用。在这个阶段,组件已经挂载到页面上,可以访问 DOM 元素。

16.3 更新阶段

  • beforeUpdate:在数据更新但 DOM 还没有重新渲染时被调用。在这个阶段,您可以查看更新之前的数据。(页面尚未和数据保持同步
  • updated:在数据更新完成,DOM 已经重新渲染后被调用。在这个阶段,DOM 元素已经更新,可以执行与更新相关的操作。(页面和数据保持同步

16.4 销毁阶段

  • beforeDestroy:在实例销毁之前调用。在这个阶段,实例仍然完全可用,您可以执行清理工作。
  • destroyed:在实例销毁之后调用。在这个阶段,实例已经被销毁,无法再访问其数据和方法。

进入销毁阶段的条件包括手动调用 vm.$destroy() 方法以及组件从父组件中销毁(例如使用 v-if 条件渲染时)。

这些生命周期函数允许您在不同的阶段执行自定义代码,以满足业务需求。例如,在 created 钩子中可以进行数据初始化,而在 mounted 钩子中可以执行 DOM 操作。在 beforeDestroy 钩子中可以进行资源清理操作,确保不会发生内存泄漏。

结束语

在Vue.js的学习过程中,不仅仅是技术知识的积累,更是一段充满启发和乐趣的旅程。Vue的简洁、优雅以及强大的特性让前端开发变得愈发令人着迷。我希望你能感受到这个框架的美妙之处,也能在实际项目中充分发挥它的潜力。

在学习和使用Vue的过程中,不要害怕遇到困难和挑战。每一次的克服都是一次成长,每一次的错误都是一次经验。不断提升自己的前端技能,学会如何构建更出色的用户体验,这是一项不断追求卓越的旅程。

最后,我想对你说声谢谢,感谢你一直与我一同学习和探索。无论你是一名新手还是已经积累了丰富经验的开发者,我都希望你能在前端的路上越走越远,实现自己的技术梦想。祝愿你的代码永远优雅,Bug少之又少,前程似锦。如果你需要任何帮助或有任何问题,请随时向我咨询。加油!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/269326
推荐阅读