Vue3 中的新特性—组合式 API(Composition API)

7,433 阅读5分钟

Vue 3的主要新增的功能是 Composition API(组合式 API),每一个新事物的出现都是来解决问题,组合式 API 为我们提供了一种新的方式编写和组织组件。通过使用 Vue2 的 Options API 重构一个组件来学习如何使用。

什么是组合式 API(composition API)

  • 组合式 API 是 Vue3 提供的新功能,为我们提供了另一种编写组件的方式

  • Option API - data()、computed 属性、methods、watchers 和 lifecycle hooks 这些 Option API 是我们在 Vue2 时代构建组件的一种方式,不过在 Vue3 我们有了新的方式来编写和组织组件的方式,这种方式

简短的回答:代码共享。在 setup 钩子里面,可以按逻辑上的关注点来对代码进行分组,并与其他组件共享代码。

另一方面,在Options API中,我们有两种主要的方法在组件之间共享代码。Mixins 和 Renderless Components。多亏了 Composition API,我们再也不用使用Mixins了。Mixins 使得我们很难确定某些逻辑部分在使用它们的组件中是来自哪里。但我认为无渲染组件仍然是一个有价值的工具,即使在组件之间可以使用可组合的代码来共享。

组合式 API 的出现解决了什么样的问题

  • 随着Vue项目规模和复杂性的增加,现有 Option API 变得难以应付
  • 逻辑并没有真正地按功能分组,这可能会让人很难读懂一个庞大而复杂的组件文件。
  • 通过 Option API 实现组件间共享重复的逻辑(共享代码)比较麻烦
  • 通过组合时 API 我们可以将重用逻辑封装为功能,这个功能可以组件间共享,这样你就可以在整个应用程序的不同组件中使用这些逻辑。

简短的回答:代码共享。在设置钩子里面,我们可以按逻辑上的关注点来分组我们的代码部分。然后我们可以提取反应式逻辑的片段,并与其他组件共享代码。

另一方面,在Options API中,我们有两种主要的方法在组件之间共享代码。Mixins和Renderless Components。多亏了Composition API,我们再也不用使用Mixins了。混合器使得我们很难确定某些逻辑部分在使用它们的组件中是来自哪里。但我认为无渲染组件仍然是一个有价值的工具,即使在组件之间可以使用可组合的代码来共享。

组合式 API

用于组合式 API 的响应式数据

在 Vue2 我们可以在 data 中定义一个基本类型数据或者一个复合类型数据,例如对象或者数组,然后将数据绑定到界面上,data 中定义数据可以被其他属性 computed 或者 methods 访问到,这些数据是响应式数据

data(){
    return{
        title:"machine leanring"
    }
}

下面是组合式 API(composition API) 实现方式,在 setup 定义个变量后将其作为一个对象的属性返回,便可以通过 {{title}} 显示在界面上

setup(){
  const title = "machine learning"
  return {
  	title
  }
}
<h1 class="title">{{title}}</h1>

响应式的基础类型数据

但是这样定义数据并不是响应式数据,不过 Vue3 提供两种方式在 setup 中定义响应式数据,分别是 refreactive 分别用于定义基本类型数据和复合数据。我们先看基础数据类型响应式方式为 ref(基础数据),例如 String、Number 或者 Boolean

        setup(){
            const title = ref("machine learning")
            return {
                title
            }
        }

响应式的复合类型数据

对于对象可以用 reactive来定义响应式对象,然后再 setup 作为返回对象的一个属性将其返回供调用。

setup(){
  const title = ref("machine learning");
	let count = ref(0)
  const tut = reactive({
		title:'machine learning',
		lesson:12,
		chapters:[
          {id:0,title:"introducion"},
          {id:2,title:"regression"},
          {id:3,title:"classification"},
				]
      })
		return {
      title,
      count,
      tut
		}
}

在 Vue2 通过defineProperty API 提供 getter 和 setter 来监听数据来实现响应式数据,不过这个中实现方式存在一些问题就是如果有大量属性值作为

Vue2 中的代码共享

Mixins 方式共享代码

文件名称说明
ClickCounter.vue通过点击按钮来更新计时器的数值
HoverCounter.vue通过鼠标滑过标题来更新计时器的数值
counter.js数据和更新数据方法从 ClickCounter.vue 和 HoverCounter.vue 抽离共享

在 Mixins 前的状态

下面代码大家可能再熟悉不过了,这里就不做过多解释了,分别实现了通过点击按钮来更新计时器的数值和通过鼠标滑过标题来更新计时器的数值功能两个组件。

ClickCounter.vue
<template>
    <div class="container">
        <div class="control">
            <button @click="incrementCount"  class="button" type="text" >click increatment {{count}}</button>
        </div>
    </div>
</template>

<script>

    export default {
        name:"ClickCounter",
        data(){
            return{
                count:0
            }
        },
        methods:{
            incrementCount(){
                this.count += 1;
            }
        }
    }
</script>
HoverCounter.vue
<template>
    <div class="container">
        <h2 @mouseover="incrementCount" class="title">Hoverd {{count}} </h2>
    </div>
</template>

<script>
    export default {
        name:"HoverCounter",
        data(){
            return {
                count:0
            }
        },
        methods:{
            incrementCount(){
                this.count += 1;
            }
        }
    }
</script>

<style scoped>

</style>
methods
methods:{
  incrementCount(){
  	this.count += 1;
  }
}

通过 Mixins 方式来将两个组件共享代码,首先我们将两个组件拥有代码提取出来到一个counter.js文件中,注意这是是 js 文件

export default{
    data(){
        return{
            count:0
        }
    },
    methods:{
        incrementCount(){
            this.count += 1;
        }
    }
}

更新后的 ClickCounter.vue 和 HoverCounter.vue ,通过引入 import CounterMixin from './counter',然后通过mixins属性引入 CounterMixin

<script>
    import CounterMixin from './counter'
    export default {
        name:"ClickCounter",
        mixins:[CounterMixin],
    }
</script>

mixin 后也可以在对象中定义同名的属性值,定义属性值会覆盖 mixin 中对应属性。

<script>
    import CounterMixin from './counter'
    export default {
        name:"HoverCounter",
        data(){
            return {
                count:100
            }
        },
        mixins:[CounterMixin]
    }
</script>

Vue3 组合式 API 来实现代码复用

首先通过组合式 API 对 ClickCounter.vue 和 HoverCounter.vue

ClickCounter.vue
<script>
    import {ref} from 'vue';

    export default {
        name:"ClickCounter",
        setup(){
            let count = ref(0);
            function incrementCount(){
                count.value += 1
            }
            return {
                count,
                incrementCount
            }
        }
    }
</script>

通过组合式 API 将上面代码改变了,然后可以将其中业务逻辑可以到处一个普通函数,

export default function incrementCount(count){
    const increment = ()=>count.value += 1;
    return {increment}
    
}

然后再文件将其 counter.js 方式导入 incrementCount

<script>
    import {ref} from 'vue';
    import incrementCount from './counter.js'
    export default {
        name:"HoverCounter",
        setup(){
            let count = ref(0);
            const {increment} = incrementCount(count)
       
            return {
                count,
                increment
            }
        }
    }
</script>

我们学习了如何一步一步地重构现有的 Vue 代码,从 Options- 到 Composition-API。这样做有助于将代码移到一个地方,而不是散落在组件中,然后将其分组为逻辑块。最后,能够提取一个组合函数,包含了我们组件的一部分,并且可以很容易地在另一个组件中再次使用。