Vue3组合式API

作者: 生命里那束光 | 来源:发表于2022-06-30 23:36 被阅读0次

    组合API

    前言

    • 组合式api(Composition API)算是vue3对我们开发者来说非常有价值的一个api更新。
    • 注意,vue3中仍可以使用选项API。

    一、选项API和组合API

    选项API

    • 各个选项都有固定的书写位置,data选项写响应式数据,methods选项写方法函数...,一个功能逻辑的代码分散。

    • 优点:写代码的位置已经约定好,结构清晰

    • 缺点:代码组织性差,相似的逻辑代码不便于复用,逻辑复杂代码多了不好阅读,同一功能的上下文代码难找。

    组合API

    • 特定功能相关的所有东西都写在一起,同一功能代码块集中
    • 优点:
      • 可以快读定位到某个功能的所有相关代码。
      • 功能复杂,代码量大,我们还可以进行逻辑拆分处理,功能封装。

    组合API功能抽离,封装:


    二、生命周期函数

    选项式API 组合式API
    beforeCreate 不需要(直接写到setup(创建实例前)函数中)
    created 不需要(直接写到setup(创建实例前)函数中)
    beforeMount onBeforeMount挂载DOM前
    mounted onMounted挂载DOM后
    beforeUpdate onBeforeUpdate更新组件前
    updated onUpdated更新组件后
    beforeDestroyed onBeforeUnmount卸载销毁前
    destroyed onUnmounted卸载销毁后

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


    三、组合API基础

    3.1 setup入口函数
    1. setup 函数是一个新的组件选项,作为组件中组合式API 的起点(入口)
    2. setup 中不能使用 this, this 指向 undefined
    3. setup函数只会在组件初始化的时候执行一次
    4. setup函数在beforeCreate生命周期钩子执行之前执行
    export default {
      setup () {
        console.log('setup执行了')
        console.log(this)
      },
      beforeCreate() {
        console.log('beforeCreate执行了')
        console.log(this)
      }
    }
    

    3.2 reactive函数
    • 作用:reactive是一个函数,接收一个普通的对象传入,把对象数据转化为响应式对象并返回

    使用步骤

    1. 从vue框架中导入reactive函数
    2. setup函数中调用reactive函数并将对象数据传入
    3. setup函数中把reactive函数调用完毕之后的返回值以对象的形式返回出去

    3.3 toRef函数
    • toRef是函数,转换响应式对象中某个属性为单独响应式数据,并且值是关联的。

    3.4 toRefs函数
    • 场景: 经过reactive函数处理之后返回的对象,如果给这个对象解构或者展开,会让数据丢失响应式的能力,为了解决这个问题需要引入toRefs函数,使用 toRefs函数 可以保证该对象展开的每个属性都是响应式的。

    3.5 ref函数
    • 作用:ref是一个函数,接受一个简单类型或者复杂类型的传入并返回一个响应式且可变的 ref 对象

    使用步骤

    1. 从vue框架中导出ref函数
    2. setup函数中调用ref函数并传入数据(简单类型或者复杂类型)
    3. setup函数中把ref函数调用完毕的返回值以对象的形式返回出去
    4. 注意:在setup函数中使用ref结果,需要通过.value访问,模板中使用不需要加.value

    四、组合API

    4.1 computed函数
    • computed函数,是用来定义计算属性的,计算属性不能修改。

    计算属性两种用法:

    • computed传入函数,返回值就是计算属性的值
    • computed传入对象,get获取计算属性的值,set监听计算属性改变。

    4.2 watch函数
    • watch函数,是用来定义侦听器的
    1. 监听ref定义的响应式数据

    2. 监听多个响应式数据数据

    3. 监听reactive定义的响应式数据

    4. 监听reactive定义的响应式数据,某一个属性

    5. 深度监听

    6. 默认执行

    <template>
      <div class="container">
        <div>
          <p>count的值:{{count}}</p>
          <button @click="add">改数据</button>
        </div>
        <hr>
        <div>
          <p>{{obj.name}}</p>
          <p>{{obj.age}}</p>
          <p>{{obj.brand.name}}</p>
          <button @click="updateName">改名字</button>
          <button @click="updateBrandName">改品牌名字</button>
        </div>
      </div>
    </template>
    <script>
    import { reactive, ref, watch } from 'vue'
    export default {
      name: 'App',
      setup () {
        const count = ref(0)
        const add = () => {
          count.value++
        }
        // 当你需要监听数据的变化就可以使用watch
        // 1. 监听一个ref数据
        // 1.1 第一个参数  需要监听的目标
        // 1.2 第二个参数  改变后触发的函数
        // watch(count, (newVal,oldVal)=>{
        //   console.log(newVal,oldVal)
        // })
    
        const obj = reactive({
          name: 'ls',
          age: 10,
          brand: {
            id: 1,
            name: '宝马'
          }
        })
        const updateName = () => {
          obj.name = 'zs'
        }
        const updateBrandName = () => {
          obj.brand.name = '奔驰'
        }
        // 2. 监听一个reactive数据
        watch(obj, ()=>{
          console.log('数据改变了')
        })
    
        watch(()=>obj.brand, ()=>{
          console.log('brand数据改变了')
        },{
          // 5. 需要深度监听
          deep: true,
          // 6. 想默认触发
          immediate: true
        })
    
        // 3. 监听多个数据的变化
        // watch([count, obj], ()=>{
        //   console.log('监听多个数据改变了')
        // }) 
    
    
        // 4. 此时监听对象中某一个属性的变化 例如:obj.name 
        // 需要写成函数返回该属性的方式才能监听到
        // watch(()=>obj.name,()=>{
        //   console.log('监听obj.name改变了')
        // })
    
        return {count, add, obj, updateName, updateBrandName}
      }
    }
    </script>
    

    4.3 ref属性
    • 使用ref属性绑定DOM或组件

    获取单个DOM或者组件:

    <template>
      <div class="container">
        <!-- vue2.0 获取单个元素 -->
        <!-- 1. 通过ref属性绑定该元素 -->
        <!-- 2. 通过this.$refs.box获取元素 -->
        <!-- <div ref="box">我是box</div> -->
        <!-- vue2.0 获取v-for遍历的多个元素 -->
        <!-- 1. 通过ref属性绑定被遍历元素 -->
        <!-- 2. 通过this.$refs.li 获取所有遍历元素  -->
        <!-- <ul>
          <li v-for="i in 4" :key="i" ref="li">{{i}}</li>
        </ul> -->
    
        <!-- 单个元素 -->
        <div ref="dom">我是box</div>
        <!-- 被遍历的元素 -->
        <ul>
          <li v-for="i in 4" :key="i" :ref="setDom">第{{i}}LI</li>
        </ul>
      </div>
    </template>
    <script>
    import { onMounted, ref } from 'vue'
    export default {
      name: 'App',
      setup () {
        // 1. 获取单个元素
        // 1.1 先定义一个空的响应式数据ref定义的
        // 1.2 setup中返回该数据,你想获取那个dom元素,在该元素上使用ref属性绑定该数据即可。
        const dom = ref(null)
        onMounted(()=>{
           console.log(dom.value)
        })
      }
    }
    </script>
    <style scoped lang="less"></style>
    

    获取v-for遍历的DOM或者组件:

    // 2. 获取v-for遍历的元素
       // 2.1 定义一个空数组,接收所有的LI
       // 2.2 定义一个函数,往空数组push DOM
       const domList = []
       const setDom = (el) => {
         domList.push(el)
       }
       onMounted(()=>{
         console.log(domList)
       })
       return {dom, setDom}
    

    总结:

    • 单个元素:先申明ref响应式数据,返回给模版使用,通过ref绑定数据

    • 遍历的元素:先定义一个空数组,定一个函数获取元素,返回给模版使用,通过ref绑定这个函数

      • 有一个边界问题:组件更新的时候会重复的设置dom元素给数组:
      // ref获取v-for遍历的DOM元素,需要在组件更新的时候重置接受dom元素的数组。
      onBeforeUpdate(()=>{
        list = []
      })
      

    4.4 父子通讯

    父传子:

    子传父:

    总结:

    • 父传子:在setup种使用props数据 setup(props){ // props就是父组件数据 }
    • 子传父:触发自定义事件的时候emit来自 setup(props,{emit}){ // emit 就是触发事件函数 }
    • 在vue3.0中 v-model.sync 已经合并成 v-model 指令

    4.5 依赖注入(祖孙通讯)
    • 使用provide函数和inject函数完成后代组件数据通讯

    总结:

    • provide函数提供数据和函数给后代组件使用
    • inject函数给当前组件注入provide提供的数据和函数

    五、补充

    5.1 v-model语法糖
    • 在vue2.0中v-mode语法糖简写的代码 <Son :value="msg" @input="msg=$event" />
    • 在vue3.0中v-model语法糖有所调整:<Son :modelValue="msg" @update:modelValue="msg=$event" />

    演示代码:

    //父组件App
    <template>
      <div class="container">
        <!-- 如果你想获取原生事件事件对象 -->
        <!-- 如果绑定事函数 fn fn(e){ // e 就是事件对象 } -->
        <!-- 如果绑定的是js表达式  此时提供一个默认的变量 $event -->
        <h1 @click="$event.target.style.color='red'">父组件 {{count}}</h1>
        <hr>
        <!-- 如果你想获取自定义事件  -->
        <!-- 如果绑定事函数 fn fn(data){ // data 触发自定义事件的传参 } -->
        <!-- 如果绑定的是js表达式  此时 $event代表触发自定义事件的传参 -->
        <!-- <Son :modelValue="count" @update:modelValue="count=$event" /> -->
        <Son v-model="count" />
      </div>
    </template>
    <script>
    import { ref } from 'vue'
    import Son from './Son.vue'
    export default {
      name: 'App',
      components: {
        Son
      },
      setup () {
        const count = ref(10)
        return { count }
      }
    }
    </script>
    
    
    //子组件Son
    <template>
      <div class="container">
        <h2>子组件 {{modelValue}} <button @click="fn">改变数据</button></h2>
      </div>
    </template>
    <script>
    export default {
      name: 'Son',
      props: {
        modelValue: {
          type: Number,
          default: 0
        }
      },
      setup (props, {emit}) {
        const fn = () => {
          // 改变数据
          emit('update:modelValue', 100)
        }
        return { fn }
      }
    }
    </script>
    

    总结: vue3.0封装组件支持v-model的时候,父传子:modelValue 子传父 @update:modelValue

    补充: vue2.0的 xxx.sync 语法糖解析 父传子 :xxx 子传父 @update:xxx 在vue3.0 使用 v-model:xxx 代替。


    5.2 mixins语法
    • 混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。

    理解全局混入:所有组件混入了这些逻辑代码

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

    相关文章

      网友评论

        本文标题:Vue3组合式API

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