在上篇笔记中 《vue3带来了什么?》中,聊到的其中一个改变是,vue3中带来一组全新的api,composition api,该 api 集中,可以更好的封装代码块逻辑,而不需要分散到每个option api 的钩子函数中。
function useMousePosition() {
const position = Vue.reactive({
x: 0,
y: 0
});
const update = e => {
position.x = e.pageX;
position.y = e.pageY;
};
Vue.onMounted(() => {
window.addEventListener("mousemove", update);
});
Vue.onUnmounted(() => {
window.removeEventListener("mousemove");
});
return position;
}
const app = Vue.createApp({
setup() {
const position = useMousePosition();
return {
position
};
}
})
app.mount('#app')
就像例子中所示的,编写一个随着鼠标移动,将鼠标坐标显示在页面上
我们可以通过composition api 的方式,封装一个函数,后面我们只要对该事件处理函数进行维护和供其他函数所使用,这很大的提高了代码的可维护性。
而 vue2 中的option api将代码分割到各个钩子函数中,导致大型页面和组件后期代码臃肿,难于阅读的问题也得以解决。
今天,对 vue3 中的 composition api 学习过程中,做个简单 demo 记录。
composition api 中的生命周期,跟option api 中的生命周期函数类似,只是在命名中有所小改动,基本都在原有钩子命名中加了 on 为前缀
因为setup会在created后执行,所以composition里没有create相关的生命周期。
选项式 API | Hook inside setup |
beforeCreate | Not needed* |
created | Not needed* |
beforeMount | onBeforeMount |
mounted | onMounted |
beforeUpdate | onBeforeUpdate |
updated | onUpdated |
beforeUnmount | onBeforeUnmount |
unmounted | onUnmounted |
errorCaptured | onErrorCaptured |
renderTracked | onRenderTracked |
renderTriggered | onRenderTriggered |
接收一个对象作为参数,并将该参数转换成响应式对象(Proxy)返回。
function useMousePosition() {
const position = Vue.reactive({
x: 0,
y: 0
});
const update = e => {
position.x = e.pageX;
position.y = e.pageY;
};
Vue.onMounted(() => {
window.addEventListener("mousemove", update);
});
Vue.onUnmounted(() => {
window.removeEventListener("mousemove");
});
return position;
}
const app = Vue.createApp({
setup() {
const position = useMousePosition()
return {
position
};
}
})
app.mount('#app')
接收一个参数,将参数的所有属性转换成响应式数据。在 reactive 中,我们返回了positon 对象,当在setup 钩子中如果使用直接解构的方式,解构出来的是数据,不具备响应式。
通过babel中 es6 转换成 es5 可以发现,解构是重新定义了两个变量,进行赋值。所以解构出来的数据,不是 Proxy 对象。
因此,vue3还提供了一个 toRefs 函数。
function useMousePosition() {
const position = Vue.reactive({
x: 0,
y: 0
});
const update = e => {
position.x = e.pageX;
position.y = e.pageY;
};
Vue.onMounted(() => {
window.addEventListener("mousemove", update);
});
Vue.onUnmounted(() => {
window.removeEventListener("mousemove");
});
return Vue.toRefs(position);
}
const app = Vue.createApp({
setup() {
const {x, y} = useMousePosition();
return {
x,
y
};
}
})
app.mount('#app')
将对象传入 toRefs 中,将会把对象中的所有属性都转换成 Proxy 对象,这样在解构后,让属性保持响应式作用。
reactive 函数是将对象转换成 Proxy 对象,而 ref 是接收一个参数,将参数转换成 Proxy 对象,参数可为基础类型和引用类型,当参数为引用类型时, ref 内部还是会调用 reactive 函数,将其转为Proxy对象。
function useCount() {
const count = Vue.ref(0)
return {
count,
increase: () => {
count.value++
}
}
}
const app = Vue.createApp({
setup() {
return {
...useCount()
};
}
})
app.mount('#app')
计算属性,跟 option 中的使用方式类似, 接收一个函数,函数中返回计算后的结果。
function useCount() {
const count = Vue.ref(0)
return {
count,
increase: () => {
count.value++
}
}
}
const app = Vue.createApp({
setup() {
const {count, increase} = useCount()
const computedCount = Vue.computed(() => count.value + 2);
return { count, increase, computedCount };
}
})
app.mount('#app')
例子中,couputedCount 依赖于 count 的更新,所以当 count 更新时,couputedCount也会同样被更新。
watch有三个参数
第一个参数:要监听的数据
第二个参数:监听到数据变化后执行的函数,这个函数有两个参数,分别为新值和旧值
第三个参数:选项对象,deep和immediate
watch的返回值
取消监听函数
使用方法跟 Option Api 中的Watch一致
WatchEffect
是watch函数的简化版本,也用来监视数据变化
接受一个函数作为参数,监听函数内响应式数据的变化
const app = Vue.createApp({
setup() {
const count = Vue.ref(0)
const stop = Vue.watchEffect(() => {
console.log(count.value);
})
return {
count,
stop,
increase: () => {
count.value++
}
};
}
})
app.mount('#app')