周亚博的个人博客

  • 首页
  • 盛夏光年
  • 陪风去荡
  • 布响丸啦
我频繁记录着 因为生活值得
  1. 首页
  2. 盛夏光年
  3. 正文

Vue3的基本使用

2022-10-09 91点热度 0人点赞 0条评论

一、数据劫持的实现

Vue2中使用的是Object.defineProperty,想要实现深层对象的响应式,必须使用递归,但是性能不好,所以使用了$set方法响应式添加属性

let obj1 = {
  a: 1,
  b: 2
}
let obj2 = {}

for (let item in obj1) {
  Object.defineProperty(obj2, item, {
    get() { return obj1[item] },
    set() { }
  })
}
console.log(obj2)       // obj2中有了obj1的属性,且是响应式的

但是Vue3中使用的是new Proxy实现响应式

let obj1 = {
  a: 1,
  b: 2
}
let obj2 = new Proxy(obj1, {
  get() {},
  set() {}
})
console.log(obj2)

二、常用组合式API

1、setup函数

什么是setup函数

  • setup是一个新的配置项,值是一个函数

  • 是所有组合式API表演的舞台

  • 组件中所用到的:数据、方法等都要配置在setup中
<!-- 写法一 Vue2+Vue3-->
<template>
  <h1>这是helloword组件</h1>
  {{name}}
</template>


<script>
export default {
  setup() {
    let name = '张三'
    return {
      name
    }
  }
}
</script>
<!-- 写法二 纯Vue3-->
<template>
  <h1>这是helloword组件</h1>
  {{name}}
</template>


<script setup>
let name = '张三'
</script>

<style scoped>
</style>

2、ref函数

什么是ref函数

vue3中直接定义数据let a = 1,数据是不可以修改的,只能展示在视图层

所以使用ref函数用于定义一个响应式数据

ref函数的使用

import { ref } from 'vue'
// 用法
const name = ref('张三')
- 创建一个包含响应式数据的引用对象(reference对象)
- 在js中读取数据:name.value
- 在模板中读取数据:直接name,不需要“点value”

备注:

  • 接收的数据可以是基本类型、也可以是对象类型
  • 基本类型数据:靠Object.defineProperty实现响应式
  • 对象数据类型:内部使用了Vue3的新函数——reactive函数(封装了proxy方法)
const obj = ref({ name: '张三' })
// 读取属性
console.log(obj.value)      // Proxy {name: '张三'}
// 只需要使用obj.value拿到代理对象,之后不再使用value获取

3、reactive函数

作用:定义一个对象类型的响应式数据

注意:基本数据类型使用的是ref函数实现响应式

使用方法

import { reactive } from 'vue'
// const 代理对象 =  reactive(原对象)
const obj = reactive({name:'张三'})
console.log(obj)        // Proxy {name: '张三'},是一个Proxy的实例对象
// 接收一个对象或者一个数组,返回的是代理对象,数据的修改可以被vue捕获到,是响应式的
  • reactive定义的响应式数据是深层次的
  • 都可以直接使用属性或者索引进行修改
  • 基于ES6的Proxy实现,通过代理对象操作原对象内部数据是响应式的

4、ref和reactive对比

定义数据的角度

  • ref定义基本类型数据,也可以定义对象/数组类型数据,内部通过reactive转换为代理对象
  • reactive定义对象或者数组类型数据

从原理角度

  • ref通过Object.defineProperty()的get和set来实现响应式(数据劫持)
  • reactive通过proxy实现响应式(数据劫持),并通过Reflect操作源对象中的数据

从使用角度

  • ref定义的数据:操作数据需要.value,模板中读取数据不需要.value
  • reactive定义的数据:操作与读取均不需要.value

5、toRef

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

错误用法

let { name, price } = reactive({
  name: '奔驰',
  price: 30
})
// 直接结构出来的可以展示到视图层,但是不是响应式的

正确用法

<template>
<h1>{{name}}{{price}}</h1>
</template>
<script setup>
  import { reactive,toRefs } from 'vue'
    let car = reactive({
    name: '奔驰',
    price: 30
  })
  // 通过toRefs或者toRef将属性提供给外部使用,而且是响应式的
  let { name, price } = toRefs( car )

  let name = toRef(car, 'name')
    let price = toRef(car, 'price')

  // 要通过 “点value” 进行修改
