Bootstrap

vue3的基本使用方法

【 vue3实例 】

【 0 】对象、方法和属性

对象(Object):

  • 对象是编程中的一个数据结构,它可以包含多种数据类型,包括数字、字符串、布尔值、数组、其他对象等。
  • 对象通常由一系列属性和方法组成。
  • 在面向对象编程(OOP)中,对象是类的实例。类是对一组相关数据和方法的定义,而对象则是具体的数据实例。
  • 对象可以通过类来创建,也可以在一些语言中直接声明。

属性(Property):

  • 属性是对象中的一个数据成员,用于存储对象的状态或数据。
  • 属性可以是任何数据类型,如数字、字符串、布尔值、数组、对象等。
  • 在编程语言中,属性可以通过对象和点符号来访问,例如 obj.property

方法(Method):

  • 方法是对象中的一个函数,用于定义对象的行为。
  • 方法可以执行一些操作,例如改变对象的状态或对对象的数据进行处理。
  • 方法通常在对象的定义中声明,并通过对象和点符号来调用,例如 obj.method()

举例说明

以下是一个 JavaScript 示例,演示对象、属性和方法:

// 定义一个对象
const person = {
    // 属性:用于存储对象的数据
    name: 'Alice',
    age: 30,
    
    // 方法:用于定义对象的行为
    greet: function() {
        console.log(`Hello, my name is ${this.name}`);
    },
    
    // 属性:用于计算对象的状态
    birthday() {
        this.age += 1;
    }
};

// 访问属性
console.log(person.name); // 输出:Alice
console.log(person.age); // 输出:30

// 调用方法
person.greet(); // 输出:Hello, my name is Alice

// 修改属性
person.birthday(); // 增加年龄
console.log(person.age); // 输出:31

在这个示例中:

  • person 是一个对象。
  • nameage 是对象 person 的属性。
  • greetbirthday 是对象 person 的方法。
  • 可以通过 person.name 访问 name 属性,通过 person.greet() 调用 greet 方法。

【 1 】创建vue3.x

// vue create 项目名
// vue create vue3
  1. app01 ([Vue 2] babel, router, vuex):
    • 这个选项代表一个使用 Vue 2 的预设。
    • 它包含了一些常见的开发工具和库,如 Babel、Vue Router 和 Vuex。
    • 这是一个较完整的 Vue 2 项目模板,适合需要使用路由和状态管理的项目。
  2. Default ([Vue 3] babel, eslint):
    • 这个选项代表一个默认的 Vue 3 项目。
    • 它包含了 Babel 和 ESLint,用于处理 JavaScript 代码的转换和静态代码分析。
    • 这个选项是较为基础的 Vue 3 项目模板,适合希望快速开始项目开发的用户。
  3. Default ([Vue 2] babel, eslint):
    • 这个选项代表一个默认的 Vue 2 项目。
    • 它也包含了 Babel 和 ESLint,类似于 Vue 3 的默认选项,但使用的是 Vue 2。
    • 这个选项适合希望在 Vue 2 环境下快速开始项目开发的用户。
  4. Manually select features:
    • 这个选项允许您手动选择要包含在项目中的功能。
    • 您可以根据自己的需求选择是否包含 Babel、Router、Vuex、ESLint、测试工具等。
    • 这种方式提供了更大的灵活性,适合对项目有特殊需求的用户。

image-20240507145412327

  • Babel: Babel 是一个 JavaScript 编译器,它可以将新版本的 JavaScript 代码转换为向后兼容的旧版本,以便在各种浏览器和环境中运行。
  • TypeScript: TypeScript 是 JavaScript 的一个超集,它添加了静态类型检查和其他一些特性,有助于提高代码的可维护性和安全性。
  • Progressive Web App (PWA) Support: 允许您将应用程序转换为渐进式 Web 应用程序,这样用户就可以在离线时访问它们,并享受其他 PWA 的优点。
  • Router: Vue Router 是 Vue.js 的官方路由器,它允许您在单页应用程序中实现导航和页面路由。
  • Vuex: Vuex 是 Vue.js 的官方状态管理库,用于管理应用程序中的共享状态。
  • CSS Pre-processors: 允许您选择在项目中使用的 CSS 预处理器,如 Sass、Less 或 Stylus。
  • Linter / Formatter: 允许您选择是否在项目中包含代码检查工具和格式化工具,如 ESLint 和 Prettier,以确保代码质量和一致性。
  • Unit Testing: 允许您选择是否在项目中包含单元测试工具,以确保代码的功能性正确性。
  • E2E Testing: 允许您选择是否在项目中包含端到端(E2E)测试工具,用于模拟用户操作并测试应用程序的完整性和正确性。

