vue2 中尝鲜 Function API --- 这是你没有见过的船新版本

793 阅读4分钟

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() 可以返回一个对象 —— 这个对象上的属性将会被暴露给模版的渲染上下文。接受两个参数:propscontext。需要注意的是,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:Functionsetter: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。如果有兴趣可以看查看官网文档。链接点这里