• Vue3 -- Composition API setup函数 reactive ref ...


    Composition API

    在Vue2中,我们编写组件的方式是Options API:
    Options API的一大特点就是在对应的属性中编写对应的功能模块;
    比如data定义数据、methods中定义方法、computed中定义计算属性、watch中监听属性改变,也包括生命周期钩子;

    但是这种代码有一个很大的弊端:
    当我们实现某一个功能时,这个功能对应的代码逻辑会被拆分到各个属性中;
    当我们组件变得更大、更复杂时,逻辑关注点的列表就会增长,那么同一个功能的逻辑就会被拆分的很分散;
    尤其对于那些一开始没有编写这些组件的人来说,这个组件的代码是难以阅读和理解的(阅读组件的其他人);

    setup函数

    我们先来研究一个setup函数的参数,它主要有两个参数:
    第一个参数:props
    第二个参数:context
    props非常好理解,它其实就是父组件传递过来的属性会被放到props对象中,我们在setup中如果需要使用,那么就可以直接
    通过props参数获取:
    对于定义props的类型,我们还是和之前的规则是一样的,在props选项中定义;
    并且在template中依然是可以正常去使用props中的属性,比如message;
    如果我们在setup函数中想要使用props,那么不可以通过 this 去获取;
    因为props有直接作为参数传递到setup函数中,所以我们可以直接通过参数来使用即可;

    另外一个参数是context,我们也称之为是一个SetupContext,它里面包含三个属性:
    attrs:所有的非prop的attribute;
    slots:父组件传递过来的插槽;
    emit:当我们组件内部需要发出事件时会用到emit(因为我们不能访问this,所以不可以通过 this.$emit发出事件);

    setup的返回值可以在模板template中被使用;
    也就是说我们可以通过setup的返回值来替代data选项;

    甚至是我们可以返回一个执行函数来代替在methods中定义的方法

    let counter = 100
    const increment = () => {
    	counter++}
    const decrement = () => {
    	counter--;
    }
    
    return {
    	counter,
    	increment,
    	decrement
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    如果我们将 counter 在 increment 或者 decrement进行操作时,是否可以实现界面的响应式呢?
    答案是不可以;
    这是因为对于一个定义的变量来说,默认情况下,Vue并不会跟踪它的变化,来引起界面的响应式操作

    setup不可使用this解析

    this没有指向当前组件的实例
    并且在setup被调用之前 data computed methods等都没有被解析
    所以无法在setup中获取this

    reactive

    如果想为在setup中定义的数据提供响应式的特性,那么我们可以使用reactive的函数:
    这是因为当我们使用reactive函数处理我们的数据之后,数据再次被使用时就会进行依赖收集;
    当数据发生改变时,所有收集到的依赖都是进行对应的响应式操作(比如更新界面);
    事实上,我们编写的data选项,也是在内部交给了reactive函数将其编程响应式对象的;

    reactive API对传入的类型是有限制的,它要求我们必须传入的是一个对象或者数组类型

    	const userInfo = reactive({
    		name:'kobe',
    		age:18
    	})
    
    • 1
    • 2
    • 3
    • 4

    如果我们传入一个基本数据类型(String、Number、Boolean)会报一个警告

    这时 vue3给我们提供了另外一个API:ref

    ref

    ref 会返回一个可变的响应式对象,该对象作为一个 响应式的引用 维护着它内部的值,这就是ref名称的来源;
    它内部的值是在ref的 value 属性中被维护的;

    const message = ref('Hello World')
    
    • 1

    注意
    在template模板中引入ref的值时,Vue会自动帮助我们进行解包操作,所以我们并不需要在模板中通过 ref.value 的方式来使用;
    但是在template模板中修改的时候依然需要是哟个ref.value的方式
    但是在 setup 函数内部,它依然是一个 ref引用, 所以对其进行操作时,我们依然需要使用 ref.value的方式;

    readonly

    我们通过reactive或者ref可以获取到一个响应式的对象,但是某些情况下,我们传入给其他地方(组件)的这个响应式对象希
    望在另外一个地方(组件)被使用,但是不能被修改,这个时候如何防止这种情况的出现呢?
    Vue3为我们提供了readonly的方法;
    readonly会返回原生对象的只读代理(也就是它依然是一个Proxy,只是这个proxy的set方法被劫持,并且不能对其进行修
    改);

    在开发中常见的readonly方法会传入三个类型的参数:
    类型一:普通对象;
    类型二:reactive返回的对象;
    类型三:ref的对象;

    在readonly的使用过程中,有如下规则:
    readonly返回的对象都是不允许修改的;
    但是经过readonly处理的原来的对象是允许被修改的;
    比如 const info = readonly(obj),info对象是不允许被修改的;
    当obj被修改时,readonly返回的info对象也会被修改;
    但是我们不能去修改readonly返回的对象info;

    其实本质上就是readonly返回的对象的setter方法被劫持了而已;

    Reactive 判断的API

    isProxy
    检查对象是否是由 reactive 或 readonly创建的 proxy。

    isReactive
    检查对象是否是由 reactive创建的响应式代理:
    如果该代理是 readonly 建的,但包裹了由 reactive 创建的另一个代理,它也会返回 true;

    isReadonly
    检查对象是否是由 readonly 创建的只读代理。

    toRaw
    返回 reactive 或 readonly 代理的原始对象(不建议保留对原始对象的持久引用。请谨慎使用)。

    shallowReactive
    创建一个响应式代理,它跟踪其自身 property 的响应性,但不执行嵌套对象的深层响应式转换 (深层还是原生对象)

    shallowReadonly
    创建一个 proxy,使其自身的 property 为只读,但不执行嵌套对象的深度只读转换(深层还是可读、可写的)。

    toRefs

    如果我们使用ES6的解构语法,对reactive返回的对象进行解构获取值,那么之后无论是修改结构后的变量,还是修改reactive
    返回的state对象,数据都不再是响应式的:

    const state = reactive({
    	name:'kobe',
    	age:18
    })
    
    const { name, age } = state;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    Vue为我们提供了一个toRefs的函数,可以将reactive返回的对象中的属性都转成ref;
    那么我们再次进行结构出来的 name 和 age 本身都是 ref的

    const { name, age } = toRefs(state)
    
    • 1

    这种做法相当于已经在state.name和ref.value之间建立了 链接,任何一个修改都会引起另外一个变化;

    toRef

    如果我们只希望转换一个reactive对象中的属性为ref,那么可以使用toRef的方法

    const name = toRef(state, 'name');
    const { age } = state;
    const changeName = () => state.name = 'lbj'
    
    • 1
    • 2
    • 3

    ref的其他API

    unref
    如果我们想要获取一个ref引用中的value,那么也可以通过unref方法:
    如果参数是一个 ref,则返回内部值,否则返回参数本身;
    这是 val = isRef(val) ? val.value : val 的语法糖函数;

    isRef
    判断值是否是一个ref对象。

    shallowRef
    创建一个浅层的ref对象;

    triggerRef
    手动触发和 shallowRef 相关联的副作用:

    const info = shallowRef({name:'kobe'});
    
    // 下面的修改不是响应式的
    const changeInfo = () => {
    	info.value.name = 'lbj'
    	//手动触发
    	triggerRef(info)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  • 相关阅读:
    机器学习基础:大数定律与中心极限定理
    leetcode:367. 有效的完全平方数
    C++静态成员&友元&命名空间介绍
    低代码开发——进最热的赛道,啃最硬的骨头
    (4E)-TCO-PEG4-acid,1802913-21-8物理性质分享
    IF 22.1,中科院1区TOP,顶级期刊更名!
    SpringBoot 学习(六)Shiro
    NCBI/BIG测序数据下载---Aspera下载安装使用
    python+django+nodejs+vue的影视信息网站
    安装配置MySQL
  • 原文地址:https://blog.csdn.net/weixin_65402230/article/details/127591321