CompisitionAPI的基本使用(1)-setup函数

745 阅读7分钟

Compsition API

  1. 为什么有mixin和mixin的合并规则是怎样的
    1. 组件和组件之间存在着相同的代码逻辑, 我们希望对相同的代码进行逻辑抽取
    2. vue2和vue3版本中都使用了mixin来完成
    3. mixin的合并规则 3.1 data中的返回对象, 返回的对象默认情况下会进行合并,如果合并对象中的命名发生冲突,以组件自身的数据为准 3.2 生命周期中相同的钩子函数会被合并到数组中,数组中的逻辑都会被调用 3.3 值为对象的选项(methods, directives等),在methods的方法都会生效,如果键名相同, 以组件的键名为准
  2. 全局混入
    • 如果某个选项 是所有组件都需要拥有的,那么我们可以在根组件使用全局混入的功能, 这样每个组件都会在初始化的时候被混入这个功能实现
        app.mixin({
          created() {
            console.log('全局的mixin')
          }
        })
      

为什么使用Compsition API

  1. optionsAPI的特点在实现一个功能时,这个功能的代码会被编写到各个功能模块中, 比如data, methods,filters等, 随着业务和功能复杂度的增加,模块中的逻辑代码就会变得越长,这样同一个功能的逻辑就会被拆得很分散,而且难以阅读和定位。这些碎片化的代码在理解和维护上面越来月困难,而且隐藏了潜在的问题逻辑。当我们在处理单个逻辑点时,需要不断的切换到模块中
  2. 这是我更加喜欢React的原因,而且Vue对于有追求的开发, 不涉及底层实现,真的毫无技术含量
  3. 大组件optionApi页面
  • 62783021-7ce24400-ba89-11e9-9dd3-36f4f6b1fae2.png
  1. 如果我们编写功能代码,同一个逻辑能够收集在一起,岂不是更好, 这就是CompisitionAPI想做以及能帮我们完成的事情.

