vue3.0学习笔记

1.快速开始

  1. 通过脚手架vite创建vue项目
npm init vite-app hello-vue3
cd hello-vue3
npm install
npm run dev
  1. 通过vue-cli创建vue3.0项目(略)

2. 入口文件main的区别

vue3.0

// 引入的不再是vue的构造函数了,而是名为createApp的工厂函数*

// createApp 里面的方法比vue2.0中引入的Vue构造函数少,相比起来会更加“轻”

import { createApp } from 'vue'

import App from './App.vue'


*// createApp(App)创建实例对象,mount将对象挂载到页面*

createApp(App).mount('#app')

3.vue3.0的新特性

1. 拉开序幕的setup
  • 理解:是一个新的配置项,是一个函数

  • 组件中所有的数据,方法等均要配置到setup中

  • setup函数有两种返回值

    • 返回一个对象,对象中的属性和方法均可在模板中访问到

    • 还可以返回一个渲染函数,则可自定义渲染内容

       <h1>我是</h1>
      
      //导入渲染函数
      import { h } from 'vue'
      // 返回
      return () => h('h1', '2021928')
      

      输出

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4pkAkJ8w-1635500034724)(C:\Users\Fxl\AppData\Roaming\Typora\typora-user-images\image-20210928115440349.png)]

​ 注意点:

  1. vue3虽然可以兼容vue2的语法,但是尽量不要混用

    在vue2的data, methods中可以访问到setup的属性和方法

    但是setup中不能访问到vue2的配置

      2. 执行时机: 在beforeCreate之前执行
    
      3. 参数:
    

    props: 值为对象,包含组件外部传递过来且在组件内部声明了的属性

    ​ props: [‘msg’, ‘sex’],

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ESefYVeE-1635500034727)(C:\Users\Fxl\AppData\Roaming\Typora\typora-user-images\image-20210928174002905.png)]

    context: 上下文对象

    ​ attrs:值为对象,包含外部传递过来但是没在内部props配置中声明的属性

    ​ slots: 收到的插槽内容,vue3中使用v-slot

    ​ emit: 分发自定义事件的函数

2. 响应式ref函数

因为在vue2中数据放在data函数内,使用数据劫持对数据进行了响应,但是在vue3中使用setup函数中直接声明数据,没有响应式,于是就诞生了ref函数,要将一个数据变成响应式数据

语法: const xxx = ref(数据)

ref会创建包含响应式的一个引用对象,将数据值放在对象的value内,在取值时使用 xxx.value,

在模板中使用时直接

{{xxx}}
就可以

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Anq6CQJ5-1635500034731)(C:\Users\Fxl\AppData\Roaming\Typora\typora-user-images\image-20210928140904168.png)]

备注:


  • 接收的数据可以是基本类型也可以是引用类型
  • 对于基本类型数据,响应依旧是靠Object.defineProperty()的set与get来实现的
  • 对于引用类型的数据,内部求助了一个新函数reactive函数
3. reactive 函数
  • 作用: 定义一个对象类型的响应式数据,基本类型不能使用reactive
  • 语法:接受一个对象或者数组,返回一个proxy代理对象

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P4EE6QrL-1635500034737)(C:\Users\Fxl\AppData\Roaming\Typora\typora-user-images\image-20210928143742164.png)]

  • reactive定义的对象是深层次的
  • 内部基于ES6的proxy实现
4. vue3.0中的响应式原理
vue2的响应式原理:

对象类型: 通过object.defineProperty()对属性的读取,修改进行拦截

数组类型: 通过重写更新数组的一系列方法进行拦截

存在的问题:

  • 只能监听到数据的修改与读取,当对象里增加,删除属性时页面不能更改,可以使用$set(对象,属性,值), $delete(对象,属性)的方式增加和删除数据
  • 直接通过数组下表修改数组,页面不会自动更新
vue3的响应式

通过Proxy: 拦截对象中的任意属性变化,包括: 属性值的读写,属性的添加,属性的删除等

let person = {
        name: "张三",
        age:32
      }
      // 模拟vue3中实现响应式
      const p = new Proxy(person, {
        // 当用户获取某个属性时触发
        get(target, propName) {
          console.log(`有人读取了p身上的${propName}属性`);
          // target是原对象,p是通过proxy代理的对象,propName是读取的属性名,因为propName是变量所以只能使用target[propName]来读取
          return target[propName]
        },
        // 当用户修改或者新增属性时触发
        set(target, propName, value) {
          console.log(`有人修改了p身上的${propName}属性`);
          // target是原对象,p是通过proxy代理的对象,propName是读取的属性名,因为propName是变量所以只能使用target[propName]来读取
          target[propName] = value
        },
        // 当有人删除属性时触发
        deleteProperty(target, propName) {
          console.log(`有人删除了p身上的${propName}属性`);
          return delete target[propName]
        }
      })

通过Reflect(反射): 对源对象的属性进行操作

