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,并使其逐年变得更好,并为我们提供更多选择。何不尝试一下,感觉也很不错哦。