Vue引入了Composition API(基于功能的API)作为当前基于Option的API的补充。该API将随Vue 3一起发布,但是现在您可以通过将Vue 3 Composition API添加到您的Vue 2应用程序中来进行尝试。
在本教程中,我将向您展示:
添加Vue Composition API会发生什么变化?
一切仍将像以前一样工作。几乎没有任何变化:
当前基于选项的API概念与新的合成API(基于函数的API)概念的区别在于:
组件选项可能变得组织起来复杂且难以维护(怪异的组件)。逻辑可能涉及props和data()的属性,某些方法,某个钩子(beforeMount/mounted)以及值班的watch。因此,一个逻辑将分散在多个选项中。
使用Composition API,每个功能都是大型组件的一部分,它封装了与逻辑相关的所有代码(属性,方法,钩子,watch观察者)。现在,较小的代码(函数)可以重复使用,并且组织得很好。
通过安装@vue/composition-api模块,我们可以在当前的Vue 2.x项目中使用新的Vue 3 Composition API。
非常简单,只需运行以下命令:
npm install @vue/composition-api or yarn add @vue/composition-api
然后将其导入main.js。
import Vue from 'vue'; import CompositionApi from '@vue/composition-api'; Vue.use(CompositionApi);
setup()是新的组件选项,我们将使用新的Vue Composition API设置组件的逻辑。如果setup()函数变得复杂,我们可以轻松地将其拆分为多个具有逻辑主题的函数。
何时调用setup()?
创建组件实例时,在props解析后调用它。
现在,使用setup()函数查看Vue组件:
const MyComponent = { props: { name: String }, setup(props, context) { console.log(props.name); // context.attrs // context.slots // context.emit // context.parent // context.root } }
该函数有2个参数:
–props
–context
context具有与this.$attrs,this.$slots,this.$emit,this.$parent,this.$root对应的属性(属性,插槽,emit,parent,root)。
即使在更新后,我们也可以使用解构attrs
来获取
最新值:
const MyComponent = { setup(props, { attrs }) { function onClick() { attrs.foo // 自动更新为最新的值 } } }
*注意:this关键字在setup()函数中不可用。
所以this.$emit不能这样使用:
setup() { function onClick() { this.$emit // 无效 } }
为了获得对模板中元素或组件实例的引用,我们使用ref API,以便setup()可以为渲染上下文返回可响应和可变对象。
import { ref } from '@vue/composition-api' const MyComponent = { setup(props) { const name = ref('bezkoder.com') const appendName = () => { name.value = `hello ${props.name}` } return { name, appendName } }, template: `<div @click="appendName">{{ name }}</div>` }
ref会自动解包为内部值,因此我们无需在模板中附加.value:。{{name}}就足够了,而不是{{name.value}}。
基于Vue2选项的API语法:
export default { props: { title: String }, computed: { vTitle() { return '-' + this.title + '-'; }, itemsQuantity() { return this.items.length; } }, data() { return { items: ['This', 'is'], }; }, }
Vue 3 Composition API语法:
import { ref, computed } from '@vue/composition-api'; export default { props: { title: String }, setup(props) { const vTitle = computed(() => '-' + props.title + '-'); const items = ref(['This', 'is']); const itemsQuantity = computed(() => items.value.length); return { vTitle, items, itemsQuantity, }; } };
使用新的计算API,我们可以使用get和set函数创建可写的ref对象。
const count = ref(1) const double = computed({ get: () => count.value * 2, set: val => { count.value = val - 1 } }) double.value = 3 // set: count.value = 3 - 1 = 2 console.log(count.value) // 2 console.log(double.value) // get: count.value * 2 = 4
这就是我们使用基于Vue2选项的API语法的方式:
export default { data() { return { items: ['This', 'is'], append: '' }; }, watch: { items: { handler: function(value, oldValue) { this.append = ''; value.forEach(item => { this.append += item + ' '; }); }, immediate: true } }, }
就像watch选项一样,每次状态改变时,我们都可以使用新的Vue watch API来执行副作用逻辑代码。
语法为:watch(源,回调,选项)
import { ref, watch } from '@vue/composition-api'; export default { setup(props) { const items = ref(['This', 'is']); const append = ref(''); watch( // getter () => items.value, // callback (items, oldItems) => { append.value = ''; items.forEach(item => { append.value += item + ' '; }); }, // watch Options { lazy: false // immediate: true } ) return { items, append }; } };
如果我们想观察多个源:
watch([aRef, bRef], ([a, b], [prevA, prevB]) => { /* ... */ })
我们还可以将多个源观察程序拆分为较小的观察程序。这有助于我们组织代码并创建具有不同选项的观察程序:
watch( // getter () => items.value, // callback (items, oldItems) => { append.value = ''; items.forEach(item => { append.value += item + ' '; }); }, // watch Options { lazy: false // immediate: true } ) watch( // getter () => todo.value.length, // callback (length, oldLength) => { todoLength.value = length; }, // watch Options { lazy: true // immediate: false } )
使用Vue2,我们通过以下方式实现Lifecycle Hooks函数:
export default { beforeMount() { console.log('V2 beforeMount!') }, mounted() { console.log('V2 mounted!') } };
新的Vue 3 Composition API具有等效的功能,我们可以在setup()函数内使用带前缀的功能:
import { onBeforeMount, onMounted } from '@vue/composition-api'; export default { setup() { onBeforeMount(() => { console.log('V3 beforeMount!'); }) onMounted(() => { console.log('V3 mounted!'); }) } };
您可以在下表中看到Vue2 生命周期Options与Composition API之间的映射:
现在,我们将以上所有代码组合到一个Vue组件中,您可以看到一个包含多个逻辑的复杂组件。我们需要为标题,待办事项和项目实现对应的逻辑:
import { ref, reactive, computed, watch, onBeforeMount, onMounted } from '@vue/composition-api'; export default { props: { title: String, initInput: String }, setup(props) { const vTitle = computed(() => '-' + props.title + '-'); const todo = ref(props.initInput); const todoLength = ref(0); const items = ref(['This', 'is']); const itemsQuantity = computed(() => items.value.length); const append = ref(''); watch( // getter () => items.value, // callback (items, oldItems) => { append.value = ''; items.forEach(item => { append.value += item + ' '; }); }, // watch Options { lazy: false // immediate: true } ) watch( // getter () => todo.value.length, // callback (length, oldLength) => { todoLength.value = length; }, // watch Options { lazy: false // immediate: true } ) const add = () => { if (todo.value) { items.value.push(todo.value); todo.value = ''; } }; const remove = index => { items.value.splice(index, 1); }; onBeforeMount(() => { console.log('V3 beforeMount!'); }) onMounted(() => { console.log('V3 mounted!'); }) return { vTitle, todo, todoLength, items, itemsQuantity, append, add, remove }; } };
是时候利用Vue Composition API了:将复杂的组件拆分为多个对应于不同逻辑的函数:
import { ref, computed, watch, onBeforeMount, onMounted } from "@vue/composition-api"; function useTitle(props) { const vTitle = computed(() => "-" + props.title + "-"); return { vTitle }; } function useTodoLength(todo) { const todoLength = ref(0); watch( // getter () => todo.value.length, // callback (length, oldLength) => { todoLength.value = length; }, // watch Options { lazy: false // immediate: true } ); return { todoLength }; } function useItems(todo) { const items = ref(["This", "is"]); const itemsQuantity = computed(() => items.value.length); const append = ref(""); watch( // getter () => items.value, // callback (items, oldItems) => { append.value = ""; items.forEach(item => { append.value += item + " "; }); }, // watch Options { lazy: false // immediate: true } ); const add = () => { if (todo.value) { items.value.push(todo.value); todo.value = ""; } }; const remove = index => { items.value.splice(index, 1); }; return { items, itemsQuantity, append, add, remove }; } export default { props: { title: String, initInput: String }, setup(props) { const todo = ref(props.initInput); onBeforeMount(() => { console.log("V3 beforeMount!"); }); onMounted(() => { console.log("V3 mounted!"); }); return { todo, ...useTitle(props), ...useTodoLength(todo), ...useItems(todo) }; } };
使用旧的基于Vue选项的API时,您可能会感到熟悉舒适;或者,您不希望将所有内容都作为函数,而是继续保持OOP思维方式的属性/方法。这些想法都没问题。同时开发者们也在积极开发Vue,并使其逐年变得更好,并为我们提供更多选择。何不尝试一下,感觉也很不错哦。