Vue 3.0 新特性及使用方法

介绍

2020年9月19日凌晨,尤雨溪大大正式发布了 Vue.js 3.0 版本,代号:One Piece。此框架新的主要版本提供了更好的性能、更小的捆绑包体积、更好的 TypeScript 集成、用于处理大规模用例的新 API,并为框架未来的长期迭代奠定了坚实的基础。

3.0 版本的开发周期长达两年多,期间产生了 30+ RFCs、2600+ commits、628 pull requests,以及核心仓库之外的大量开发和文档工作。

Vue 3.0 的发布标志着此框架整体上已处于可用状态。尽管框架的某些子项目可能仍需要进一步的开发才能达到稳定状态(特别是 devtools 中的路由和 Vuex 集成),不过现在仍然是开始使用 Vue 3 启动新项目的合适时机。官方还鼓励库作者现在可以开始升级项目以支持 Vue 3。

what is RFC?

RFC(Request For Comments) - 即请求评议,旨在为新功能进入框架提供一致且受控的路径。

The "RFC" (request for comments) process is intended to provide a consistent and controlled path for new features to enter the framework.
Many changes, including bug fixes and documentation improvements can be implemented and reviewed via the normal GitHub pull request workflow.
Some changes though are "substantial", and we ask that these be put through a bit of a design process and produce a consensus among the Vue core team and the community.

RFC 为新功能的引入提供了统一可控的途径,利于在Vue核心团队和社区中进行方案的讨论和优化,最终达成共识。

The RFC life-cycle

An RFC goes through the following stages:

  • Pending: when the RFC is submitted as a PR.
  • Active: when an RFC PR is merged and undergoing implementation.
  • Landed: when an RFC's proposed changes are shipped in an actual release.
  • Rejected: when an RFC PR is closed without being merged.

如何参与

提出RFC pull request前,先在issue中讨论该问题,然后提出RFC PR,PR中包含一个 RFC的markdown文件(非实际代码),经过讨论后核心团队最终将决定是否接受或拒绝该RFC。RFC的提出者并不一定需要自己去实现它(当然欢迎实现)。

Vue RFCs 仓库

创建Vue3.0项目

  • 通过脚手架 vite 安装:
npm init vite-app hello-vue3 # OR yarn create vite-app hello-vue3

Vite is an opinionated web dev build tool that serves your code via native ES Module imports during dev and bundles it with Rollup for production.

Vite目前仅支持 Vue 3.x以上,这意味着你不能使用不兼容Vue 3的组件库

目前基于Vue的第三方组件库兼容Vue 3的情况:

Ant Design Vue:支持 Vue 3.0 的 2.0.0 测试版已发布

ElementUI:尚未支持

MintUI:尚未支持

iView(ViewUI):尚未支持

Vue2-leaflet:很明显不支持

  • 通过脚手架 vue-cli 安装:

首先全局更新最新版的 Vue CLI,4.5.0以上版本支持 Vue3:


npm install -g @vue/cli # OR yarn global add @vue/cli
vue create hello-vue3
# select vue 3 preset

Vue2.x 项目升级为 Vue3.x项目

最简单的方法,就是使用vue-cli 3.0,创建一个新的项目,然后将原有的项目源码拷到新的项目中。

Vue3中兼容Vue2中定义组件的写法,所以只需要将入口文件 main.js 中创建Vue实例的代码替换为使用Vue3中新引入的 createApp方法,来创建应用程序实例的方式即可。

Vue 2 main.js:

import Vue from 'vue'
import App from './App.vue'

new Vue({
    render: h => h(App),
}).$mount('#app')

Vue 3 main.js:

import { createApp } from 'vue'
import App from './App.vue'

createApp(App).mount('#app')

值得注意的Vue3 新特性

Composition API(组合 API):

当组件变得越来越大时,逻辑关注点的列表也会增长。这可能会导致组件难以阅读和理解,且碎片化使得理解和维护复杂组件变得困难。选项的分离掩盖了潜在的逻辑问题。此外,在处理单个逻辑关注点时,我们必须不断地“跳转”相关代码的选项块。