image-20240507145940253

  • 选择版本3.x还是2.x

image-20240507150010581

在这里插入图片描述

  • Check the features needed for your project: 这是您选择项目所需功能的部分。您已选择了 Babel、Router 和 Vuex,这意味着您的项目将包含这三个功能:Babel 用于 JavaScript 编译,Router 用于页面导航,Vuex 用于状态管理。
  • Choose a version of Vue.js that you want to start the project with: 这是选择您想要使用的 Vue.js 版本的部分。您选择了 3.x,表示您希望从 Vue.js 3.x 版本开始项目开发。
  • Use history mode for router? (Requires proper server setup for index fallback in production): 这个选项询问您是否要在路由器中使用历史模式。选择 “Yes” 意味着您希望在路由器中启用历史模式。历史模式使用 HTML5 History API 来管理路由,使 URL 更加美观,并且不带有 # 符号。但是,需要在生产环境中正确配置服务器以处理路由的后备。如果选择 “No”,则将使用默认的哈希模式。
  • Where do you prefer placing config for Babel, ESLint, etc.?: 这个选项询问您偏好将 Babel、ESLint 等配置放在哪里。您选择了将配置放在 package.json 文件中。这意味着相关的配置将作为 package.json 文件的一部分,并且不会创建额外的配置文件。这种方式可以使项目更加简洁,但也可能会导致 package.json 文件变得臃肿,取决于配置的复杂程度。如果选择 “In dedicated config files”,则会为每个配置项创建单独的配置文件,使项目结构更清晰,但可能会增加一些文件数量。

在这里插入图片描述

image-20240507150233743

全过

image-20240507150419258

image-20240507150451555

【 2 】Vue2跟Vue3的区别

​ 先来说说当下市场开发使用的问题,目前2021年使用vue3开发的企业还是少,基本上都还是以vue2的形式进行开发,vue3的开发模式跟react很像,这时候有人就会想那我学vue3有用么,淦,他喵的,先别激动,冷静听我说说,vue3对于现在企业来说都在慢慢的把一些vue2的东西进行升级,这个非常关键,因为vue2中可以使用vue3的方法,vue3不能使用vue2,你连vue2都没有搞定,还拿个锤子去搞vue3,我们先来看看vue3和vue2的一些区别

image-20240507151338959

【 1 】webpack和vite

vue2使用的是webpack形式去构建项目
webpack是一开始是入口文件,然后分析路由,然后模块,最后进行打包,然后告诉你,服务器准备好了可以开始干了

vue create vue3
注意选择vue3,其他都一样
  • ​ webstorm打开–》配置启动
//配置npm 镜像站
// npm config set registry https://registry.npmmirror.com
// npm config get registry

vue3使用vite构建项目
先告诉你服务器准备完成,然后等你发送HTTP请求,然后是入口文件,Dynamic import(动态导入)code split point(代码分割)

​ 最大的好处和区别就是为了让项目中一些代码文件多了以后去保存更新数据时更快能够看到实际效果,也就是所谓的(热更新)

什么是vite?— 新一代前端构建工具。

  • 优势如下:
  • 开发环境中,无需打包操作,可快速的冷启动。
  • 轻量快速的热重载(HMR)。
  • 真正的按需编译,不再等待整个应用编译完成。
  • 传统构建 与 vite构建对比图

兼容性注意

  • Vite 需要 Node.js 版本 18+,20+。然而,有些模板需要依赖更高的 Node 版本才能正常运行,当你的包管理器发出警告时,请注意升级你的 Node 版本
  • 官网:https://cn.vitejs.dev/

创建工程

  • 不指定名字创建:npm create vite@latest

    • 配置npm镜像站:npm config set registry https://registry.npmmirror.com
    • 查看镜像站:npm config get registry
  • 指定名字创建

    • # 创建项目方式一
      npm create vite@latest
      # 创建项目方式二:指定名字
      npm create vite@latest vue3_demo002
      # 创建项目方式三
      cnpm create vite@latest vue3_demo002
      # 创建项目方式四
      cnpm create vite vue3_demo002
      
  • 使用编辑器打开vue项目

  • npm的配置

    • 在这里插入图片描述
  • 安装依赖

    npm install

  • 运行项目

    npm run dev

