react & vue & angularvueVue

Vue3组合式API

2022-06-30  本文已影响0人  生命里那束光

组合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}

总结:


4.4 父子通讯

父传子:

子传父:

总结:


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

总结:


五、补充

5.1 v-model语法糖

演示代码:

//父组件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语法

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

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

上一篇下一篇

猜你喜欢

热点阅读