如果能够将与同一个逻辑关注点相关的代码配置在一起会更好,于是 Composition API 应运而生。

使用Composition api的位置被称为setup

setup组件选项

setup 组件选项在创建组件之前执行,一旦 props 被解析,并充当合成 API 的入口点。

注意:由于在执行 setup 时尚未创建组件实例,因此在 setup 选项中没有 this。这意味着,除了 props 之外,你将无法访问组件中声明的任何属性——本地状态、计算属性或方法。

// src/components/UserRepositories.vue `setup` function
import { fetchUserRepositories } from '@/api/repositories'
import { ref, onMounted } from 'vue'

// in our component
export default {
    setup (props) {
      const repositories = ref([]) // 定义一个变量
      const getUserRepositories = async () => { // 定义一个方法
        repositories.value = await fetchUserRepositories(props.user)
      }

      onMounted(getUserRepositories) // 生命周期钩子 当实例mounted后调用getUserRepositories方法

      return {
        repositories, // 返回一个data
        getUserRepositories // 返回一个method
      }
    }
}

单文件组件 Composition API 语法糖 (<script setup>):

当组件可以使用组合API后,setup往往成为了唯一会用到的组件属性,因此利用语法糖简化setup的写法

<template>
  <button @click="inc">{{ count }}</button>
</template>

// Composition API
<script>
export default {
  setup() {
    const count = ref(0)
    const inc = () => count.value++

    return {
      count,
      inc,
    }
  },
}
</script>
// 使用了 Composition API 语法糖:
<script setup>
  import { ref } from 'vue'

  export const count = ref(0)
  export const inc = () => count.value++
</script>

单文件组件状态驱动的 CSS 变量 (<style vars>):

有能力在运行时根据组件状态来动态更新样式

<template>
  <div class="text">hello</div>
</template>

<script>
export default {
  data() {
    return {
      color: 'red'
    }
  }
}
</script>

<style vars="{ color }">
.text {
  color: var(--color);
}
</style>

单文件组件 <style scoped> 现在可以包含全局规则或只针对插槽内容的规则:

带有scoped属性的style 不再只能作用域当前单文件组件,通过深度选择器、插槽选择器、全局选择器拥有了更改其他范围样式的能力。

<style scoped>
/* deep selectors */
::v-deep(.foo) {}
/* shorthand */
:deep(.foo) {}

/* targeting slot content */
::v-slotted(.foo) {}
/* shorthand */
:slotted(.foo) {}

/* one-off global rule */
::v-global(.foo) {}
/* shorthand */
:global(.foo) {}
</style>

Vue 3的重大改变

引入createApp

背景:

从技术上讲,Vue 2 没有“app”的概念,我们定义的应用程序只是通过 new Vue() 创建的根 Vue 实例。从同一个 Vue 构造函数创建的每个根实例共享相同的全局配置,因此全局配置使得在测试期间很容易意外地污染其他测试用例。用户需要仔细存储原始全局配置,并在每次测试后恢复 (例如重置 Vue.config.errorHandler)。有些 API 像 Vue.use 以及 Vue.mixin 甚至连恢复效果的方法都没有,这使得涉及插件的测试特别棘手。

createApp:

import { createApp } from 'vue'

const app = createApp({})

调用 createApp 返回一个应用实例,应用程序实例暴露当前全局 API 的子集,任何全局改变 Vue 行为的 API 现在都会移动到应用实例上,以下是当前全局 API 及其相应实例 API 的表:

[图片上传失败...(image-c4a9d6-1601349914900)]

所有其他不全局改变行为的全局 API 现在被命名为 exports。

全局和内部API已重构为可 tree-shakable

Tree shaking 是一个通常用于描述移除 JavaScript 上下文中的未引用代码(dead-code) 行为的术语。
它依赖于ES2015中的 import 和 export 语句,用来检测代码模块是否被导出、导入,且被 JavaScript 文件使用。
在现代 JavaScript 应用程序中,我们使用模块打包(如webpack或Rollup)将多个 JavaScript 文件打包为单个文件时自动删除未引用的代码。这对于准备预备发布代码的工作非常重要,这样可以使最终文件具有简洁的结构和最小化大小。

