前端大事件

就在本月的20号,vue框架作者尤雨溪在知乎发布了一篇文章,在该篇文章中宣告vue的又一巨大革新。

尤大在文章中提到,Vue 3 将在 2022 年 2 月 7 日 成为新的默认版本!以下是部分原文:

“软发布” 的过程比预期要长,但这个时刻终于到了:
我们很高兴地宣布,Vue 3 将在 2022 年 2 月 7 日 成为新的默认版本。

除了 Vue 核心库以外,我们还几乎改进了框架的每个方面。
· 基于 Vite 的极速构建工具链
· <script setup> 带来的开发体验更丝滑的组合式 API 语法
· Volar 提供的单文件组件 TypeScript IDE 支持
· vue-tsc 提供的针对单文件组件的命令行类型检查和生成
· Pinia 提供的更简洁的状态管理
· 新的开发者工具扩展,同时支持 Vue 2/Vue 3,并且提供一个插件系统来允许社区库自行扩展开发者工具面板。

我们还彻底重写了主文档。全新的 vuejs.org (目前处于待发布状态,中文版的翻译还在进行中) 将提供最新的框架概述与开发建议、
针对不同背景的用户的灵活的学习路径,在整个指南与示例中都能够在选项式 API 和组合式 API 之间进行切换,以及许多新的深入章节。
新文档本身的网站性能也非常优秀——我们将在不久后的另一篇博文中详细探讨一下。
…………

详细内容可以参考原文 Vue 3 将成为新的默认版本

这可以说是vue框架自诞生以来最为劲爆的一则消息了。vue3从2018年开始提出构造,到2020年9月正式发布3.0版本,两年多的开发成本不可谓不低。然而即使携带着前瞻的composition-api思想和一系列性能优化及生态革新, 最初发布的vue3.0并没有得到大多数开发者的青睐,与以往大相径庭的编程样式和不稳定性让他们更多的选择保持vue2.x。

但是又经过一年多的沉淀,在今年的新年之际,vue终于抛弃2.0,迎来3.0的主场。vue3是以解决vue2.0开发大型复杂项目产生的代码逻辑分散性高的目的诞生的,全新的composition-api较以往的options-api有着完全的进步,如今vue3的生态圈也进一步完善,对ts的支持也不再残疾,相信vue3一定会在国内乃至全球范围产生一定影响力。

简要谈谈一些变化

vue3与vue2不同的内核标志着与之关联紧密的生态圈必然也将发生较大的变化,下面简要谈谈必要的一些改变。

1. <script setup> 语法糖

组合式api初识

composition-api与options-api在表现形式上的最大不同就是其更像函数式编程,所有业务逻辑均写在setup(prop,context)函数中,不再区分data,methods,props,watch等等。这个更改的好处就是代码关联性更强,逻辑相关的代码位置相近,方便书写及查找、维护。

常规写法类似如下:

<script>
import { reactive, ref, computed } from "vue";
export default {
  name: "Hello1",
  // 接收父组件传递的数据
  props: {
    msg: {
      type: String,
    },
    code: {
      type: Number,
    },
  },
  //声明要向父组件传递的自定义事件
  emits: ["test"],
  setup(props, context) {
    // 计算属性
    let completeMsg = computed(() => {
      return props.msg + props.code;
    });
    // 利用context抛出事件
    function click_() {
      context.emit("test", "waga");
    }
    // 将数据及方法return 出去
    return {
      click_,
      completeMsg,
    };
  },
};
</script>

可以看到此时的写法还是有些options-api的影子,export defalut导出一个组件对象,里面有各种属性包括setup()函数等,而且在setup()最后还要将dom元素使用到的数据及方法return出去,还是有些繁琐的,这也是我在学习vue3时看到不少一起学习的网友经常吐槽的点。

使用setup标注

使用了setup标志的<script>标签会将标签内的代码封装为setup函数,并采用了宏定义及api的方式提供prop,emits的获取,末尾也不用再麻烦的return出去,你要做的只是处理逻辑,不必再关心js/ts代码的结构,setup语法糖已经帮开发者进行了屏蔽。

下面给出一个使用setup语法糖的demo:

<script setup>
// 导入所需方法及组件
import { ref, reactive, onBeforeMount, onMounted,computed } from 'vue';
import TabBar from '@/components/TabBar.vue';
import TabBarItem from '@/components/TabBarItem.vue';
import { testStore } from '@/store/index.js';

// vue3全新生命周期钩子 对标vue2 created
onMounted(() => {
  const test_store_ins = testStore();
  test_store_ins.set_major("动画制作");
  test_store_ins.set_grade(2019);
})

// 声明响应式数据
const num = ref(180);
const person = reactive({
    name:"dio"
    age:22,
    stand:{
        name:"the world",
        damage:120
    }
})

// 宏定义获取props
const props = defineProps({
	color: String
})

// 计算属性
const bg_color = computed(() => {
	return `background-color:${props.color}`;
})
</script>

可以看到所有js代码只需要按顺序书写即可,不必再考虑应该放置在哪个板块中,setup标注帮开发者封装的很彻底,相较于options-api,开发及维护体验都有了良好的提升。除上述demo所引用的功能外,原本vue2内置的所有属性都可以在vue3的vue模块中找到相应的api并进行引用,(比如watch等)

2. vue-router@4

vue-router作为vue单页应用中进行路由跳转的插件,在4.0版本前提供对vue2的支持,在进入vue3的时代后,vue-router也更新到4.x版本已提供对vue3的支持。

vue4较先前版本有着诸多破坏式不兼容的变更,拿比较显著的几个方面作个例子:

实例创建方式

在vue-router4以前,创建一个vue-router实例采用的是调用构造函数

// 构造函数实例化
const Router=new VueRouter({
    routes
})

来到vue-router4后,实例创建方式改为调用createRouter方法;

const Router = createRouter({
    route
})

mode属性变更为history

history属性已替代mode属性用于表示浏览器历史记录模式
原本的三种模式分别由vue-router库中的三个函数表示:

  • "history": createWebHistory()
  • "hash": createWebHashHistory()
  • "abstract": createMemoryHistory()
import { createRouter, createWebHistory } from 'vue-router'
// 还有 createWebHashHistory 和 createMemoryHistory

createRouter({
  history: createWebHistory(),
  routes: [],
})

其他详细

可以参考 从vue2迁移-vue-router

3. vuex@4

官网中迁移部分提到:

Almost all Vuex 4 APIs have remained unchanged from Vuex 3. 
However, there are still a few breaking changes that you must fix.

vuex4较3版本并无太大变化,简而言之即兼容度极高。对此感兴趣想详细了解的可以参考 从vue2迁移-vuex

4. pinia

尤大在这次宣告中也提到了一个新技术栈——pinia , 这是由vuex团队核心团队的成员开发的另一款vue状态管理插件,对标vuex5, 超越vuex4。pinia较目前的vuex4在诸多方面有更强的功能及优势。官网也给出了明确的描述:

Pinia API is very different from Vuex ≤4, namely:

  • mutations no longer exist. They were very often perceived as extremely verbose. They initially brought devtools integration but that is no longer an issue.
  • No need to create custom complex wrappers to support TypeScript, everything is typed and the API is designed in a way to leverage TS type inference as much as possible.
  • No more magic strings to inject, import the functions, call them, enjoy autocompletion!
  • No need to dynamically add stores, they are all dynamic by default and you won't even notice. Note you can still manually use a store to register it whenever you want but because it is automatic you don't need to worry about it.
  • No more nested structuring of modules. You can still nest stores implicitly by importing and using a store inside another but Pinia offers a flat structuring by design while still enabling ways of cross composition among stores. You can even have circular dependencies of stores.
  • No namespaced modules. Given the flat architecture of stores, "namespacing" stores is inherent to how they are defined and you could say all stores are namespaced.

翻译下来大概有如下区别:

  • 突变不再存在。他们经常被认为非常冗长。他们最初带来了 devtools 集成,但这不再是问题。
  • 无需创建自定义的复杂包装器来支持 TypeScript,所有内容都是类型化的,并且 API 的设计方式尽可能地利用 TS 类型推断
  • Pinia 不支持嵌套存储。相反,它允许你根据需要创建store。但是,store仍然可以通过在另一个store中导入和使用store来隐式嵌套
  • 存储器在被定义的时候会自动被命名。因此,不需要对模块进行明确的命名。
  • Pinia允许你建立多个store,让你的捆绑器代码自动分割它们
  • Pinia允许在其他getter中使用getter
  • Pinia允许使用 $patch 在devtools的时间轴上对修改进行分组。

简单使用下来最为直接的感觉就是代码比vuex更简短了,vuex的不同modules多放在不同js文件中再进行集成,代码复杂且集成后的state,mutations等仍属于同一store。

pinia提供了多store的书写方式,切实做到了store的分类,逻辑关联的内容封装为一个个独立的store, 使用更轻巧。

import { defineStore } from "pinia";

// 学生相关的store属性、方法
export const stuStore = defineStore({
  id: "global_stu",
  state: () => {
    major: String;
    grade: Number;
  },
  getters: {
    SchoolAndMajor(state) {
      return `${state.grade}级${state.major}专业`;
    },
  },
  actions: {
    set_major(val) {
      this.major = val;
    },
    set_grade(val) {
      this.grade = val;
    },
  },
});

// 角色相关的store属性、方法
export const roleStore = defineStore({
  id: "global_role",
  state: () => {
    name: String;
    apperance: Number;
    gender: String;
  },
  getters: {
    RoleInfo(state) {
      return `角色名${state.name},性别${state.gender}`;
    },
  },
  actions: {
    set_name(val) {
      this.name = val;
    },
    set_apperance(val) {
      this.apperance = val;
    },
  },
});

更多细节请查阅 pinia官方文档

5. element-ui

element-ui作为vue开发者常用的ui库,其简易、灵活、轻巧先进的组件能在提供美观界面的同时提供全面而强大的功能。

由于vue3.0在插件install函数的入参从Vue原型(类)改成了app(vue实例e)。导致element-ui中Vue.prototype.* 这样的代码已经全都失效了, 标示着element-ui并不兼容vue3。

好在element-ui团队早已马不停蹄地肝,如今已产出了element vue3
适配版 element-plus。不过目前该项目仍处于beta测试版,还不稳定,之前去官网看了一眼,赋值粘贴就能用的字体图标居然也给摒弃了,希望element-plus还能维持以往友好的特性吧。

6. Typescript

遥想还在vue2时期,在项目中引入ts,需要vue-property-decorator插件提供支持,再在代码中用一系列装饰器进行标注,搞得和写springboot的注解开发似的,vue2对ts的支持可谓缺胳膊少腿,前端开发人员们苦不堪言。

vue3改变了底层逻辑,从根本上提供了对ts的支持, 并且专门开发了官方vscode插件volar 来为ts项目提供强大的多功能服务,( 详细内容可以参考这篇文章关于volar ) 现在使用vue3开发ts项目可谓是如虎添翼,前端开发者的体验将有质的飞跃。