尤大看了👀 都落泪的教程(1)

145 阅读4分钟

Composition API


1.Options API的缺点

  • 在Vue2的开发中,我们使用的是组合式API:

    • 组合式API一大特点就是在对应属性中编写对应的功能
    • 例如: data, methods,computed,watch,etc...
  • 但其实这种代码有一个很大弊端

    • 就是如果实现某一个功能的时候,这个功能对应的代码逻辑会被拆分到各个属性中;
    • 当组件变的越大,越复杂的时候,逻辑关注点的列表会增长,那么同一个功能的逻辑就会被拆分的很分散

img


2.认识Composition API

  • 为了开始使用Composition API,我们需要有一个可以实际使用它(编写代码)的地方

  • 就在setup函数中

  • setup函数其实就是组件的另外一个选项

    • 在setup函数中可以编写之前option api的大部分东西

3.setup函数的参数

  • 第一个参数是props

  • 第二个参数是context也可以简写为ctx上下文的意思

  • props其实很好理解,其实就是父组件传递过来的属性会放在props对象里,如果setup中如果需要使用,那么就可以通过props参数获取到传过来的值

    • 对于定义props的类型,我们还是和之前的是一样的,在props选项中定义;
    • 并且template中依旧能正常使用props的属性
    • setup函数里面不能直接this获取props
    • 因为props有直接作为参数传递到setup函数中,所以我们可以直接通过参数来使用即可
  • context也称为SetupContext,里面包含有三个属性

    • attrs:所有非prop的attribute
    • slots:父组件传递过来的插槽
    • emit:当我们组件内部需要发出事件时会用到emit(不能使用this)

来段代码看看

  • App.vue
<template>
  <div>
    <Home message="🥷你好"></Home>
  </div>
</template>
<script>
  import Home from "./Home.vue"
  export default {
    components: {
      Home
    }
    setup() {
      
    }
  }
</script>
<style scoped></style>
  • Home.vue
<template>
  <div>
    HOME PAGE
    <h2>{{props.message}}</h2>
  </div>
</template>
<script>
  export default {
    props: {
      message: {
        type:String,
        required:true
      }
    }
    setup(props,{attrs,slots,emit}) {
      console.log(props.message)
      console.log(context.emit) 对象结构完就不需要context.了
      console.log(emit)
    }
  }
</script>
<style scoped></style>

4.setup需要返回值

  • setup返回的值可以在template进行使用
  • 也就是之前的data() {return {}}被替代了
  • 方法和data在setup函数中都需要被返回,要不然使用不了
<template>
  <div>
    HOME PAGE
    <h2>{{message}}</h2>
    <button @click="changMessage">点我修改信息</button>
  </div>
</template>
<script>
  import {ref} from "vue"
  export default {
    setup(props,{emit}) {
      const message = ref("你好") //这个ref先不要理解,知道有这么一个东西就行,后面进行说明.
      //函数修改值
      const changMessage = () => {
        message.value = "javascript"
      }
      return {
        message,
        changMessage
      }
    }
  }
</script>
<style scoped></style>

5.setup的this问题

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

6.Reactive API

  • reactive函数在setup函数中提供响应式的特性

  • 为什么可以变成响应式?

    • 是因为如果使用reactive函数给我们的数据之后,数据再次使用会进行依赖收集
    • 当数据变化时,收集到的依赖都是对应的响应式操作(比如更新页面)
    • 其实以前data() {}也是在内部交给了reactive函数的哦
<template>
  <div>
    HOME PAGE
    <h2>{{person.age}}</h2>
    <button @click="changPerson">点我修改信息</button>
  </div>
</template>
<script>
  import {reactive} from "vue"
  export default {
    setup(props,{emit}) {
      const person = reactive({
        age:21
      })
      const changPerson = () => {
        person.age = 18
      }
      return {
        person,
        changPerson
      }
    }
  }
</script>
<style scoped></style>

