Vue 3 大不同 | 全局 API “没了”

前端桃园

共 2826字,需浏览 6分钟

 · 2020-07-24

Vue 的 2.x 版本有很多的全局 API 和 配置,它们会在全局范围内改变 Vue 的行为。

比如常见的全局 API 有:Vue.component / Vue.mixin / Vue.extend / Vue.nextTick;

常见的全局配置有:Vue.config.silent / Vue.config.devtools / Vue.config.productionTip

比如(官方例子),如果你想创建一个全局的组件,你会用到 Vue.component:

Vue.component('trump-sucks', {
  data() => ({ position'America president', }),
  template`

Trump is the worst ${position}

`;
});


ac8611820a1399e179d63e3538525fbb.webp

或者声明一个全局指令:

Vue.directive('focus', {
  insertedel => {
    console.log('聚焦!');
    el.focus();
  },
});

这样确实比较方便,但是会造成一些问题。首先要明确的一点是,Vue 2.x 在设计上并没有 app(应用)的概念。开发者在使用 Vue 2.x 时所谓的 app 不过是一个用 new Vue()创建的 Vue 实例罢了(呵,不过如此)。由同一个 Vue 构造函数创建的 Vue 实例都会共享来自构造函数的全局配置。这将会导致:

在测试过程中,由于全局配置的存在,测试用例很容易就会被“污染”。开发者需要小心翼翼地将全局配置找一个地方存下来,在每次测试结束后将其还原,比如 Vue.config.errorHandler;一些 API 比如 Vue.useVue.mixin 甚至没有避免其影响的办法。这使得在测试中一旦涉及了插件,整个过程都会变得非常棘手。事实上,为了解决这个问题,vue-test-utils 不得不引入一个特殊的 API:createLocalVue

import { createLocalVue, mount } from '@vue/test-utils';
const localVue = createLocalVue();
localVue.use(MyPlugin);
mount(Component, { localVue });

还有一个避免不了的问题是,一旦页面上有多个 Vue 实例时,它们的全局配置就很自然地共享了,但在很多时候开发者并不想要这样的结果

Vue.mixin({
  mounted() => {
    console.log('wubba lubba dub dub');
  },
});

const rick = new Vue({ el'#rick' });
const morty = new Vue({ el'#morty' });

因此,为了规避这些问题,Vue 3 引入了应用实例的概念。


全局 API: createApp

调用 createApp 会返回一个 应用实例,没错,应用实例这个概念是 Vue 3 中新引入的。

import { createApp } from 'vue';
const app = createApp();

应用实例会暴露一个当前全局 API 的子集。在这个重构工作中,Vue 团队秉承的经验法则是:任何会在全局范围内影响 Vue 行为的 API 都会被迁移至应用实例中去

2.x 的全局 API3.x 的应用实例 API

Vue.config

app.config

Vue.config.productionTip

移除

Vue.config.ignoredElements

app.config.isCustomElement

Vue.component

app.component

Vue.directive

app.directive

Vue.mixin

app.mixin

Vue.use

app.use

其他不会在全局影响 Vue 行为的 api 都已改造为具名导出的构建方式(named exports),就像之前尤雨溪尤大在直播里说的那样:为了支持 TreeShaking

10b90392ecd5b8aa32db8fb1ab89a90c.webp

挂载一个应用实例

在使用 createApp(VueInstance) 得到一个应用实例后,这个应用实例就可以用来把整个 Vue 跟实例挂载到页面上了:

import { createApp } from 'vue';
import MyApp from './MyApp.vue';

const app = createApp(MyApp);
app.mount('#app');

在完成了这些改造之后,开篇我们提到的那些例子将会重写成这样:

app.component('trump-sucks', {
  data() => ({ position'America president', }),
  template`

Trump is the worst ${position}

`;
});

app.directive('focus', {
  insertedel => {
    console.log('聚焦!');
    el.focus();
  },
});

// 至此,所有在 app 所包含的组件树内创建的 Vue 实例才会共享 trump-sucks 这个组件和 focus 这个指令,而 Vue 构造函数并没有被污染。

多个应用实例的配置共享

上文提到的“不是所有开发者都想要的全局配置共享”,在 Vue 3 中可以通过工厂函数的方式实现:

import { createApp } from 'vue';
import CaiXuKun from './CXK.vue';
import WuYiFan from './WYF.vue';

const createIdolApp = (IdolInstance) => {
 const idolApp = createApp(IdolInstance);
  idolApp.directive('sing-and-dance', {
   inserted() => {
      console.log('I am cool!');
    },
  });
}

createIdolApp(CaiXuKun).mount('#caixukun');
createIdolApp(WuYiFan).mount('#wuyifan');

这样就能实现多个应用实例的配置共享了:蔡徐坤和吴亦凡都有了一个叫做“唱跳”的 Vue 自定义指令。

9c92b5c72a6564ef46c089798178dd5f.webp

- END -




推荐阅读




我的公众号能带来什么价值?(文末有送书规则,一定要看)

每个前端工程师都应该了解的图片知识(长文建议收藏)

为什么现在面试总是面试造火箭?

浏览 5
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报