前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >写给 vue2.0 开发者的 vue3.0 教程

写给 vue2.0 开发者的 vue3.0 教程

作者头像
公众号---人生代码
发布2020-05-26 15:18:02
2.7K0
发布2020-05-26 15:18:02
举报
文章被收录于专栏:人生代码人生代码

Vue 3还没有正式发布,但是维护者已经发布了beta版本,以供我们的用户尝试并提供反馈

如果您想知道Vue 3的主要特性和主要变化,我将在本文中通过使用Vue 3 beta 9创建一个简单的应用程序来强调它们

我将介绍尽可能多的新内容,包括片段、传送、复合API和其他一些模糊的更改。我也会尽我所能来解释这个特性或变更的基本原理

如何构建

我们将构建一个带有模态窗口功能的简单应用程序。我选择这个是因为它方便地允许我展示一些Vue 3的更改。

下面是这款应用在打开和关闭状态下的样子,这样你就可以在脑海中想象出我们正在做的事情:

Vue3.0的安装与启动

与其直接安装Vue 3,不如克隆Vue -next- Webpack -preview项目,它将为我们提供包括Vue 3在内的最小的Webpack设置。

代码语言:javascript
复制
$ git clone https://github.com/vuejs/vue-next-webpack-preview.git vue3-experiment
$ cd vue3-experiment
$ npm i

一旦克隆并安装了NPM模块,我们所需要做的就是删除样板文件并创建一个新的main.js文件,这样我们就可以从头创建Vue 3应用程序了。