认识CompisitionAPI

  1. 在Vue3中兼容了Vue2的写法基础上, 增加了setup函数
  2. setup其实就是Vue3在组件中的新增配置选项
    • 只不过这个选项可以强大到可以替换之前编写的大部分的选项功能
    • 比如 metods computed watch data 生命周期等
  3. 了解setup函数
    1. setup有两个参数 props和context

      1. props就是父组件传递的子组件的属性被放在了props中,当在setup中使用的时候,可以在props上直接获取
      2. 另外一个参数时context,称为setupContext. 这个对象包含了三个属性
        1. attrs: 所有非props的attribute集合
        2. slots: f父组件传递过来的slot插槽集合
        3. emit: 组件想要内部发出事件的功能函数
    2. setup的返回值

      1. setup的返回值可以在template模板中使用
      2. 也就是可以通过setup的返回值代替Vue2中的data
      3. setup中也可以返回一个执行函数替代Vue2中methods
          setup(props, context) {
            let foo = 'foo'
            let counter = 0 //不具有响应式
            const changeCounter = () =>  counter++
            return {
              foo,
              counter,
              changeCounter
            }
          }
        
      4. 但是对于Vue来说, 默认情况下Vue并不会跟踪它的变化,来响应页面的更新
    3. setup中不可以使用this

      1. 47652692-AF1F-41fe-87C8-8256062D0B5A.png
      2. 这段表达的意思是
        1. this没有指向当前的实例

        2. 在setup调用之前data,properrty computed或者methods都没有被解析

        3. 无法在setup中获取this

        4. 其实之前在描述setup不能使用this的原因是组件的实例还没有被创建出来,但是在源码中可以看到setup函数执行之前组件的实例已经被创建。

    4. 响应式API

      1. reactive函数和ref函数
          <template>
            <div>{{myName}}</div>
            <div>{{state.age}}</div>
            <div>需要value: {{info.name.value}}</div>
            <div>不需要value: {{info1.name}}</div>
          </template>  
        
          setup(props, context) {
            // reactive响应式 传递的数据类型是对象或者数组(Object, Array)
            const state = reactive({
              name: 'hawkeye',
              age: 18
            })
            // ref函数也是响应式的, 不过一般传递的是基本数据类型数据(Number,String,Boolean)
            const myName = ref('hawkeye')
            const info = {
              name: myName
            }
            const info1 = reactive({
              name: myName
            })
            return  {
              state,
              myName,
              info,
              info1
            }
          }
        
      2. reactive为什么会是响应式?
        1. 因为我们在使用reactive函数处理我们的数据以后, 数据再次被使用时就会进行依赖收集
        2. 当数据发生变化时,所有收集的响应式依赖都是进行对应的响应式操作(比如页面跟新, 更改数 据等)
        3. 其实在Vue3中的data属性也是交给了reactive函数将其变成响应式的,而Vue2中使用的时 Object.defineProperty
      3. ref是怎样应用的?
        1. ref会返回一个可变的响应式对象,该对象作为一个响应式的引用维护着内部的值
        2. ref对象内部的值是通过value的属性值进行维护
        3. 模板template中使用ref,Vue会自动帮助我们进行解包操作,所以我们并不需要在return使 用ref.value的方式
        4. 但是在setup中它依然是一个引用的值,使用的时候通过ref.value来使用
        5. ref的解包功能是浅层解包, 在ref放在reactive属性中,在模板中使用也会自动解包
    5. readonly

      1. reactive和ref可以获取一个响应式的对象, 但是某些情况下我们在数据传递给其他组件的时候,我们希望我们传递的数据只能被使用,不能被更改, 像props provide提供的数据等
      2. Vue3提供了readonly, readonly会返回一个对原生对象只读的代理,再开发中常见的readonly数据类型
        1. 普通对象
        2. reactive返回的对象
        3. ref返回的对象
      3. readonly的使用规则
        1. readonly返回的对象都是不能被修改的

        2. 但是经过readonly处理的原对象是可以被修改的

            const info = {
              name: 'hawkeye',
              age: 18
            }
            const info1 = readonly(info)
            console.log(info1)
          
            const state = reactive({
              name: 'hawkeye',
              age: 18
            })   
            const state1 = readonly(state)
            console.log(state1)
          
            const name = ref('hawkeye')
            const name1 = readonly(name)
            console.log(name1)
                    // info对象是不允许被修改的, 但是当obj对象被修改时,应用类型的关系 info的属性也被修改了,但是我们不能直接去对象info的属性进行修改
          
        3. 其本质就是再readonly函数返回的对象中对setter函数进行了劫持,但是被代理的对象并没有

        4. 修改readonly产生的警告

        5. 9FA1B714-438F-4577-87FE-7233E6184CF9.png

    6. 响应式API的判断

      1. isProxy(): 检查对象是否时reactive或者readonly创建的proxy对象
      2. isReactive(): 检查对象是否是有reactive创建出来的代理对象, 还有一种如果这个对象是由readonly代理的reactive的对象, 结果也会返回true
          const info = reactive({name: 'hawkeye', age: 18})
          console.log(isReactive(info)) // true
          console.log(isReactive(readonly(info))) // true
        
      3. isReadonly():检查是否由readonly创建的只读代理对象
      4. toRaw(): 返回reactive或者readonly的代理原始对象
      5. shadowReactive(): 创建一个响应式代理,他跟踪自身property属性,但是不嵌套深层次的响应式转换
      6. shadowReadonly(): 创建一个proxy,使其自身是只读的,但是不嵌套深层次的响应式转换
    7. toRefs

      使用es6的解构特性, 对reactive返回的对象进行解构,都会让数据失去响应式,那么我们怎样可以让解构的数据也具有响应式呢?

      1. vue给我们提供了toRefs的函数, 可以将reactive返回对象中的属性都转换为ref
      2. 这种做法相当于reactive中的属性ref建立了链接, 任何一个修改都会引起另一个变化
      3. 如果我们只想修改reactive中的一个某个属性,可以使用toRef, toRef(reactiveObj, property)
            const state = reactive({
              name: 'haw',
              age: 18,
              height: 1.80
            })
            const {name, age} = toRefs(state)
            const height = toRef(state, 'height')
            console.log(height) // 响应式的ref对象
            const changeName = () => {
              info.name = 'hawkeye'
              console.log(state) // 会发生变化
            }
            return {
              ...toRefs(state), // 不涉及到变量的修改可以直接这样写 
              name,
              age,
              changeName
            }
        
        1. isRef() 判断值是否未一个ref对象
        2. shallowRef(): 创建一个浅层的ref
        3. triggerRef():手动触发和shallowRef相关联的副作用
           const info = shallowRef({name: 'haw'})
            // 这种修改不死响应式的
            const changeRef = () => {
              info.value.name = 'hawkeye' // 获取的时候是ref.value.property
              // 手动触发shallowRef的响应式
              triggerRef(info)
            }
        
            return {
              info,
              changeRef
            }