vue3 中公布的 RFC 中有一个很重要的概念--Function API。这个概念是用来做什么呢?简单的说是为了逻辑组合与复用。那为什么要在 vue2 中尝试呢?第一确实好用,第二官方明确表示:vue-function-api 的实现只依赖 Vue2.x 本身,不论 Vue3.x 的发布与否,都不会影响您正常使用本库。第三,在 vue3 发布后,可以无缝替换掉。所以不用担心以后的问题。既然没有后顾之忧,那么我们先看一段船新版本的代码
安装
npm install vue-function-api --save
使用
//app.js
import Vue from 'vue'
import { plugin } from 'vue-function-api'
Vue.use(plugin)
// mousePosition.js
import { value, onMounted, onUnmounted } from 'vue-function-api';
export default function mousePosition() {
const x = value(0);
const y = value(0);
const update = e => {
x.value = e.pageX;
y.value = e.pageY;
};
onMounted(() => {
window.addEventListener('mousemove', update);
});
onUnmounted(() => {
window.removeEventListener('mousemove', update);
});
return { x, y };
}
这段代码是用来获取鼠标的位置,并且返回两个值,x 和 y。下面是我们具体使用的代码。
// hello.vue
<template>
<div>鼠标 x:{{ x }} 鼠标 y:{{ y }</div>
</template>
<script>
import mousePosition from "./mousePosition";
export default {
setup() {
const { x, y } = mousePosition();
return { x, y };
}
};
</script>
来看一下效果:
在 vue2 中我们可以通过 Mixins 或者 HOC(高阶组件) 来实现逻辑抽象和复用。但是这些模式都存在数据来源不清晰和命名空间冲突的问题。记得以前的项目中,我用 mixins 来做通用逻辑的时候,团队其他成员很可能无意间写的重名函数覆盖 mixins 中的函数。 而通过上面的代码,我们可以看到新版的 function-api 的特点:
- 暴露给模版的属性来源清晰(从函数返回),不存在隐式依赖;
- 通过赋值解构,返回值可以被任意重命名,不存在命名空间冲突;
- 需要用到的函数需要手动引入(这样对 tree-shaking 真的很友好啊有木有,又可以优化打包大小了有木有)
下面来具体看一下 function API。
setup()
vue3 的组件现在接受一个新的 setup() 选项,类似 data(),setup() 可以返回一个对象 —— 这个对象上的属性将会被暴露给模版的渲染上下文。接受两个参数:props 和 context。需要注意的是,setup() 中不可以使用 this 访问当前组件实例, 我们可以通过 setup() 的第二个参数 context 来访问 vue2.x API 中实例上的属性。
来看一下与 vue2 的对比
//vue2
<template>
<div>鼠标 x:{{ x }} 鼠标 y:{{ y }}</div>
</template>
<script>
export default {
data() {
return {
x: 0,
y: 0
}
},
mounted() {
window.addEventListener("mousemove", this.update);
},
beforeDestroyed() {
window.removeEventListener("mousemove", this.update);
},
methods: {
update(e) {
this.x = e.pageX;
this.y = e.pageY;
}
}
};
</script>
// function-api
<template>
<div>鼠标 x:{{ x }} 鼠标 y:{{ y }}</div>
</template>
<script>
import { value, onMounted, onUnmounted } from 'vue-function-api';
export default {
setup(){
const x = value(0);
const y = value(0);
const update = e => {
x.value = e.pageX;
y.value = e.pageY;
};
onMounted(() => {
window.addEventListener('mousemove', update);
});
onUnmounted(() => {
window.removeEventListener('mousemove', update);
});
return { x, y };
}
};
</script>
新版的 setup() 函数中,需要处理的数据可以按照逻辑顺序写下来,这样是不是比原来更紧凑一些?
value()
在定义变量中,我们需要用 value() 函数来包装变量对象。这是因为在 JavaScript 中,原始类型只是保存了值,无法追踪原始变量后续的变化的。所以需要用 value() 函数来包装一下。在模板中使用变量时,可以直接使用,而不用写 x.value。这是因为 vue 自动帮我们做了这些操作。
computed()
接受两个参数:getter:Function 和 setter:Function,基本上和 vue2 中的 computed 一样。
举个栗子
export default {
setup(){
const num = value(0)
const numPuls = computed(()=>num.value+1)
}
};
生命周期
除了 beforeCreated 之外,支持所有的 vue2 中的生命周期函数,都换成了 onXXX,另外增加了一个 onUnmounted。接收的参数是一个 function。使用起来也很简单,与原来相比并无太大差距。
总结
这篇文章并没有翻译全部的 API,只是简单的将逻辑复用的思路将了一下,如果项目中有大量可复用代码可以尝试在 vue2 中使用 function API。如果有兴趣可以看查看官网文档。链接点这里