Vue 3.0 前瞻Vue Function API新特性体验

最近 Vue 官方公布了 Vue 3.0 最重要的,并发布了兼容 Vue 2.0 版本的 plugin:vue-function-api,可用于提前体验 Vue 3.0 版本的 Function-based component API。笔者出于学习的目的,提前在项目中尝试了vue-function-api

笔者计划写两篇文章,本文为笔者计划的第一篇,主要为笔者在体验 Vue Function API 的学习心得。第二篇计划写阅读vue-function-api的核心部分代码原理,包括setup、observable、lifecycle。

本文阅读时间约为15~20分钟。

概述

Vue 2.x 及以前的高阶组件的组织形式或多或少都会面临一些问题,特别是在需要处理重复逻辑的项目中,一旦开发者组织项目结构组织得不好,组件代码极有可能被人诟病为“胶水代码”。而在 Vue 2.x 及之前的版本,解决此类问题的办法大致是下面的方案:

笔者维护的项目也需要处理大量复用逻辑,在这之前,笔者一直尝试使用mixin的方式来实现组件的复用。有些问题也一直会对开发者和维护者造成困惑,如一个组件同时mixin多个组件,很难分清对应的属性或方法写在哪个mixin里。其次,mixin的命名空间冲突也可能造成问题。难以保证不同的mixin不用到同一个属性名。为此,官方团队提出函数式写法的意见征求稿,也就是。使用函数式的写法,可以做到更灵活地复用组件,开发者在组织高阶组件时,不必在组件组织上考虑复用,可以更好地把精力集中在功能本身的开发上。

注:本文只是笔者使用vue-function-api提前体验 Vue Function API ,而这个 API 只是 Vue 3.0 的 RFC,而并非与最终 Vue 3.x API 一致。发布后可能有不一致的地方。

在 Vue 2.x 中使用

要想提前在Vue 2.x中体验 Vue Function API ,需要引入vue-function-api,基本引入方式如下:

import Vue from 'vue'; import { plugin as VueFunctionApiPlugin } from 'vue-function-api'; Vue.use(VueFunctionApiPlugin);

基本组件示例

先来看一个基本的例子:

<template> <div> <span>count is {{ count }}</span> <span>plusOne is {{ plusOne }}</span> <button @click="increment">count++</button> </div> </template> <script> import Vue from 'vue'; import { value, computed, watch, onMounted } from 'vue-function-api'; export default { setup(props, context) { // reactive state const count = value(0); // computed state const plusOne = computed(() => count.value + 1); // method const increment = () => { count.value++; }; // watch watch( () => count.value * 2, val => { console.log(`count * 2 is ${val}`); } ); // lifecycle onMounted(() => { console.log(`mounted`); }); // expose bindings on render context return { count, plusOne, increment, }; }, }; </script>

详解

setup

setup函数是Vue Function API 构建的函数式写法的主逻辑,当组件被创建时,就会被调用,函数接受两个参数,分别是父级组件传入的props和当前组件的上下文context。看下面这个例子,可以知道在context中可以获取到下列属性值:

const MyComponent = { props: { name: String }, setup(props, context) { console.log(props.name); // context.attrs // context.slots // context.refs // context.emit // context.parent // context.root } }

value & state

value函数创建一个包装对象,它包含一个响应式属性value:

Vue 3.0 前瞻Vue Function API新特性体验

那么为何要使用value呢,因为在JavaScript中,基本类型并没有引用,为了保证属性是响应式的,只能借助包装对象来实现,这样做的好处是组件状态会以引用的方式保存下来,从而可以被在setup中调用的不同的模块的函数以参数的形式传递,既能复用逻辑,又能方便地实现响应式。

直接获取包装对象的值必须使用.value,但是,如果包装对象作为另一个响应式对象的属性,Vue内部会通过proxy来自动展开包装对象。同时,在模板渲染的上下文中,也会被自动展开。

import { state, value } from 'vue-function-api'; const MyComponent = { setup() { const count = value(0); const obj = state({ count, }); console.log(obj.count) // 作为另一个响应式对象的属性,会被自动展开 obj.count++ // 作为另一个响应式对象的属性,会被自动展开 count.value++ // 直接获取响应式对象,必须使用.value return { count, }; }, template: `<button @click="count++">{{ count }}</button>`, };

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/0da36298073a176aeaec57d76eae9e69.html