【 2 】main.js文件

  • vue2中我们可以使用pototype(原型)的形式去进行操作,引入的是构造函数

  • import Vue from 'vue'
    import App from './App.vue'
    
    Vue.config.productionTip = false
    
    new Vue({
      render: h => h(App),
    }).$mount('#app')
    
  • vue3中需要使用结构的形式进行操作,引入的是工厂函数

    • import { createApp } from 'vue'
      import App from './App.vue'
      
      createApp(App).mount('#app')
      
  • vue3app组件中可以没有根标签

  • <template>
    	<!-- Vue3组件中的模板结构可以没有根标签 -->
    	<img alt="Vue logo" src="./assets/logo.png">
    	<HelloWorld msg="Welcome to Your Vue.js App"/>
    </template>
    

【 3 】API风格

API 风格

​ Vue 的组件可以按两种不同的风格书写:选项式 API组合式 API

选项式 API (Options API)

​ 使用选项式 API,我们可以用包含多个选项的对象来描述组件的逻辑,例如 datamethodsmounted。选项所定义的属性都会暴露在函数内部的 this 上,它会指向当前的组件实例。

<script>
export default {
  // data() 返回的属性将会成为响应式的状态
  // 并且暴露在 `this` 上 
  data() {
    return {
      count: 0
    }
  },

  // methods 是一些用来更改状态与触发更新的函数
  // 它们可以在模板中作为事件处理器绑定
  methods: {
    increment() {
      this.count++
    }
  },

  // 生命周期钩子会在组件生命周期的各个不同阶段被调用
  // 例如这个函数就会在组件挂载完成后被调用
  mounted() {
    console.log(`The initial count is ${this.count}.`)
  }
}
</script>

<template>
  <button @click="increment">Count is: {{ count }}</button>
</template>

​ 通过组合式 API,我们可以使用导入的 API 函数来描述组件逻辑。在单文件组件中,组合式 API 通常会与 `` 搭配使用。这个 setup attribute 是一个标识,告诉 Vue 需要在编译时进行一些处理,让我们可以更简洁地使用组合式 API。比如,<script setup> 中的导入和顶层变量/函数都能够在模板中直接使用。

​ 下面是使用了组合式 API 与 <script setup> 改造后和上面的模板完全一样的组件:

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

// 响应式状态
const count = ref(0)

// 用来修改状态、触发更新的函数
function increment() {
  count.value++
}

// 生命周期钩子
onMounted(() => {
  console.log(`The initial count is ${count.value}.`)
})
</script>

<template>
  <button @click="increment">Count is: {{ count }}</button>
</template>

【 4 】箭头函数

  1. 匿名函数: 使用function关键字定义的普通匿名函数。

    var f = function(name) {
        console.log(name);
    };
    f('jing');
    
  2. 无参数无返回值的箭头函数:

    var f1 = () => {
        console.log('这个就是箭头函数');
    };
    f1();
    
  3. 有多个参数无返回值的箭头函数:

    var f2 = (name, age) => {
        console.log(name, age);
    };
    f2();
    
  4. 有一个参数无返回值的箭头函数:

    var f3 = name => {
        console.log(name);
    };
    f3('jingyexiao');
    
    var f3 = () => {
    
    };
    f3();
    
  5. 有一个参数,一个返回值的箭头函数:

    var f4 = name => {
        return name + '_nb';
    };
    f4('jianshu');
    

    这个可以简写成:

    var f5 = name => name + '_nb';
    var res = f5('jianshu');
    console.log(res);
    
  6. 箭头函数内部的this 箭头函数内部没有自己的this,会继承外层作用域的this

// 在全局作用域下定义一个对象
const obj = {
  name: 'Alice',
  getNameRegular: function() {
    return this.name; // 正常函数中的this指向当前对象obj
  },
  getNameArrow: () => {
    return this.name; // 箭头函数中的this继承自外层作用域,在这里指向全局作用域的this(通常是window对象)
  }
};

console.log(obj.getNameRegular()); // 输出: "Alice",正常函数中的this指向obj对象
console.log(obj.getNameArrow()); // 输出: undefined,箭头函数继承外层作用域的this,在全局作用域中找不到name属性,返回undefined

如果在外部写一个let name = 'yun'

结果就会输出console.log(obj.getNameRegular()); // 输出: "Alice",正常函数中的this指向obj对象
console.log(obj.getNameArrow()); // 输出: yun,

总结

原始的函数声明方式:

var f = function(name) {
    console.log(name);
};
f('jing');

使用箭头函数:

这里function= =>

var f3 = (name) => {
    console.log(name);
};
f3('jing');
let f=()=>{}

【 5 】响应式

  • 可以说响应式系统能够保持数据和视图之间的同步,从而实现数据变化的自动渲染。
【 1 】什么是响应式