2.x 语法:

// 全局 API Vue.nextTick() 不能tree-shaking
import Vue from 'vue'

Vue.nextTick(() => {
  // 一些和DOM有关的东西
})

3.x语法:

全局 API 现在只能作为 ES 模块构建的命名导出进行访问,如果模块绑定器支持 tree-shaking,则 Vue 应用程序中未使用的全局 api 将从最终捆绑包中消除,从而获得最佳的文件大小。

import { nextTick } from 'vue'

nextTick(() => {
  // 一些和DOM有关的东西
})

受影响的API:

  • Vue.nextTick
  • Vue.observable (用Vue.reactive替换)
  • Vue.version
  • Vue.compile
  • Vue.set
  • Vue.delete

组件上 v-model 用法已更改

  • 自定义v-model时,prop和事件默认名称已更改:
    prop: value -> modelValue
    event: input -> update:modelValue
  • .sync和组件的model选项已移除,可用v-model作为替代
  • 现在可以在同一个组件上使用多个 v-model 进行双向绑定;
  • 现在可以自定义 v-model 修饰符
    比如自定义v-model.capitalize,绑定为字符串第一个字母的大写

<template v-for> 和非 - v-for 节点上 key 用法已更改

  • Vue 2.x 建议在 v-if/v-else/v-else-if 的分支中使用 key,Vue 3.x 中仍能正常工作,但不再建议,因为没有为条件分支提供 key 时,也会自动生成唯一的 key。

  • 在 Vue 2.x 中 <template> 标签不能拥有 key,在 Vue 3.x 中 key 则应该被设置在 <template> 标签上。

在同一元素上使用的 v-if 和 v-for 优先级已更改

  • Vue 3.x 中v-if 会拥有比 v-for 更高的优先级。
    由于语法上存在歧义,建议避免在同一元素上同时使用两者,比如利用计算属性筛选出列表。

v-bind="object" 现在排序敏感

  • Vue 2.x 如果一个元素同时定义了 v-bind="object" 和一个相同的单独的 property,那么这个单独的 property 总是会覆盖 object 中的绑定。
  • Vue 3.x 声明绑定的顺序决定了它们如何合并。
// 2.x中 id最终为red  3.x中 id为blue
<div id="red" v-bind="{ id: 'blue' }"></div>

v-for 中的 ref 不再注册 ref 数组

  • Vue 2 中,在 v-for 里使用 ref属性时,从$refs中获取的相应属性会是一个ref数组。

  • Vue 3中则将ref绑定到一个更灵活的函数上 (ele) => { ...//保存ele的操作 }:

    template:

    <div v-for="item in list" :ref="setItemRef"></div>
    

    script:

    import { ref, onBeforeUpdate, onUpdated } from 'vue'
    
    export default {
      setup() {
        let itemRefs = []
        const setItemRef = el => {
          itemRefs.push(el)
        }
        onBeforeUpdate(() => {
          itemRefs = []
        })
        onUpdated(() => {
          console.log(itemRefs)
        })
        return {
          itemRefs,
          setItemRef
        }
      }
    }
    

官方库的支持情况

所有的官方库和工具现在都支持 Vue 3,但大多数仍然处于 beta 状态,并在 NPM 的 next dist 标签下发。计划在 2020 年底前稳定所有项目,并将其转换为使用 latest 的 dist 标签。

Vue Cli

从 v4.5.0 开始,vue-cli 现在提供了内置选项,可在创建新项目时选择 Vue 3 预设。现在可以升级 vue-cli 并运行 vue create 来创建 Vue 3 项目。

Vue Router

Vue Router 4.0 提供了 Vue 3 支持,并有许多突破性的变化。

Vuex

Vuex 4.0 提供了 Vue 3 支持,其 API 与 3.x 基本相同。唯一的突破性变化是插件的安装方式。

Devtools Extension

正在开发一个新版本的 Devtools,目前只支持Vue 3。

IDE 支持

推荐使用 VSCode 和官方拓展 Vetur,Vetur为 Vue 3 提供了全面的 IDE 支持

参考

vue3 中文文档

vue-router 4.0 英文文档

Vuex 4 README

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269