</script>

6、计算属性

vue3也支持vue2的写法(不建议)

vue3中的计算属性变成了一个组合式API

import { computed } from 'vue'
setup(){
  // 简写形式,没有考虑计算属性被修改的情况
  let name = computed(()=>{
    ...
    return xxx
  })

  // 完整写法
  let name = computed({
    get(){},
    set(){}
  })
}

6、watch监视

变成了一个组合式API,是一个函数

import { ref, reactive, watch } from 'vue'
setup(){
  /**
  * 监视ref定义的一个响应式数据
  */
  let sum = ref(0)
  let msg = ref('ok')
  watch(sum, (newVal, oldVal)=>{
    console.log('数据变化了')
  })
    // 与vue2不同,这里的watch是一种行为,而不是配置项。所以可以写多次
  // 如果ref定义了一个对象类型数据,需要监听obj.value

  /**
  * 监视多个响应式数据可以写到数组中
  */
  watch([sum, msg], (newVal, oldVal)=>{
    console.log(newVal)     // 结果是一个数组
  })

  /**
  * 可以有第三个参数(配置)
  */
  watch(sum, (newVal, oldVal)=>{
    console.log('数据变化了')
  },{immediate: true})


  /**
  * 监视reactive定义的一个响应式数据的全部属性
  */
  let person = reactive({
    name: '张三',
    age: 18
  })
  watch(person, (newVal, oldVal) => {
    console.log(newVal,oldVal)
  })
  /*
  存在问题:
  无法正常获取oldVal,变化后oldValue和newVal一样
  监听的是reactive定义的对象,默认强制开启了深度监视(deep配置无效)
  */

  /**
  * 监视reactive定义的一个响应式数据的某个属性
  */
  let person = reactive({
    name: '张三',
    age: 18
  })
  watch(()=>person.age, (newVal, oldVal) => {
    ...
  })
  // 只监视某一个属性,不能写person.age,因为只能监视ref、reactive、数组
  // 必须通过函数的返回值进行监视


  /**
  * 监视reactive定义的一个响应式数据的某个属性
  */
  let person = reactive({
    name: '张三',
    age: 18
  })
  watch([()=>person.name, ()=>person.age], (newVal, oldVal) => {
    ...
  })
  // 通过函数返回要监视的对象属性,存放在数组之中,实现监视多个属性


  /**
  * 特殊情况
  */
  let person = reactive({
    name: '张三',
    age: 18,
    job: {
      money: 20
    }
  })
  watch(()=>person.job,(newVal)=>{
    console.log(newVal)
  },{ deep:true })
  // 如果只监视job,此时深度监视有效,因为监听的不再是reactive定义的对象
}

7、watchEffect监视

立即执行传入的一个函数,并响应式追踪其依赖,并在其依赖变更时重新运行该函数。

import { watchEffet } from 'vue'
watchEffect(()=>{
  console.log('该回调执行了')
})

8、provide与inject

提供与注入,可以实现祖与后代组件之间的通信

父组件有一个provide选项提供数据,后代组件有一个inject选项使用数据

写法:

// 祖组件中
import { provide } from 'vue'
setup(){
    let cat = reactive({name:'张三'})
  // 给自己的后代组件传递数据
  provide('car', car)
  return {cat}
}
// 孙组件中
import { inject } from 'vue'
setup(){
  // 得到传递的数据,修改后所有的数据都会发生变化
  const car = inject('car')
  return {car}
}

三、其他组合式API

1、shallowRef和shallowReactive

import { shallowRef, shallowReactive } from 'vue'
/**
*   shallowReactive只考虑对象第一层的响应式
*/

/**
*   shallowRef和Ref的区别
*/
- shallowRef不去处理对象类型的响应式,只处理基本数据类型的响应式
- 而Ref会求助Reactive实现响应式

2、readonly和shallowReadonly

readonly是一个函数,加工一个响应式数据后不可修改

shallowReadonly只会使得第一层属性不可修改