​ 响应式是指数据在变化时,可以自动同步更新视图和逻辑之间的状态。在前端框架(如Vue.js)中,响应式系统使得数据的变化会自动触发视图的更新,从而保持数据和界面的一致。

具体来说:

  • 数据绑定:响应式数据可以绑定到模板中的HTML元素。当数据变化时,相关的HTML元素会自动更新以反映最新的状态。这就是所谓的视图更新。
  • 双向绑定:前端框架通常提供双向绑定机制,让数据的变化能够自动反映到界面上,而用户在界面上输入或修改数据时,也会自动更新数据。这是响应式的一部分。
  • 监控数据变化:响应式系统通过监控数据的变化(通常是通过访问或设置对象属性),在数据发生改变时触发相应的更新操作。这些更新可以是界面上的元素、其他数据、或者是逻辑处理。

​ 因此,可以说响应式系统能够保持数据和视图之间的同步,从而实现数据变化的自动渲染。

【 2 】vue3的响应式原理
  • Vue 的响应式系统设计思路

​ 虽然 Vue 2 与 Vue 3 实现响应式系统的方式不同,但是他们的核心思想还是一致的,都是通过 发布-订阅模式 来实现(因为发布者和观察者之间多了一个 dependence 依赖收集者,与传统观察者模式不同)。

个人理解,观察者模式发布-订阅模式 都是 消息传递的一种实现方式,用来实现 对象间的通信(消息传递),只是发布订阅模式可以看做是观察者模式的 升级版,避免了 被观察对象与观察者之间的直接联系

​ 观察者模式:一个被观察对象对应多个观察者,两者直接联系;被观察这改变时直接向所有观察者发送消息(调用观察者的更新方法)

  • Vue 3 的响应式实现

​ 碍于 Object.defineProperty 的局限性,Vue 3 采用了全新的 Proxy 对象来实现整个响应式系统基础。

  • 什么是 Object.defineProperty

Object.defineProperty 是 JavaScript 中用于在对象上定义或修改属性的方法。它可以让你对对象的属性进行精确的控制,包括可写性、可枚举性、可配置性等。Object.defineProperty 提供了一种更详细和灵活的方式来控制对象属性的行为,而不仅仅是简单地赋值。

基本用法:

const person = {};

// 使用 Object.defineProperty 定义一个属性
Object.defineProperty(person, 'name', {
  value: 'John',
  writable: false, // 该属性是否可写
  enumerable: true, // 该属性是否可枚举
  configurable: false // 该属性是否可重新定义或删除
});

console.log(person.name); // 输出 "John"

// 尝试修改属性值
person.name = 'Jane';
console.log(person.name); // 仍然输出 "John",因为 writable 设置为 false

// 尝试删除属性
delete person.name;
console.log(person.name); // 仍然输出 "John",因为 configurable 设置为 false

通过 Object.defineProperty,你可以设置以下属性选项:

  • value: 属性的初始值。
  • writable: 如果设置为 true,则该属性可以被修改;否则不可修改。
  • enumerable: 如果设置为 true,则该属性可以在循环遍历中显示;否则不会显示在循环中。
  • configurable: 如果设置为 true,则该属性可以被删除或更改其特性;否则不可更改。

​ Vue 2 使用 Object.defineProperty 来实现响应式系统。它通过为对象的每个属性设置 getter 和 setter,以检测和响应属性的变化。这样,当你更改某个属性时,Vue 2 的响应式系统就可以检测到,并触发相关的更新。

  • 什么是 Proxy

ProxyES6 新增的一个构造函数,用来创建一个 目标对象的代理对象,拦截对原对象的所有操作;用户可以通过注册相应的拦截方法来实现对象操作时的自定义行为

​ 目前 Proxy 支持的拦截方法包含一下内容:

  • get(target, propKey, receiver):拦截对象属性的读取操作;
  • set(target, propKey, value, receiver):拦截对象属性的赋值操作;
  • apply(target, thisArg, argArray):拦截函数的调用操作;
  • construct(target, argArray, newTarget):拦截对象的实例化操作;
  • has(target, propKey):拦截 in 操作符;
  • deleteProperty(target, propKey):拦截 delete 操作符;
  • defineProperty(target, propKey, propDesc):拦截 Object.defineProperty 方法;
  • getOwnPropertyDescriptor(target, propKey):拦截 Object.getOwnPropertyDescriptor 方法;
  • getPrototypeOf(target):拦截 Object.getPrototypeOf 方法;
  • setPrototypeOf(target, proto):拦截 Object.setPrototypeOf 方法;
  • isExtensible(target):拦截 Object.isExtensible 方法;
  • preventExtensions(target):拦截 Object.preventExtensions 方法;
  • enumerate(target):拦截 for...in 循环;
  • ownKeys(target):拦截 Object.getOwnPropertyNamesObject.getOwnPropertySymbolsObject.keysJSON.stringify 方法。