代码语言:javascript
复制
$ rm -rf src/*
$ touch src/main.js

现在我们将运行开发服务器:

创建一个新的 vue3.0 app

马上,我们启动一个新的Vue应用程序的方式改变了。我们现在需要导入新的createApp方法,而不是使用新的Vue()

然后我们调用这个方法,传递我们的Vue实例定义对象,并将返回对象分配给一个变量app

接下来,我们将在app上调用mount方法,并传递一个CSS选择器来指示我们的mount元素,就像我们在Vue 2中使用$mount实例方法一样

代码语言:javascript
复制
import { createApp } from "vue";

const app = createApp({
  // root instance definition
});

app.mount("#app");

改变的原因

在旧的API中,我们添加的任何全局配置(插件、混合、原型属性等)都会永久地改变全局状态。例如:

代码语言:javascript
复制
// Affects both instances
Vue.mixin({ ... })

const app1 = new Vue({ el: '#app-1' })
const app2 = new Vue({ el: '#app-2' })

这在单元测试中确实是一个问题,因为它使确保每个测试与上一个测试隔离变得很棘手。

在新的API下,调用createApp将返回一个新的app实例,该实例不会被应用于其他实例的任何全局配置所污染。

Learn more:Global API change RFC.

添加状态属性

我们的模式窗口可以处于两种状态之一——打开或关闭。让我们用一个布尔状态属性modalOpen来管理它,我们会给它一个初始值false

代码语言:javascript
复制
const app = createApp({
  data: {
    modalOpen: false
  }
});

这是不允许的。相反,必须为数据分配一个返回状态对象的工厂函数。

这是您必须为Vue组件做的事情,但是现在它也对Vue应用程序实例强制执行

代码语言:javascript
复制
const app = createApp({
  data: () => ({
    modalOpen: false
  })
});

Reason for change

使用对象而不是工厂函数的优点是,首先,它在语法上更简单,其次,你可以在多个根实例之间共享顶层状态,例如:

代码语言:javascript
复制
const state = {
  sharedVal: 0
};

const app1 = new Vue({ state });
const app2 = new Vue({ state });

// Affects both instances
app1._data.sharedVal = 1;

这种用例很少,可以使用。因为有两种类型的声明是不适合初学者的,所以决定删除这个特性。

Learn more:Data object declaration removed RFC

在继续之前,让我们添加一个方法来切换modalOpen值。这与Vue 2没有什么不同。

代码语言:javascript
复制
const app = createApp({
  data: () => ({
    modalOpen: true  
  }),
  methods: {
    toggleModalState() {
      this.modalOpen = !this.modalOpen;
    }
  }
});

使用根组件

如果您现在转到浏览器并检查控制台,您将看到警告“组件缺少呈现函数”,因为我们还没有为根实例定义模板。

Vue 2的最佳实践是为根实例创建一个最小的模板,并创建一个应用程序组件,其中将声明主应用程序标记。

我们在这里也做一下。

代码语言:javascript
复制
touch src/App.vue

现在我们可以获得根实例来呈现该组件。不同之处在于,在Vue 2中,我们通常会使用渲染函数来完成以下操作:

代码语言:javascript
复制
import App from "./App.vue";

const app = createApp({
  ...
  render: h => h(App)
});

app.mount("#app");

我们仍然可以这样做,但是Vue 3有一个更简单的方法——让应用程序成为一个根组件。为此,我们可以删除根实例定义并传递App组件。

代码语言:javascript
复制
import App from "./App.vue";

const app = createApp(App);

app.mount("#app");

这意味着App组件不仅由根实例呈现,而且是根实例。

在此过程中,让我们通过删除app变量来简化一下语法:

代码语言:javascript
复制
createApp(App).mount("#app");

现在移动到根组件,让我们重新添加状态和方法到这个组件:

代码语言:javascript
复制
<script>
export default {
  data: () => ({
    modalOpen: true  
  }),
  methods: {
    toggleModalState() {
      this.modalOpen = !this.modalOpen;
    }
  }
};
</script>

让我们也为模态特性创建一个新组件:

代码语言:javascript
复制
touch src/Modal.vue

现在,我们将提供一个包含内容插槽的最小模板。这确保了我们的模式是可重用的。稍后我们将向该组件添加更多内容。

代码语言:javascript
复制
<template>
  <div class="modal">
    <slot></slot>
  </div>
</template>

Multi-root模板

现在让我们为根组件创建模板。我们将创建一个按钮来打开模态,它将触发toggleModalState方法

我们还将使用刚刚创建的模态组件,它将根据modalState的值呈现。我们还可以在内容槽中插入一段文本。

代码语言:javascript
复制
<template>
  <button @click="toggleModalState">Open modal</button>
  <modal v-if="modalOpen">
    <p>Hello, I'm a modal window.</p>
  </modal>
</template>
<script>
import Modal from "./Modal.vue";
export default {
  components: {
    Modal
  },
  ...
}
</script>

注意到这个模板有什么奇怪的地方吗?看一遍。我将等待。

没错,有两个根元素。在Vue 3中,由于一个称为fragment的特性,它不再强制拥有单个根元素!

使用复合API重构

Vue 3的旗舰特性是复合API。这个新的API允许您使用setup函数定义组件功能,而不是使用添加到组件定义对象的属性。

现在,让我们重构应用程序组件,以使用复合API。

在我解释代码之前,要清楚我们所做的一切都是重构——组件的功能是相同的。还要注意,模板没有改变,因为复合API只影响我们定义组件功能的方式,而不是我们呈现它的方式。

代码语言:javascript
复制
<template>
  <button @click="toggleModalState">Open modal</button>
  <modal v-if="modalOpen">
    <p>Hello, I'm a modal window.</p>
  </modal>
</template>
<script>
import Modal from "./Modal.vue";
import { ref } from "vue";
export default {
  setup () {
    const modalState = ref(false);
    const toggleModalState = () => {
      modalState.value = !modalState.value;
    };
    return {
      modalState,
      toggleModalState
    }
  }
};
</script>

setup method

首先,请注意我们导入了ref函数,该函数允许我们定义一个反应变量modalState。这个变量等价于This . modalstate。

toggleModalState方法只是一个普通的JavaScript函数。但是,请注意,要更改方法体中的modalState的值,我们需要更改它的子属性值。这是因为使用ref创建的反应变量被包装在一个对象中。这对于保持它们在传递过程中的活性是必要的。

如果您想详细了解refs的工作方式,最好查阅Vue Composition API文档。

最后,我们从setup方法返回modalState和toggleModalState,因为它们是在模板呈现时传递给模板的值。

Reason for change

请记住,组合API不是一个更改,因为它完全是可选的。主要动机是考虑更好的代码组织和组件之间的代码重用(因为mixin本质上是一种反模式)

如果您认为在本例中重构应用程序组件以使用复合API是不必要的,那么您是正确的。但是,如果这是一个更大的组件,或者我们需要与其他组件共享它的特性,那么您就会看到它的有用性。

提供更深入的示例超出了本文的范围,所以如果您有兴趣了解更多关于新API的使用,请参阅我的另一篇文章,了解何时使用新Vue复合API(以及何时不使用)。

传送内容

如果您以前创建过模态特性,您就会知道它通常被放置在关闭的标记之前。

代码语言:javascript
复制
<body>
  <div>
    <!--main page content here-->
  </div>
  <!--modal here-->
</body>

这样做是因为情态动词通常有一个页面覆盖的背景(如果你不明白我的意思,请参阅开头的图片)。要使用CSS实现这一点,您不需要处理父元素定位和z-index叠加上下文,因此最简单的解决方案是将模态放在DOM的最底部。

这就与Vue产生了问题。不过,它假设UI将被构建为一个组件树。为了允许树的片段移动到DOM中的其他位置,Vue 3中添加了一个新的传送组件

要使用传送,让我们首先向页面添加一个元素,我们希望将模态内容移动到该页面。我们将转到index.html,并在Vue的挂载元素旁边放置一个带ID modal-wrapper的div。

代码语言:javascript
复制
<body>
  ...
  <div id="app"></div><!--Vue mounting element-->
  <div id="modal-wrapper">
    <!--modal should get moved here-->
  </div>
</body>

现在,回到App.vue,我们将把模态内容包装在传送组件中。我们还需要指定一个to属性,它将被分配一个用于标识目标元素的查询选择器,在本例中是#modal-wrapper。

代码语言:javascript
复制
<template>
  <button @click="toggleModalState">Open modal</button>
  <teleport to="#modal-wrapper">
    <modal v-if="modalOpen">
      <p>Hello, I'm a modal window.</p>
    </modal>
  </teleport>
</template>

就是这样。传送中的任何内容都将在目标元素中呈现。然而,它仍然会像它在层级中的最初位置一样工作(关于道具,事件等)。

因此,在您保存代码之后,重新加载页面,在开发工具中检查DOM,您会感到惊讶!

Learn more:Teleport RFC

发出一个事件

现在让我们在模态中添加一个按钮来关闭它。为此,我们将向modal tempate添加一个按钮元素,并使用一个发出事件close的click处理程序。

代码语言:javascript
复制
<template>
  <div class="modal">
    <slot></slot>
    <button @click="$emit('close')">Dismiss</button>
  </div>
</template>

然后父组件将捕捉此事件,并切换modalState的值,使其在逻辑上为假,并导致窗口关闭。

代码语言:javascript
复制
<template>
  ...
    <modal 
      v-if="modalOpen" 
      @click="toggleModalState"
    >
      <p>Hello, I'm a modal window.</p>
    </modal>
  </teleport>
</template>

到目前为止,这个特性与Vue 2中的特性完全相同。但是,在Vue 3中,现在建议您使用新的component选项显式地声明组件的事件。就像使用道具一样,您可以简单地创建一个字符串数组来命名组件将发出的每个事件

代码语言:javascript
复制
<template>...</template>
<script>
export default {
  emits: [ "close" ]
}
</script>

Reason for change

想象一下,打开别人编写的组件文件,并查看显式声明的组件的道具和事件。马上,您就会理解这个组件的接口,即它要发送和接收什么。

除了提供自我记录的代码之外,您还可以使用事件声明来验证事件负载,尽管在本例中我找不到这样做的理由。

Learn more:Emits Option RFC

样式槽内容

为了使我们的模式可重用,我们为内容提供了一个插槽。让我们通过向组件添加样式标签来开始对该内容进行样式化。

在我们的组件中使用限定范围的CSS是一个很好的实践,以确保我们提供的规则不会对页面中的其他内容产生意外的影响

让我们把任何段落文本放到槽里都改成斜体。为此,我们将使用p选择器创建一个新的CSS规则。

代码语言:javascript
复制
<template>...</template>
<script>...</script>
<style scoped>
  p {
    font-style: italic;
  }
</style>

如果你试一下,你会发现它不起作用。问题是,当槽内容仍然属于父内容时,在编译时确定了作用域样式。

Vue 3提供的解决方案是提供一个伪选择器::v- sloated(),允许您使用提供插槽的组件中的作用域规则来锁定插槽内容。

Here's how we use it:

代码语言:javascript
复制
<style scoped>
  ::v-slotted(p) {
    font-style: italic;
  }
</style>

Vue 3 also includes some other new scoped styling selectors::v-deepand::v-globalwhich you can learn more about here:Scoped Styles RFC

Other changes

好了,这就是我可以在一个简单的例子中介绍的所有新特性。我得到了大部分主要的,但这里有一些我认为重要到足以在结束文章之前提到,你可以自己研究:

Added:

Removed:

  • Filters
  • Inline templates
  • Event interface for components (no more event bus!)

Changed:

  • Async component API
  • Custom directive API
  • Render function syntax

There are also various changes regarding Vue Router but I'll be dedicating a separate article to those!

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-05-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 CryptoCode 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 如何构建
  • Vue3.0的安装与启动
  • 创建一个新的 vue3.0 app
  • 改变的原因
  • 添加状态属性
  • Reason for change
  • 使用根组件
  • Multi-root模板
  • 使用复合API重构
  • setup method
  • Reason for change
  • 传送内容
  • 发出一个事件
  • Reason for change
  • 样式槽内容
  • Other changes
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档