import { shallowReadonly, readonly }
setup(){
  let person = reactive({
    name: '张三',
    age: 18,
    job: {
      money: {
        num: 20
      }
    }
  })

  // person只读
  person = readonly(person)
  // person第一层只读
  preson = shallowReadonly(person)
}

3、toRaw与markRaw

toRaw可以将一个由reactive生成的响应式对象转为普通对象

处理ref生成的响应式数据得到的是undefined

使用场景:用于读取响应式对象的普通对象,对普通对象的操作都不会引起页面更新

markRaw可以标记一个对象,这个对象永远都不会成为一个响应式对象

使用场景:

  • 有些值不应该设为响应式,例如复杂的第三方类库
  • 当渲染具有不可变数据源的大列表时候,跳过响应式转换可以提高性能

4、customRef

创建一个自定义的Ref,并对其依赖项进行跟踪和更新触发进行显示控制

实现防抖效果

<template>
    <input type="text" v-model="keyWord"/>
    <h3>{{keyWord}}</h3>
</template>
<script>
  import { customRef } from 'vue'
  export default {
    name:'App',
    setup(){
      // 自定义ref
      function myRef(val){
        return customRef((track,trigger)=>{
          return {
            // 读取自定义ref中数据时候调用
            get(){
              track()       // 追踪数据的改变,再次调用时返回数据
              return val
            },
            // 修改自定义ref中数据时候调用
            set(newVal){
              val = newVal
              trigger()     // 通知vue重新解析模板,再次调用get
            }
          }
        })
      }
      // 使用自定义ref
      let keyWord = myRef('')

      return {keyWord}
    }
  }
</script>

可以延迟trigger()的调用实现防抖,每次修改时清除定时器,再添加定时器

set(newVal){
  clearTimeout(timer)
  timer = setTimeout(()=>{
    val = newVal
    trigger()
  },500)
}

5、响应式数据的判断API

  • isRef:检查一个是是否为ref对象
  • isReactive:检查一个对象是否是由reactive创建的响应式代理
  • idReadonly:检查一个对象是否是由readonly创建的只读代理
  • isProxy:检查对象是否是由reactive或者readonly方法创建的代理

四、路由

版本v4.x

import { useRoute, useRouter } from 'vue-router'

使用的变化

  • let route = useRoute() 相当于this.$route
  • let router = useRouter() 相当于this.$router

路由的跳转

通过router-link进行跳转,取消了tag属性渲染成任意标签

导航守卫

1、全局

beforeEach(to, from, next){} 全局前置守卫,路由跳转前触发
beforeResolve(to, from, next){} 全局解析守卫
afterEach(to, from, next){} 全局后置守卫,路由跳转完成后触发

2、路由独享

beforeEnter(to, from, next){} 路由对象单个路由配置,路由进入前触发

3、组件

beforeRouteEnter(to, from, next){}      组件beforeCreate阶段触发
beforeRouteUpdate(to, from, next){}     当前路由改变时触发
beforeRouteLeave(to, from, next){}      导航离开该组件时触发

五、生命周期

image-20221007173246114

vue2和vue3生命周期可以混合使用

标签: vue3 组合式
最后更新:2022-10-16

粥呀Bo

所谓惊喜,就是苦苦等候的兔子来了,后面却跟着狼

点赞
< 上一篇
下一篇 >

文章评论

取消回复
目录
  • 一、数据劫持的实现
  • 二、常用组合式API
    • 1、setup函数
    • 2、ref函数
    • 3、reactive函数
    • 4、ref和reactive对比
    • 5、toRef
    • 6、计算属性
    • 6、watch监视
    • 7、watchEffect监视
    • 8、provide与inject
  • 三、其他组合式API
    • 1、shallowRef和shallowReactive
    • 2、readonly和shallowReadonly
    • 3、toRaw与markRaw
    • 4、customRef
    • 5、响应式数据的判断API
  • 四、路由
    • 1、全局
    • 2、路由独享
    • 3、组件
  • 五、生命周期

COPYRIGHT © 2022 zhouyaker.cn. ALL RIGHTS RESERVED.

THEME KRATOS MADE BY VTROIS

陕ICP备2022009272号