let person = {
        name: "张三",
        age:32
      }
      // 模拟vue3中实现响应式
      const p = new Proxy(person, {
        // 当用户获取某个属性时触发
        get(target, propName) {
          console.log(`有人读取了p身上的${propName}属性`);
          // target是原对象,p是通过proxy代理的对象,propName是读取的属性名,因为propName是变量所以只能使用target[propName]来读取
          return Reflect.get(target, propName)
        },
        // 当用户修改或者新增属性时触发
        set(target, propName, value) {
          console.log(`有人修改了p身上的${propName}属性`);
          // target是原对象,p是通过proxy代理的对象,propName是读取的属性名,因为propName是变量所以只能使用target[propName]来读取
          return Reflect.set(target, propName, value)
        },
        // 当有人删除属性时触发
        deleteProperty(target, propName) {
          console.log(`有人删除了p身上的${propName}属性`);
          return Reflect.defineProperty(target, prop)
        }
      })

4.计算属性

vue3.0的计算属性与vue2.0的计算属性一致,但是在vue3内需要引入

计算属性设计的初衷就是为了避免在模板中进行复杂计算,所以,对于任何包含响应式数据的复杂逻辑,都应该使用计算属性

计算属性的 Setter

计算属性默认只有 getter,不过在需要时你也可以提供一个 setter:

import { computed } from 'vue'
// ...
 setup() {
     let person = reactive({
         firstName:'张'+ ' ',
         lastName:'三',
     })
     // let fullName = computed(
     //   () => {
     //     return person.firstName + person.lastName
     //   }
     // )

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


     // 返回一个对象
     return {
         person
    }

现在再运行 vm.fullName = 'John Doe' 时,setter 会被调用,vm.firstNamevm.lastName 也会相应地被更新

5.监听器

当数据变化时执行异步或者开销较大的操作是,就要使用watch, watch有三个参数第一个参数是要监听的属性,第二个是数据变化是的回调函数,第三个为配置文件

<h2>当前求和为: {{sum}}</h2><button @click="add">点我加1</button><div>{{person.name}}</div><div @click="addAge">{{person.age}}</div><input type="text" v-model="person.job.j1.salary">

<script>  import { ref, watch, reactive } from 'vue'export default {  name: 'HelloWorld',  setup() {    let sum = ref(1)    let sum2 = ref(3)    let person = reactive({      name: '张三',      age: 21,      job: {        j1: {          salary: 20        }      }    })    function add() {      sum.value += 1    }     function add1() {      sum2.value += 1    }    //1. 监听一个响应式数据的时候    watch(sum,(newValue,oldValue) => {      console.log('sum变化了', newValue,oldValue);    }    ,{      immediate:true    })     // 2. watch还可以监听多个响应式数据,当监听的任意一个数据变化时都会监听到并且执行回调函数      watch([sum, sum2],(newValue,oleValue) => {         console.log('sum变化了', newValue,oleValue);      })    /*      3.监听reactive所定义的一个响应式对象的全部属性,      注意:这里无法获取到oldvalue,强制开启了深度监听    */    watch(person, (newvalue, oldvalue)=>{      console.log("person变化了", newvalue, oldvalue);    })    /*      4. 监听reactive所定义的一个响应式对象里面的某一个属性,只能定义一个函数将对象里的属性返回出去    */     watch(()=>person.age, (newvalue, oldvalue)=>{      console.log("person的age变化了", newvalue, oldvalue);    })    /*      5. ractive所定义的一个响应式对象里面的一些属性    */     watch([()=>person.age, ()=> person.name], (newvalue, oldvalue)=>{      console.log("person的age变化了", newvalue, oldvalue);    })    //6. 特殊情况    //当见识的是reactive定义的对象中的某个属性时且该值为对象时,deep配置是有效的    // 当改变了job里面j1里面的salary并不能监听到变化,只有配置deep:true    watch([()=>person.job, ()=> person.name], (newvalue, oldvalue)=>{      console.log("person的age变化了", newvalue, oldvalue);    },{deep:true})    // 返回一个对象    return {      add,      sum,      add1,      sum2,      person,      addAge    }      },</script>

6.watchEeffct函数

watchEffect的套路是,不用指明监视哪个属性,监视的回调中用到哪个属性,就监视哪个属性

当person.count改变时,会重新运行watchEffect函数

watchEffect(()=>{   console.log(person.count,"count改变了");  })

7.生命周期

beforeCreate — created — beforeMount — mounted —beforeUpdate — updated—beforeUnmount — Unmounted

与vue2不同的是将beforeDestroy和destoried改成了beforeUnmount — Unmounted ,而且全部除了beforeCreate 和 created之外都可以在setup函数中使用,不过要改变名称,

选项式 API 的生命周期选项和组合式 API 之间的映射

  • beforeCreate -> 使用 setup()
  • created -> 使用 setup()
  • beforeMount -> onBeforeMount
  • mounted -> onMounted
  • beforeUpdate -> onBeforeUpdate
  • updated -> onUpdated
  • beforeUnmount -> onBeforeUnmount
  • unmounted -> onUnmounted

8.自定义hook函数

Vue3 的 hook函数 相当于 vue2 的 mixin, 不同在与 hooks 是函数,目的是让setup中的逻辑更清晰
Vue3 的 hook函数 可以帮助我们提高代码的复用性, 让我们能在不同的组件中都利用 hooks 函数
例子 :

首先在src目录下建立一个 hooks 文件夹
申明一个我们要复用的方法的名字.js 文件

下面是 useMousePosition.ts 代码,讲一个方法的逻辑封装到函数内,当使用时就直接引用该函数

import {onBeforeUnmount, onMounted, ref} from 'vueexport default function () {	const x = ref(-1) ; // x 绑定为响应式数据	const y = ref(-1);	const clickHandler=(event)=>{		x.value = event.pageX		y.value = event.pageY	} 	onMounted(()=>{		window.addEventListener('click', clickHandlker)	})	onBeforeUnmount(()=>{		window.removeEventListner('click', clickHandler)	})	return {		x,		y	}}

下面是 App.vue组件使用我们的 userMousePosition 这个 hooks 方法

<template><div>  <h2>x: {{x}}, y: {{y}}</h2></div></template><script>import {  ref} from "vue"/* 在组件中引入并使用自定义hook自定义hook的作用类似于vue2中的mixin技术自定义Hook的优势: 很清楚复用功能代码的来源, 更清楚易懂*/import useMousePosition from './hooks/useMousePosition'export default {  setup() {    const {x, y} = useMousePosition() // 这里就用了 hooks 函数, 从而提高了复用性    return {      x,      y,    }  }}</script>

9.toRef , toRefs

toRef作用就是将一个不是响应式的数据变成响应式,可以用来为源响应式对象上的某个 property 新创建一个 ref。然后,ref 可以被传递,它会保持对其源 property 的响应式连接。

toRefs可以将一个对象的多个属性变成响应式数据

初始代码

<div>    <h3>{{person.name}}</h3>    <h3>{{person.age}}</h3>    <h3>{{person.job.j1.salary}}</h3>    <button @click="changeName">修改名称</button>    <button @click="changeAge">修改年龄</button>    <button @click="changeSla">修改薪资</button>  </div>

将person返回出去,在template中需要使用person.name这样使用值

setup() {   let person = reactive({     name: '张三',     age: 20,     job: {       j1: {         salary: 30       }     }   })   function changeName() {     person.name += '~'   }   function changeAge() {     person.age += 1   }   function changeSla() {     person.job.j1.salary++   }    return {      person,      changeName,      changeAge,      changeSla    }  },

将person的某个属性返回出去(错误版本),虽然template里面可以直接使用name,age,但是这样相当于将字符串直接赋值给name,并不是响应式数据,这时候就要使用toRef函数

 return {      name: person.name,      age: person.age,      salary: person.job.j1.salary,      changeName,      changeAge,      changeSla    }

使用toRef将属性返回

   let name = toRef(person, 'name')   let age = toRef(person, 'age')   let salary = toRef(person.job.j1, 'salary')    return {      name,      age,      salary,      changeName,      changeAge,      changeSla    }

但是如果会返回很多个属性,使用toRef未免太复杂,这时候就可以使用toRefs, 而且如果想让对象里面的数据实现响应式的话就只能在toRefs之后才能对对象进行解构赋值,不然只能等到普通的数值并不是响应式数据

// 第一种方式,将某几个属性暴露let  {name, age, job} = toRefs(person)    return {      name,      age,      job,      changeName,      changeAge,      changeSla    }//第二种,将所有属性都暴露出去return {      ...toRefs(person),      changeName,      changeAge,      changeSla    }

​ 模板内使用:

<h3>{{name}}</h3><h3>{{age}}</h3><h3>{{job.j1.salary}}</h3>

10.不常用的api

shallowReactive 与shallowRef

按照字面意思来说就是浅层次的响应,shallowReactive声明的对象只能响应到第一层,如果对象里面的对象就无法响应,如下person里面job对象下的那些属性就无法响应。

let person = shallowReactive({     name: '张三',     age: 20,     job: {       j1: {         salary: 30       }     }   })

shallowRef与ref的区别是shallowRef只考虑基本数据类型的数据,但是ref如果传入的是对象的话,它会去使用reactive去处理传进来的对象,

什么时候用:

如果有一个对象数据,结构比较深,但变化只是外层属性变化就可以使用shallowReactive

如果有一个对象数据,后续功能不会修改该对象的属性,而是生成新的对象来替换

11.readonly 和shallowReadonly

readonly: 让一个响应式的数据变为只读的(深只读)

shallowReadonly: 让一个响应式的数据变为只读的(浅只读)

应用场景: 不希望数据被修改时使用

12. toRaw与markRaw

toRaw:

​ 作用: 将一个有reactive生成的响应式对象转为普通对象

​ 使用场景: 用于读取响应式对象对应的普通对象,对这个普通对象的所有操作不会影响页面更新

markRaw:

​ 作用:标记一个对象使其永远不会成为响应式对象

​ 使用场景:

​ 有些值不该被设置为响应式的,例如复杂的第三方类库等

​ 当渲染具有不可变数据源的大列表是,跳过响应式可以提高性能

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值