一起来学习vue3的知识点,看看和vue2有哪些区别

144 阅读8分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第11天,点击查看活动详情

Vue3的生命周期

Vue2的生命周期钩子函数:

  • beforeCreate
  • Created
  • beforeMount
  • Mounted
  • beforeUpdate
  • Updated
  • beforeDestroy
  • Destroyed

Vue3的生命周期钩子函数:

  • setup 组件实例创建之前
  • onBeforeMount挂载DOM前
  • onMounted 挂载DOM后
  • onBeforeUpdate 更新组件前
  • onUpdated更新组件后
  • onBeforeUnmount 卸载销毁前
  • onUnmounted 写在销毁后

总结:组合API的生命周期钩子函数有7个,可以多次使用同一个钩子函数,执行顺序和书写顺序相同

setup函数

使用细节:

  • setup是一个新的组件选项,作为组件中使用组合API的起点
  • 从组件生命周期来看,它的执行在组件实例创建之前vue2的beforCreate执行
  • 这就意味着在setup函数中,this还不是组件实例,this此刻是undefined
  • 在模板中需要使用的数据和函数,需要在setup中返回

image.png

<template>
 <div>
   {{name}}
 </div>
</template>
<script>
export default{
  setup(){
      
     const name="张三"
     
    return {name}
      
  }
}
</script>
<style lang='less'  scoped>
    
</style>

总结: setup组件初始化之前执行,它返回的数据和函数可在模板中使用

reactive函数

定义响应式数据

  • reactive是一个函数,定义一个对象成为响应式数据
const obj = reactive({})

toRef函数

  • 将响应式数据对象中的某个属性变成了ref对象
toRef将对象里的某个属性转换为应式数据,并且包装成了ref对象,value是存放值的位置
cosnt name=toRef(目标对象,'属性')
const age=toRef(obj,'age')  //操作的是同一个数据值, 更新时二者是同步的
const age=ref(obj.name)    //拷贝了一份新的数据值单独操作, 更新时相互不影响
  • 为源响应式对象上的某个属性创建一个 ref对象, 二者内部操作的是同一个数据值, 更新时二者是同步的
  • 区别ref: 拷贝了一份新的数据值单独操作, 更新时相互不影响
  • 应用: 当要将 某个prop 的 ref 传递给复合函数时,toRef 很有用

toRefs函数

问题: reactive 对象取出的所有属性值都是非响应式的

解决: 利用 toRefs 可以将一个响应式 reactive 对象的所有原始属性转换为响应式的 ref 属性

拿出对象里的所有属性为独立响应式变量数据使用

  • toRefs是一个函数,转换响应式对象所有属性独立响应式数据,并且值是关联的
  • 通常用于解构或展开reactive定义的对象
  • 把对象中的所有属性,拿出来当变量使用
toRefs将对象里的所有属性转换为应式数据,并且每个属性都包装成了对象,value是存放值的位置
cosnt name=toRefs(目标对象)

使用场景:剥离(解构或展开)响应式对象,想使用响应式对象中的多个或者所有属性作为独立的响应式数据(在模板中不想使用obj.name,想直接使用name)

ref函数

定义简单数据为响应式数据

  • ref是一个函数,定义一个简单数据类型为响应式数据
  • ref函数也支持定义复杂数据类型为响应式数据
const num = ref(10)

使用场景:

  • 当你明确知道需要的是一个响应式数据对象,那么就是用reactive
  • 其他情况使用ref

computed函数

定义计算属性

  • computed是一个函数,是用来定义计算属性的
 // 只有getter的计算属性
const new = computed(()=>{
             retun 1
            })
     
     
// 有getter与setter的计算属性
const fullName = computed({
      get () {
        return 1
      },
      set (value: string) {
        consolr.log(value)
      }
})

实际上返回的是ref类型的对象

watch函数

定义侦听器

  • watch是一个函数,用来定义侦听器的
watch三个参数:
1、监听的参数
2、改变后触发的函数
3、深度监听
​
//监听ref基本数据
const count = ref(0)
watch(count,(new,old)=>{    
})
​
//监听reactive对象
const obj = reactive({})
watch(obj ,(new,old)=>{    
})
​
//监听对象中某一个属性的变化,需要写成函数返回该属性的方式才能监听到
//因为obj是响应式的,obj.name不是,也就是说监听的不是响应式数据,需要通过函数来指定
const obj = reactive({})
watch(()=>obj.name ,(new,old)=>{    
})
​
​
//监听多个类型数据
const count = ref(0)        
const obj = ractive({})    
const obj2 = ractive({
    name:'123'
})
watch([count,obj,()=>obj2.name],(new,old)=>{    
})
​
//深度监听(对象里有对象)
const obj = reactive({})
watch(obj ,(new,old)=>{    
},{
      // 深度监听
      deep: true,
      // 默认触发
      immediate: true
    })

ref属性

获取DOM或组件实例

vue2获取:

image.png

vue3:获取:

获取单个DOM

image.png

获取v-for遍历的DOM