我们基本上用上的就是set、get这两种方法

  • Vue3跟Vue2的响应式的区别

  1. Proxy 替代 Object.defineProperty:
    • 在 Vue 2 中,使用了 Object.defineProperty 来劫持对象的属性,实现响应式。
    • 而在 Vue 3 中,利用了 JavaScript 的 Proxy 对象来完成相同的任务。Proxy 提供了更强大和灵活的拦截能力,相较于 Object.defineProperty,Proxy 更容易追踪对象的变化。
  2. 性能优化:
    • Vue 3 在响应式系统的内部做了很多性能优化,包括更好的缓存策略和剪枝优化,以提高大型应用程序的性能表现。
    • 由于 Proxy 的使用,Vue 3 的响应式系统在某些情况下可能比 Vue 2 更快。
  3. Composition API:
    • Vue 3 引入了 Composition API,它提供了一种新的组织组件代码的方式。与 Vue 2 的选项 API 相比,Composition API 允许更灵活地组合和重用逻辑,同时也更容易测试和维护。
  4. Tree-shaking 支持:
    • Vue 3 的响应式系统被设计成更容易进行 tree-shaking,使得在构建时能更有效地剔除未使用的代码,减小应用程序的体积。

​ 总的来说,Vue 3 的响应式实现相较于 Vue 2 在性能、灵活性和易用性上都有所提升,这些改进使得 Vue 3 更适合构建大型和高性能的应用程序。

总结:

'''
vue2 用data中定义在用this响应出来
vue3就是用setup 中使用  导入	import {ref,reactive} from "vue"; 用let name = ref('JIng');或者是recative

'''

悟吧!!!

【 6 】ref跟reactive

  • ref 包裹值类型[数字,字符串,布尔],做成响应式

  • reactive包裹引用类型[对象,数组],做成响应式

  • 使用reactive包裹的对象,直接通过 . [] 取值赋值就是响应式的

    • ref包裹的对象,需要使用 对象.value 修改值
  • 使用ref包裹的,在template中,不许用使用 变量.value

【 1 】ref与reactive区别
  • ref定义的是基本数据类型

  • ref通过Object.defineProperty()的get和set实现数据劫持

  • ref操作数据.value,读取时不需要。value

  • reactive定义对象或数组数据类型

  • reactive通过Proxy实现数据劫持

  • reactive操作和读取数据不需要.value

【 2 】两者的使用方法
<script>
import { reactive } from "vue";

export default {
  setup() {
    const state = reactive({
      name: 'Jing',
      age: 25,
      email: '[email protected]'
    });

    return {
      state
    };
  }
};
</script>
<script>
import { ref } from "vue";

export default {
  setup() {
    // 使用ref函数创建一个响应式引用
    const name = ref('Jing');

    // 将响应式引用返回,使其在模板中可用
    return {
      name
    };
  }
};
</script>

【 7 】setup函数

  1. setup函数必须要return返回出去

  2. setup为Vue3.0中一个新的配置项,值为一个函数

  3. setup是所有Composition API(组合API)编写的位置

  4. 组件中所用到的:数据、方法等等,均要配置在setup中

  5. setup函数的返回值:返回一个对象,对象中的属性、方法, 在模板中均可以直接使用

  6. 注意:

    尽量不要与Vue2.x配置混用

    • Vue2.x配置(data、methos、computed…)中可以访问到setup中的属性、方法。

    • 但在setup中不能访问到Vue2.x配置(data、methos、computed…)。

    • 如果有重名, setup优先。

    • ref的使用方法

<template>
  <div class="about">
    <h1>姓名:{{ name }}</h1>
    <h1>年龄:{{ age }}</h1>
    <button @click="handadd">点击加年龄</button>
    <button @click="handname">点击田女士</button>
  </div>
</template>


<script>
import {ref,reactive} from "vue";

export default {
  name: 'AboutView',
  setup() {
    let name = ref('JIng');
    let age = ref(26);

    const handadd = () => {
      age.value++;
    };
    const handname = () => {
      name.value = '你好我好大家好!!!';
    };
    return {
      name,
      age,
      handadd,
      handname
    };

  }


}

</script>

image-20240507170603634

  • recative的使用方法

    • 注意就是返回的响应格式跟渲染方法

      return {
            rec,
            handadd,
            handname
          };
      
    • <h1>姓名:{{ rec.name }}</h1>
      <h1>年龄:{{ rec.age }}</h1>
      
