美文网首页
拉开序幕的 setup

拉开序幕的 setup

作者: 荆承鹏 | 来源:发表于2022-08-16 15:34 被阅读0次

1. 拉开序幕的 setup

  1. 理解:vue3 中的一个新的配置项,值为一个函数。

  2. setup 是所有 Compositon api 的表演的舞台。

  3. 组件中用到的:数据,方法,watch,计算属性等都要配置在 setup 中

  4. setup 的返回值有两种:

  • 若返回一个对象,则对象中的属性,方法,在模板中均可以直接使用。(重点关注)
  • 若返回的是一个渲染函数,则可以直接定义渲染内容。(了解)
  1. 注意点:
  • 尽量不要与 vue2 混用。
    -- vue2配置(data, methods, computed...)中可以访问到 setup 中的属性,方法。但是setup 中不能访问到 vue2 中的配置(data, methods, computed...)
    -- 如果有重名,setup 优先

  • setup 不能是一个 async 函数,因为返回值不再是 return 的对象,而是 promise, 模板看不到 returen 对象中的属性。

2. ref函数

  1. 作用:定义一个响应式的数据。
  2. 语法: const xxx = ref(initeValue)
  • 创建一个包含响应式数据的引用对象(reference 对象)。
  • JS 中操作数据: xxx.value
  • 模板中读取不用 .vulue 直接写。
  1. 备注:
  • 接收数据可以是是基本数据类型,也可以是对象类型。
  • 基本数据类型:响应依然是靠 Object.defineProperty() 里的 get 和 set 完成的。
  • 对象类型:内部是求助了 vue3 中的内置的新函数 reactive 函数。

3. reactive 函数

  1. 作用:定义一个对象类型的响应式。基本理性用 ref 函数。
  2. 语法: const 代理对象 = reactive(原对象)。 接收一个对象(或者数据),返回一个代理对象(proxy 对象)。
  3. reactive 定义的响应式数据是深层次的。
  4. 内部基于 ES6 的 proxy 实现,通过代理对象操作源对象内部数据,进行操作。

4. vue2 的响应式原理

  1. 实现原理:
  • 对象类型:通过 Object.defineProperty() 对属性的读取,修改进行拦截(数据劫持)。
  • 数据类型:通过重写更新数组的一系列方法来实现拦截. (对数组的变更方法进行了包裹)。
Object.defineProperty(data,'count',{
  set(){},
  get(){}
})
  1. 存在问题:
  • 新增属性,删除属性,界面不会发生变化
  • 数组通过下标修改,不会更新界面

5. vue3 的响应式

  1. 实现原理:
  • 通过 Proxy(代理):拦截对象中任意属性的变化,包括属性的读写,添加,删除等。
  • 通过 Reflect (反射):实现源对象的属性进行操作
  • MDN 有对应的文档
new Proxy(data, {
  //拦截读取数据属性值
  get(target, prop){
    return Reflect.get(target,prop)
  },
  //拦截设置或或添加属性值
  set(target,prop,value){
    return Reflect.set(target,prop,value)
  }
  //拦截删除属性
  deleteProperty(target, prop){
    return Reflect.deleteProperty(target, prop)
  }
})

6. ref 和 reactive 的对比

  1. 从定义数据角度对比
  • ref 定义基本类型数据
  • reactive 定义对象或者数组类型数据
  • 备注:ref 也可以定义对象或者数组类型数据,但是内部它自动通过 reactive 转为代理对象实现。
  1. 从原理角度对比:
  • ref 还是通过 vue2 的 Object.defineProperty() 的 get 和 set 实现的响应式(数据劫持)。

  • reactive 通过使用 Proxy 来实现响应式(数据劫持),并通过 Reflect 操作源对象内部的数据。

  1. 从使用角度对比:
  • ref 定义的数据:操作数据需要 .value。 读取数据时候模板中直接读取不需要 .value

  • reactive 定义的数据,操作与读取均不需要 .value

7. setup 的两个注意点

  1. setup 的执行时机
    在 beforeCreate 之前执行一次,this 是 undifined

  2. setup 的参数

  • props:值为对象,包含:组件外部传递过来,且组件内部声明接收了的属性。
  • context:上下文对象
    -- attrs:值为对象,包含:组件外部传递过来,但是没有在 props 配置中-声明的属性。相当于 this.attrs. -- slots: 接收的插槽内容,相当于this.slots.
    -- emit: 分发自定义函数,相当于 this.$emit.

8. 计算属性与监视

8.1 computed 函数

  1. 与vue2 中的 computed 相比,配置功能一致。
  2. 写法
import {computed} from 'vue'

setup(){
  ...
  //计算属性一般写法
  let fullName = computed(()=>{
    return person.firstName + '-' + person.lastName
  })
  
  //计算属性完整写法
  let fullName = computed(()=>{
  get(){
    
   return person.firstName + '-' + person.lastName
  },
  set(value){
    const nameArr = value.splice("-")
    person.firstName = nameArr[0]
    person.lastName = nameArr[1]
  }
  })
  
}

8.2 watch 函数

  1. 与 vue2 中的 watch 配置一样
  2. 两个小坑
  • 监视 reactive 定义的响应式数据时,oldValue 无法正确获取,强制开启了深度监视(deep 配置失效)。
  • 监视 reactive 定义的响应式数据中的某个属性时候,deep 配置有效。
//情况一,监视 ref定义的数据
watch(sum, (newValue,oldVaule)=>{
  consolo.log("sum数据变化了", newValue,oldVaule)
})

//情况二,监视多个 ref定义的数据
watch([sum,msg], (newValue,oldVaule)=>{
  consolo.log("sum或者 msg 数据变化了", newValue,oldVaule)
})

//情况三,监视reactive定义的数据
//若 watch 监视的是 reactive 定义的响应式数据,则无法获取正确的 oldValue
//若 watch 监视的是 reactive 定义的响应式数据,则强制开启了深度监视

watch(person, (newValue,oldVaule)=>{
  consolo.log("person数据变化了", newValue,oldVaule)
}, {immediate:ture, deep: false}) //此处的 deep 不生效

//情况四,监视reactive定义的某个属性
watch(()=>person.job, (newValue,oldVaule)=>{
  consolo.log("person的job数据变化了", newValue,oldVaule)
}) 

//情况五,监视reactive定义的某些属性
watch([()=>person.job,()=>person.name], (newValue,oldVaule)=>{
  consolo.log("person的job或者name数据变化了", newValue,oldVaule)
})

//特殊情况
watch([()=>person.job,()=>person.name], (newValue,oldVaule)=>{
  consolo.log("person的job或者name数据变化了", newValue,oldVaule)
}, {deep:true}) //此处由于监视的是 reactive 定义中的某个属性,所以 deep配置有效。

8.3 watchEffect 函数

  1. watch 函数的套路:既要指明监视的属性,也要指明监视的回调
  2. watchEffect 函数的套路是:不用指明监视那个属性,监视的回调中用到那个属性,那就监视那个属性。
  3. watchEffect有点像 computed:
  • 但是 computed 注重的计算出来的值(回调函数返回值),所以必须要写返回值。
  • 而 watchEffect 更注重的是过程(回调函数的函数体),所以不用写返回值。
//watchEffect所指定的回调中用到的数据只要发生变化,则直接重新执行回调
watchEffect(()=>{
  const x = sum.value
  const x2 = person.age
  console.log("watchEffect配置的回调执行了")
})

相关文章

网友评论

      本文标题:拉开序幕的 setup

      本文链接:https://www.haomeiwen.com/subject/ojzrgrtx.html