image.png

获取组件和DOM方法一致

父子组件通讯

父传子:父自定义属性+子props接收

模板中使用和vue2一样

在要steup中使用,需要props参数

image.png

子传父:子使用$emit触发父自定义事件

在要steup中使用,需要context参数才能拿到emit

image.png

依赖注入

共享父组件数据

场景:有一个父组件,里头有子组件,有孙组件,有很多后代组件,共享父组件数据

使用:provide函数和inject函数完成后代组件通讯

// 父组件将数据提供给后代组件provide        
父组件:  provide('属性名', 值)
//子组件接收祖先组件提供的数据inject   
任意后代组件:  const money = inject('属性名')

子组件如何修改传过来的值

关于子想修改值,必须通知父亲,通知的父亲是谁定义的谁修改
​
1、父组件可以将修改值的函数提供给后代
2、后代可以接收父组件传过来的函数,再合适的时机调用,传参修改
​

v-model语法糖

image.png

 大概思路:
    1、 v-moldel=“n“可实现父向子传值
    2、 子:props里modelVale 接收
    3、 子修改父组件传来的数据,v-moldel包含了async,可直接update:modelVale 修改
  
 注意点:当组件复用时,不能多次使用 v-moldel
    <myCompnets  v-moldel='n'></myCompnets>  //实现组件间的数组双向通信
    <myCompnets  v-moldel='n'></myCompnets>  // v-moldel='n'不能再同一组件出现多次,组件复用也不能写,只能出现一次
    

vue3里,使用v-moldel实现父子组件之间的数据双向通讯时,要注意只能出现一次,组件复用也只能出现一次,不能出现多次

mixins语法

将重复逻辑的代码抽取出来,然后混入到组件中

main.js里:

image.png

1、全局混入:所有组件都混入这些逻辑代码

image.png

所有组件DOM挂载后都会打印这句话

2、局部混入

1、创建一个js文件,提供mixin逻辑

// 配置对象
export const followMixin =  {
  data () {
    return {
      loading: false
    }
  },
  methods: {
    followFn () {
      this.loading = true
      // 模拟请求
      setTimeout(()=>{
        // 省略请求代码
        this.loading = false
      },2000)
    }
  }
}

2、个别组件内使用

#组件1
<template>
  <div class="container1">
    <h1> 作者:周杰伦  <a href="javascript:;" @click="followFn">{{loading?'请求中...':'关注'}}</a> </h1>
    <hr>
    <Son />
  </div>
</template>
<script>
import Son from './Son.vue'
import {followMixin} from './mixins'
export default {
  name: 'App',
  components: {
    Son
  },
  mixins: [followMixin]   //使用
}
</script>
​
​
##组件2
<template>
  <div class="container2">
    <h2> 作者:周杰伦  <button @click="followFn">{{loading?'loading...':'关注'}}</button> </h2>
  </div>
</template>
<script>
import {followMixin} from './mixins'
export default {
  name: 'Son',
  mixins: [followMixin]  //使用
}
</script>
<style scoped lang="less"></style>

总结:在vue2.0中一些可复用的逻辑可以使用mixins来封装,当是需要考虑逻辑代码冲突问题。vue3.0的组合API很好的解决了这个问题,就不在推荐使用mixins了

API(其它部分)

shallowReactive 与 shallowRef

  • shallowReactive : 只处理了对象内最外层属性的响应式(也就是浅响应式)

  • shallowRef: 只处理了value的响应式, 不进行对象的reactive处理

  • 什么时候用浅响应式呢?

    • 一般情况下使用ref和reactive即可
    • 如果有一个对象数据, 结构比较深, 但变化时只是外层属性变化 ===> shallowReactive
    • 如果有一个对象数据, 后面会产生新的对象来替换 ===> shallowRef

readonly 与 shallowReadonly

  • readonly:

    • 深度只读数据
    • 获取一个对象 (响应式或纯对象) 或 ref 并返回原始代理的只读代理。
    • 只读代理是深层的:访问的任何嵌套 property 也是只读的。
  • shallowReadonly

    • 浅只读数据
    • 创建一个代理,使其自身的 property 为只读,但不执行嵌套对象的深度只读转换
  • 应用场景:

    • 在某些特定情况下, 我们可能不希望对数据进行更新的操作, 那就可以包装生成一个只读代理对象来读取数据, 而不能修改或删除

toRaw 与 markRaw

  • toRaw(变成普通对象)

    • 返回由 reactivereadonly 方法转换成响应式代理的普通对象。
    • 这是一个还原方法,可用于临时读取,访问不会被代理/跟踪,写入时也不会触发界面更新。
  • markRaw(让对象再也不能变成代理对象)

    • 标记一个对象,使其永远不会转换为代理。返回对象本身

    • 应用场景:

      • 有些值不应被设置为响应式的,例如复杂的第三方类实例或 Vue 组件对象。
      • 当渲染具有不可变数据源的大列表时,跳过代理转换可以提高性能。

响应式数据的判断

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

动态引入组件

image.png