<template>
  <div class="about">
    <h1>姓名:{{ rec.name }}</h1>
    <h1>年龄:{{ rec.age }}</h1>
    <button @click="handadd">点击加年龄</button>
    <button @click="handname">点击修改姓名</button>
  </div>
</template>

<script>
import { reactive } from "vue";

export default {
  name: 'AboutView',
  setup() {
    // 使用reactive创建包含姓名和年龄的响应式对象
    const rec = reactive({
      name: 'Jing', // 直接赋值
      age: 25 // 直接赋值
    });

    // 定义增加年龄的方法
    const handadd = () => {
      console.log(rec.name);
      console.log(rec.age);
      rec.age++; // 递增年龄
      console.log(rec.age); // 打印递增后的年龄
    };

    // 定义修改姓名的方法
    const handname = () => {
      rec.name = '你好我好大家好!!!'; // 修改姓名
    };

    // 将响应式对象和方法返回,使其在模板中可用
    return {
      rec,
      handadd,
      handname
    };
  }
}
</script>

在这里插入图片描述

【 8 】计算属性

  • 缓存: 计算属性默认是有缓存的,只有当依赖的响应式属性发生改变时,它们才会重新计算。这样可以避免不必要的重复计算,提高性能。
  • 响应式: 计算属性会自动响应其依赖的响应式属性的变化,当依赖的属性发生改变时,计算属性会重新计算其值。

计算属性中重要的就是它的缓存机制

vue中的计算属性的好处就是我比如在设置了一个input标签里写了计算属性之后 别的组件发生改变我的input标签也不会发生改变

<template>
  <div>
    <h2>购物车</h2>
    <ul>
      <li v-for="(item, index) in cart" :key="index">
        {{ item.name }} - 单价: {{ item.price }}元 - 数量: {{ item.quantity }}
      </li>
    </ul>
    <p>总价格: {{ total }}</p>
    <button @click="addItem">添加商品</button>
  </div>
</template>

<script>
import { reactive, computed } from 'vue';

export default {
  setup() {
    const cart = reactive([
      {name: '商品1', price: 10, quantity: 2},
      {name: '商品2', price: 20, quantity: 1},
      {name: '商品3', price: 30, quantity: 3}
    ]);

    // 计算总价格的计算属性
    const total = computed(() => {
      console.log('重新计算总价格');
      let totalPrice = 0;
      cart.forEach(item => {
        totalPrice += item.price * item.quantity;
      });
      return totalPrice;
    });

    // 添加商品的方法
    const addItem = () => {
      cart.push({name: '新商品', price: 50, quantity: 1});
    };

    return {
      cart,
      total,
      addItem
    };
  }
};
</script>

image-20240507190357084

【 9 】监听属性

  1. 监听普通属性变化:
    • setup 函数中,使用 reactive 创建一个响应式对象,例如:const rec = reactive({ age: 266 })
    • 使用 watch 函数监听该普通属性的变化,例如:watch(() => rec.age, (newValue, oldValue) => { /* 处理变化 */ })
    • 在监听函数中,可以访问新旧值来执行相应的操作。
  2. 监听对象属性变化:
    • 使用 refreactive 来创建一个包含对象的响应式引用或响应式对象,例如:const person = ref({ name: "jing", age: 25 })const person = reactive({ name: "jing", age: 25 })
    • 在监听对象属性变化时,确保使用 person.value 来访问对象的属性,例如:watch(() => person.value.name, (newValue, oldValue) => { /* 处理变化 */ })
    • 监听函数将在对象属性的值变化时被调用。
  3. 监听多个属性变化:
    • setup 函数中,创建一个包含多个属性的响应式对象,例如:const res = reactive({ sum: 250, msg: "你很好!!" })
    • 使用 watch 函数来同时监听多个属性的变化,例如:watch([() => res.sum, () => res.msg], ([newSum, newMsg], [oldSum, oldMsg]) => { /* 处理变化 */ })
    • 监听函数将在任一被监听属性的值变化时被调用,传递新旧值作为参数。
  • 原始的写法

<template>
  <div>
    <!-- 显示普通属性的值 -->
    <p>年龄:{{ rec.age }}</p>

    <button @click="handadd">点击加年龄</button>

    <!-- 显示对象属性的值 -->
    <p>姓名:{{ person.name }}</p>
    <button @click="handname">点我</button>
    <!-- 显示多个属性的值 -->
    <p>总和:{{ res.sum }}, 消息:{{ res.msg }}</p>
    <button @click="handsum">点我</button>
  </div>

</template>