7.Ref API

  • reactive API对传入的类型是有限制的,它要求必须传入的是一个对象或者数组类型:
  • 如果我们传入一个基本数据类型会报警告;

  • 那就可以使用ref,会返回一个可变的响应式对象,该对象作为一个 响应式的引用 维护着它内部的值,这就是ref名称的来源

  • 这里有两个注意事项:

    • 在模板中引入ref的值时,Vue会自动进行解包操作,所以并不需要在模板中通过 ref.value 的方式来使用
    • 但是在 setup 函数内部,它依然是一个 ref引用, 所以对其进行操作时,所以,依然需要使用 ref.value的方式;
<template>
  <div>
    HOME PAGE
    <h2>{{age}}</h2>
    <button @click="changAge">点我修改信息</button>
  </div>
</template>
<script>
  import {ref} from "vue"
  export default {
    setup(props,{emit}) {
      const age = ref(25)
      const changAge = () => {
        age.value = 18
      }
      return {
        age,
        changAge
      }
    }
  }
</script>
<style scoped></style>

8.解包操作

  • 其实ref是很浅的解包,所以如果你用另外一个对象存放声明好的ref其实是在template不会帮你解包的
  • 但是在reactive是可以解包的
<template>
  <div>
    HOME PAGE
    <h2>{{age}}</h2>
    <h3>{{newrefAge.age}}</h3> <!-- 不会解包,需要再.value -->
    <h4>{{newreactiveAge.age}}</h4><!-- 可以输出值 -->
    <button @click="changAge">点我修改信息</button>
  </div>
</template>
<script>
  import {ref,reactive} from "vue"
  export default {
    setup(props,{emit}) {
      const age = ref(25)
      const changAge = () => {
        age.value = 18
      }
      const newrefAge = {
        age
      }
      const newreactiveAge = {
        age
      }
      
      return {
        age,
        changAge
        newrefAge
        newreactiveAge
      }
    }
  }
</script>
<style scoped></style>

9.readonly

  • readyonly就是不能被修改,只能读取,假设把值传递给子组件的响应式对象,设置了readonly就不能被修改。
  • readonly也是会返回原生对象的只读代理(但它还是一个Proxy,set方法被劫持,并且不能进行修改)
  1. 第一种普通对象
<template>
  <button @click="updateInfo">
    点我修改
  </button>
</template>
<script>
  import {readonly} from "vue"
  export default {
    setup() {
      const info = {person:"周杰伦"}
      const readonlyInfo = readonly(info)
      const updateInfo =() => {
        readonlyInfo.person = "林俊杰"
      }
      return {
        updateInfo
      }
    }
  }
</script>
  1. 响应式对象
<template>
  <button @click="updateInfo">
    点我修改
  </button>
</template>
<script>
  import {readonly,reactive} from "vue"
  export default {
    setup() {
      const info = reactive({
        person:"周杰伦"
      })
      const readonlyInfo = readonly(info)
      
      const updateInfo =() => {
        readonlyInfo.person = "林俊杰"
      }
      return {
        updateInfo
      }
    }
  }
</script>
  1. 响应式对象ref
<template>
  <button @click="updateInfo">
    点我修改
  </button>
</template>
<script>
  import {ref,readonly} from "vue"
  export default {
    setup() {
      const info = ref("周杰伦")
      const readonlyInfo = readonly(info)
      
      const updateInfo =() => {
        readonlyInfo.value = "林俊杰"
      }
      return {
        updateInfo
      }
    }
  }
</script>

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


10.小总结

  • 这篇文章就是全面的开启了Vue3的主要新特性
  • 在选项式api中的this是不能使用的,要转换习惯
  • 选项式api还提供了ref和reactive响应式对象,都有对应注意的点,比如reactive只能定义复杂数据类型,简单数据类型不能定义哦
  • readonly可以设置成为只读的类型,一般使用都是给子组件传递一些不修改的值🔒