<script>
import { ref, reactive, watch } from "vue";

export default {
  name: "JianView",
  setup() {
    // 监听普通属性
    const rec = reactive({
      age: 266,
    });

    const handadd = () => {
      console.log(rec.age);
      rec.age++; // 递增年龄
      console.log(rec.age); // 打印递增后的年龄
    };

    // 监听 rec.age 的变化
    watch(() => rec.age, (newValue, oldValue) => {
      console.log('age这个值变化了', newValue, oldValue);
    });

    // 监听对象属性
    const person = ref({
      name: "jing",
      age: 25,
    });

    const handname = () => {
      console.log(person.value.name);
      person.value.name = '云';
      console.log(person.value.name);
    };

    watch( () =>person.value.name, (newValue, oldValue) => {
      console.log('注意观察person.value.name变化了', newValue,oldValue);
    });



    //监听多个属性
    const res = reactive({
      sum: 250,
      msg: "你很好!!"
    });

    const handsum = () => {
      console.log(res.sum);
      console.log(res.msg);
      res.sum = 2555; // 递增年龄
      res.msg = '九日'; // 递增年龄
      console.log(res.sum); // 打印递增后的年龄
      console.log(res.msg);
    };

    watch([() => res.sum, () => res.msg], ([newSum, newMsg], [oldSum, oldMsg]) =>  {
      console.log("sum或者msg变化了", newSum, newMsg,oldMsg,oldSum);
    });

    return {
      rec,
      person,
      res,
      handadd,
      handname,
      handsum
    }
  }
}
</script>

<style>

</style>

在这里插入图片描述

image-20240507202952501

  • watchEffect方法

watch 不同,watchEffect 没有明确的监听目标,而是会自动追踪其内部使用的所有响应式变量,这使得它在处理一些复杂场景时非常方便。

export default {
  name: "JianView",
  setup() {
    // 监听普通属性
    const rec = reactive({
      age: 266,
    });

    const handadd = () => {
      console.log(rec.age);
      rec.age++; // 递增年龄
      console.log(rec.age); // 打印递增后的年龄
    };

    // 使用 watchEffect 监听 rec.age 的变化
    watchEffect(() => {
      console.log('age 这个值变化了', rec.age);
    });

    // 监听对象属性
    const person = ref({
      name: "jing",
      age: 25,
    });

    const handname = () => {
      console.log(person.value.name);
      person.value.name = '云';
      console.log(person.value.name);
    };

    // 使用 watchEffect 监听 person.value.name 的变化
    watchEffect(() => {
      console.log('注意观察 person.value.name 变化了', person.value.name);
    });

    //监听多个属性
    const res = reactive({
      sum: 250,
      msg: "你很好!!"
    });

    const handsum = () => {
      console.log(res.sum);
      console.log(res.msg);
      res.sum = 2555; // 递增年龄
      res.msg = '九日'; // 递增年龄
      console.log(res.sum); // 打印递增后的年龄
      console.log(res.msg);
    };

    // 使用 watchEffect 监听 res.sum 和 res.msg 的变化
    watchEffect(() => {
      console.log("sum 或者 msg 变化了", res.sum, res.msg);
    });

    return {
      rec,
      person,
      res,
      handadd,
      handname,
      handsum
    };
  }
};

image-20240507203607615

【 10 】生命周期

  • vue2中我们是通过new Vue(),在执行beforeCreate与created接着问你有没有vm.$mount(el)
  • 区别:beforeCreate与created并没有组合式API中,setup就相当于这两个生命周期函数

image-20240507192128297

vue2           ------->      vue3
 
beforeCreate   -------->      setup(()=>{})
created        -------->      setup(()=>{})
beforeMount    -------->      onBeforeMount(()=>{})
mounted        -------->      onMounted(()=>{})
beforeUpdate   -------->      onBeforeUpdate(()=>{})
updated        -------->      onUpdated(()=>{})
beforeDestroy  -------->      onBeforeUnmount(()=>{})
destroyed      -------->      onUnmounted(()=>{})
activated      -------->      onActivated(()=>{})
deactivated    -------->      onDeactivated(()=>{})
errorCaptured  -------->      onErrorCaptured(()=>{})

总结: Vue2和Vue3钩子变化不大,beforeCreate 、created 两个钩子被setup()钩子来替代。

<template>
  <div class="home">
    <h1>生命周期</h1>
    <h3>年龄是:{{ age }}</h3>
    <button @click="addAge">点击age+1</button>


  </div>
</template>

<script>

import {ref, reactive, watch, watchEffect,onBeforeMount,onMounted,onBeforeUpdate,onUpdated,onBeforeUnmount,onUnmounted} from 'vue'

export default {
  name: 'HomeView',
  setup() {
    // 生命周期钩子
    // 1 写在这里是就是beforeCreate
    console.log('beforeCreate')

    const age=ref(26)
    function addAge(){
      age.value++
    }

    //2 写在这里是就是created
    console.log('created',age.value)

    //3 beforeMount-->onBeforeMount
    // onBeforeMount,onMounted,onBeforeUpdate,onUpdated,onBeforeUnmount,onUnmounted
    onBeforeMount(()=>{
      console.log('onBeforeMount','组件挂载前')
    })
    //4 mounted-->onMounted
    onMounted(()=>{
      console.log('onMounted','组件挂载后')
    })
    //5 beforeUpdate-->onBeforeUpdate
    onBeforeUpdate(()=>{
      console.log('onBeforeUpdate','更新之前')
    })
    //6 updated-->onUpdated
    onUpdated(()=>{
      console.log('onUpdated','更新之后')
      console.log(age.value)
    })

    //7 beforeUnmount-->onBeforeUnmount
    onBeforeUnmount(()=>{
      console.log('onBeforeUnmount','销毁之前')
    })

    //8 unmounted-->onUnmounted
    onUnmounted(()=>{
      console.log('onUnmounted','销毁后')
    })

    return {age,addAge}

  },



}
</script>

image-20240507192522354

【 11 】toRef

  • 作用:创建一个 ref 对象,其value值指向另一个对象中的某个属性。
  • 语法:const name = toRef(person,'name')
  • 应用: 要将响应式对象中的某个属性单独提供给外部使用时。
  • 扩展:toRefstoRef功能一致,但可以批量创建多个 ref 对象,语法:toRefs(person)

toRef是将原始对象中的指定属性创建为一个新的 ref 对象。这个 ref 对象会保持响应性,即当原始对象的属性发生变化时,这个 ref 对象的值也会相应地更新。

  • 基本使用

就是要先定义一个响应对象

import { reactive, toRef } from 'vue';
const person = reactive({
  name: 'Alice',
  age: 30,
});

在使用toRef 创建一个指向 person.name 的 ref 对象

const nameRef = toRef(person, 'name');

​ 现在,你可以在其他组件或函数中使用 nameRef当 person.name 变化时,nameRef 的值也会随之更新。

具体示例

  • toRef的使用方法

  • import { ref,reactive,toRef } from "vue";  
    ...
    const nameRef = toRef(rec,"name");
    
<template>
  <div class="about">
    <h1>姓名:{{ rec.name }}</h1>
    <button @click="handadd">更改年龄</button>
    <br>
    <hr>
</template>

<script>
import { ref,reactive,toRef } from "vue";

export default {
  name: 'AboutView',
  setup() {
    // 使用reactive创建包含姓名和年龄的响应式对象
    const rec = reactive({
      name: 'Jing', // 直接赋值
      age: 25 // 直接赋值
    });

    const nameRef = toRef(rec,"name");


    const handadd = () => {
      console.log(rec.name);
      console.log(nameRef.value);
      nameRef.value = '宠物小精灵!!!';
      console.log(nameRef.value);
    };





    // 将响应式对象和方法返回,使其在模板中可用
    return {
      rec,
      handadd,

    };
  }
}
</script>

image-20240507212620565

  • toRefs的使用方法

    import { ref,reactive,toRefs } from "vue"; 
    
    ...
    const {name,age} = toRefs(rec);
    
<template>
  <div class="about">
    <h1>姓名:{{ rec.name }}</h1>
    <button @click="handadd">更改年龄</button>
    <br>
    <hr>
    <h1>年龄:{{ rec.age }}</h1>
    <button @click="handage">修改年龄</button>
  </div>
</template>

<script>
import { ref,reactive,toRefs } from "vue";

export default {
  name: 'AboutView',
  setup() {
    // 使用reactive创建包含姓名和年龄的响应式对象
    const rec = reactive({
      name: 'Jing', // 直接赋值
      age: 25 // 直接赋值
    });

    // 使用toRefs创建对rec的引用对象
    const {name,age} = toRefs(rec);


    const handadd = () => {
      console.log(rec.name);
      console.log(name.value);
      name.value = '宠物小精灵!!!';
      console.log(name.value);
    };

    const handage = () => {
      console.log(age.value);
      age.value = 266;
      console.log(age.value);
    };





    // 将响应式对象和方法返回,使其在模板中可用
    return {
      rec,
      handadd,
      handage

    };
  }
}
</script>

image-20240507212452517

;