迟到的 Vue3.0 与 Vite 的体验学习总结

尤大的 Vue3.0 已经发布有一阵子了, 已经很成熟了。今天想起来,是时候该上手体验一波了。

Vue3中文文档 - vuejs



一、Vue3.0 亮点

  1. Performance:性能更比Vue 2.0强;
  2. Tree shaking support:可以将无用模块“剪辑”,仅打包需要的;
  3. Composition API:组合式API;
  4. Fragment, Teleport, Suspense:“碎片”,Teleport 即 Protal 传送门,“悬念”;
  5. Better TypeScript support:更优秀的Ts支持;
  6. Custom Renderer API:暴露了自定义渲染API;

二、Vue3.0 项目初始化

  • 使用 vue-cli 脚手架

    1. 安装 vue-cli 脚手架
    $ npm install -g @vue/cli
    

    安装成功后,使用 vue -V 命令,查看是否安装成功:

    $ vue -V
    @vue/cli 4.5.9
    

    如果没有安装成功或者是还是2.0版本的,那么我们要将他升级到 3.0。
    先将已有的 vue-cli 卸载,然后重新安装即可。

    $ npm uninstall vue-cli -g
    
    2. 创建 vue3.0 项目
    $ vue create vue3-demo
    

    在出现的命令交互窗口选择 Manually select features:

    然后勾选:Router、Vuex、CSS Pre-processors 和 Linter / Formatter等内容。

    回车后根据自己的习惯选择好,就开始创建项目。
    在这里插入图片描述

    选择vue版本:
    在这里插入图片描述

    安装完成之后就可以直接创建 vue3.0 的项目了,通过命令进行后续操作了。
    通过下面两个命令就可以启动 vue3.0 的项目了。

     $ cd vue3-demo
     $ npm run serve
    

    成功运行项目:
    在这里插入图片描述

  • 使用 Vite 创建 Vue3.0 项目(详细实例应用请移步至:Vue3应用之使用Vite搭建Vue3项目

    1. 全局安装Vite

    npm install -g create-vite-app
    

    2. 使用Vite创建Vue3项目

    create-vite-app projectName
    

    3. 安装依赖运行项目

    cd vite-app
    npm install (or `yarn`)
    npm run dev (or `yarn dev`)
    

    4. 引入 Vue Router4 路由

    1. 查看 vue-router 所有版本号

      npm info vue-router versions
      

      查看 vue-router 所有版本号

    2. 安装最新的 vue-router

      yarn add vue-router@4.0.2
      

    项目运行成功:
    在这里插入图片描述

下面就开始干我们的正事了。。。


三、Vue3.0 新特性分析

1. 创建实例

在 Vue3 中每个 Vue 应用都是通过用 createApp 函数创建一个新的实例,不在通过 new 的方式进行创建:

Vue3创建实例的方式:

// src/main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'

createApp(App).use(store).use(router).mount('#app')

Vue2 通过函数式创建实例:、

new Vue({
  el: '#app',
  router,
  store,
  render: h => h(App)
})

2. 创建路由

现在创建路由实例需要手动引入 createRouter 方法,创建 history 模式路由也需要手动引入 createWebHistory 方法,这达到 Tree-Shaking 的目的,即不会把所有的 api 都打包进来,只会打包你用到的 api,vue3 将都会使用这种形式。

import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
  }
]

const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes
})

export default router

3. 响应式数据和事件绑定

Vue 3.0 中初始化状态通过 setup() 方法,定义状态需要调用 ref() 方法。
这就跟在 vue2 中有很大的不同,vue2 中我们是使用选项的方式来创建 datamethodswatchcomputed 的。

<template>
  <div>
      {{count}}
      {{str}}
      <button @click="add">add</button>
  </div>
</template>

<script>
import { ref } from 'vue';
export default {
    setup() {
        const count = ref(0); // 声明count,初始值为 0
        const str = ref('hello'); // 声明str,初始值为 'hello'
        const add = () => {	// 定义一个事件,用来更新count状态
            count.value ++;	// 更新count值的时候不能直接使用count++,而应使用 count.value++
        }
        return {
            count,
            str,
            add
        }
    },
}
</script>

4. 使用 reactive 声明响应式数据

使用 reactive 来一次声明多个变量

import { reactive } from 'vue'
export default {
  setup () {
    // 引入 reactive,同时定义多个变量
    const state = reactive({
      count: 0,
      str: 'hello'
    })
 
    // 现在访问变量,不能使用 .value 方式访问了
    const add = () => {
      // state.count.value++ // 错误
      state.count++
    }
 
    return {
      state,
      add
    }
  }
}

reactiveref 比较

  • reactive 是接收一个普通对象,返回该对象的响应式代理,它等同于 2.x 中的 Vue.observable()

    const obj = reactive({ count: 0 })
    // obj 此时是一个响应式的对象
    // 访问或修改,直接基于 obj.count
    
  • ref 也是接收一个参数并返回一个响应式且可改变的 ref 对象,一般参数是基础类型。
    如果传入的参数是一个对象,将会调用 reactive 方法进行深层响应转换。ref 对象拥有一个指向内部值的单一属性 .value,即当你要访问它的值时,需要 .value 拿到它的值。但是如果是在 setup 中返回且用到模板中时,在 {{}} 里不需要加 .value 访问,在返回时已经自动解套。

    setup() {
    	return {
    		count: ref(0), // 这里返回,在模板中无需 .value 访问值
    	}
    },
    

5. watchcomputed

在 Vue3 中使用监听器和计算属性,也需要手动引入,且 watchcomputed 都需要在 setup 中进行。

import { ref, watch, computed } from 'vue';
export default {
    setup() {
        const count = ref(0);
        const add = () => {
            count.value ++;
        }
        
        // 监听器 watch 同样是一个方法,它包含 2 个参数,2 个参数都是 function
        // 第一个参数是监听的值,count.value 表示当 count.value 发生变化就会触发监听器的回调函数,即第二个参数,第二个参数可以执行监听时候的回调
        watch(
	      () => count.value,  
	      (val, oldVal) => {
	        console.log(`new count: ${val},old count: ${oldVal}`);
	      }
	    );
	    
	    // 计算属性 computed 是一个方法,里面需要包含一个回调函数,当我们访问计算属性返回结果时,会自动获取回调函数的值:
	    const doubleCount = computed(() => {
	      return count.value * 2;
	    });
        return {
            count, 
            add,
            doubleCount
        }
    },
}

如果是 2 个以上的监听属性:

watch(
  [refA, () => refB.value],
  ([a, b], [prevA, prevB]) => {
    console.log(`a is: ${a}`)
    console.log(`b is: ${b}`)
  }
)

6. 获取路由信息

vue3.0 中使用 getCurrentInstance 方法获取当前组件实例,然后通过 ctx 属性获取当前上下文,ctx.$router 是路由实例,而 ctx.$router.currentRoute 就包含当前路由信息。

import { getCurrentInstance } from 'vue'
export default {
  setup () {
    const { ctx } = getCurrentInstance()
    console.log(ctx.$router.currentRoute.value)
  }
}

7. Vuex

在学习 Vue3 的 Vuex 4 之前,先来看一下 Vue2 的 Vuex 3:
可以发现创建 store 实例的方式改变了,vue2 中是使用 new 的方式进行创建的

export default new Vuex.Store({
   // ... 
})

看完 Vue2 的 Vuex 3,那么继续回到我们 Vue3 的使用。

  1. 定义 Vuex 状态

    state 中创建了一个状态,在 mutations 中添加修改该状态的方法,在actions 中提交 mutation 的方法,而不是直接变更状态。

    import { createStore } from 'vuex'
    
    export default createStore({
      state: {
        count: 0
      },
      mutations: {
        ADD(state) {
          state.count++;
        }
      },
      actions: {
        add({ commit }){
          commit('ADD')
        }
      },
      modules: {
      }
    })
    
    
  2. 更新 Vuex 状态

    方式一:
    在 xx.vue 页面中,通过计算属性使用 Vuex 状态;
    在具体事件中通过 store.dispatch 方法触发 Action。

    <template>
      <div>
        <div>state from vuex {{count}}</div>
        <button @click="add">add</button>
      </div>
    </template>
    
    <script>
    import { computed } from "vue";
    import { useStore } from 'vuex';  // 引入 useStore 方法返回 store 实例
    export default {
      setup() {
        const store = useStore()
        const count = computed(() => store.state.count)
        const add = () => {
          store.dispatch('add')
        }
        return {
          count,
          add,
        };
      },
    };
    </script>
    

    方式二:
    通过获取当前组件实例 ctx,使用 ctx.$store.commit 直接分发 mutations ,但是mutation有个限制:必须同步执行,而 Action 就不受约束,可以在 action 内部执行异步操作。

    <template>
      <div>
        <div>state from vuex {{count}}</div>
        <button @click="add">add</button>
      </div>
    </template>
    
    <script>
    import { computed, getCurrentInstance } from "vue";
    
    export default {
      setup() {
        const { ctx } = getCurrentInstance()
        const count = computed(() => ctx.$store.state.count)
        const add = () => {
          ctx.$store.commit('ADD')
        }
        return {
          count,
          add,
        };
      },
    };
    </script>
    

四、值得注意的新特性

Vue 3 中需要关注的一些新功能包括:


五、非兼容的变更

Global API

  • 全局 Vue API 已更改为使用应用程序实例
  • 全局和内部 API 已经被重构为可 tree-shakable

模板指令

  • 组件上 v-model 用法已更改
  • <template v-for> 和非 v-for 节点上 key 用法已更改
  • 在同一元素上使用的 v-ifv-for 优先级已更改
  • v-bind="object" 现在排序敏感
  • v-for 中的 ref 不再注册 ref 数组

组件

  • 只能使用普通函数创建功能组件
  • functional 属性在单文件组件 (SFC) <template>functional 组件选项被抛弃
  • 异步组件现在需要 defineAsyncComponent 方法来创建

渲染函数

  • 渲染函数 API 改变

  • $scopedSlots property 已删除,所有插槽都通过 $slots 作为函数暴露

  • 自定义指令 API 已更改为与组件生命周期一致

  • 一些转换 class 被重命名了:

    • v-enter -> v-enter-from
    • v-leave -> v-leave-from
  • 组件 watch 选项和实例方法 $watch 不再支持点分隔字符串路径,请改用计算函数作为参数

  • 在 Vue 2.x 中,应用根容器的 outerHTML 将替换为根组件模板 (如果根组件没有模板/渲染选项,则最终编译为模板)。VUE3.x 现在使用应用程序容器的 innerHTML

其他小改变

  • destroyed 生命周期选项被重命名为 unmounted
  • beforeDestroy 生命周期选项被重命名为 beforeUnmount
  • prop default 工厂函数不再有权访问 this 是上下文
  • 自定义指令 API 已更改为与组件生命周期一致
  • data 应始终声明为函数
  • 来自 mixindata 选项现在可简单地合并
  • attribute 强制策略已更改
  • 一些过渡 class 被重命名
  • 组建 watch 选项和实例方法 $watch 不再支持以点分隔的字符串路径。请改用计算属性函数作为参数。
  • <template> 没有特殊指令的标记 (v-if/else-if/elsev-forv-slot) 现在被视为普通元素,并 将生成原生的 元素,而不是渲染其内部内容。
  • 在 Vue 2.x 中,应用根容器的 outerHTML 将替换为根组件模板 (如果根组件没有模板/渲染选项,则最终编译为模板)。Vue 3.x 现在使用应用容器的 innerHTML,这意味着容器本身不再被视为模板的一部分。

以上内容如果想要详细了解,请移步至 v3 迁移指南


六、基于Vue的第三方组件库兼容Vue3.0的情况

截止目前仅有 Ant Design of Vue 支持 Vue3.0 的 2.0.0测试版 已发布。

20210107 更新:
基于 Vue3 的组件库 element-plus 已经正式发布:Element Plus
如果想要研究一下它的源码和架构,请移步至:GitHub - element-plus


七、Vite 与 Vue CLI

Has Vite Made Vue CLI Obsolete?
原文:https://vuejsdevelopers.com/2020/12/07/vite-vue-cli/
作者:Anthony Gore

Vue 生态系统中有一个新构建工具 Vite ,它的开发服务器比 Vue CLI 快 10 ~ 100倍。

快10~100倍?是不是很好奇,那是不是意味着 Vue CLI 即将过时?下面将会对这两种构建工具进行对比分析。

Vue CLI 概述

Vue CLI 是使用标准构建工具和最佳实践配置快速建立基于Vue的项目的不可或缺的工具。

主要功能包括:

  • 工程脚手架
  • 带热模块重载的开发服务器
  • 插件系统
  • 用户界面

但是需要主要的是:Vue CLI 是构建在 Webpack 之上的,因此开发服务器和构建功能和性能都将是 Webpack 的超集。

Vite 概述

Vue CLI 类似,Vite 也是一个提供基本项目脚手架和开发服务器的构建工具。

然而,Vite 并不是基于 Webpack 的,它有自己的开发服务器,利用浏览器中的原生ES模块。这种架构使得ViteWebpack的开发服务器快了好几个数量级。Vite采用Rollup进行构建,速度也更快。

但是 Vite 目前还处于测试阶段,可以看出 Vite 项目的目的并不是像 Vue CLI 那样的一体化工具,而是专注于提供一个快速的开发服务器和基本的构建工具。

Vite 的优点

Vite 开发服务器至少会比 Webpack 快10倍左右。对于一个基本的项目来说,与2.5秒相比,开发构建/重新构建的时间相差250ms。

在一个较大的项目中,这种差异会变得更加明显。Webpack 开发服务器在构建/重新构建时可能会慢到25-30秒,有时甚至更慢。与此同时,Vite开发服务器可能会以恒定的250ms的速度为同一个项目提供服务。

Vite 为什么这么快?
  • Webpack 开发服务器架构
    Webpack 的工作方式是:它通过解析应用程序中的每一个 importrequire ,将整个应用程序构建成一个基于JavaScript的捆绑包,并在运行时转换文件(例如SassTypeScriptSFC)。
    这都是在服务器端完成的,依赖的数量和改变后构建/重新构建的时间之间有一个大致的线性关系。

  • Vite 开发服务器架构
    Vite不捆绑应用服务器端。相反,它依赖于浏览器对JavaScript模块的原生支持(也就是ES模块,这是一个比较新的功能)。
    浏览器将在需要时通过HTTP请求任何JS模块,并在运行时进行处理。Vite开发服务器将按需转换任何文件(如SassTypeScriptSFC)。
    这种架构避免了服务器端对整个应用的捆绑,并利用浏览器高效的模块处理,提供了一个明显更快的开发服务器。

当你对应用程序进行 code-splittree-shake 动时,Vite 的速度会更快,因为它只加载它需要的模块,即使是在开发阶段。这与 Webpack 不同,在 Webpack 中,代码拆分只对生产包有利。

Vite 的缺点

由于Vite使用了JavaScript模块,所以最好让依赖关系也使用JavaScript模块。虽然大多数现代JS包都提供了这一点,但一些老的包可能只提供CommonJS模块。

Vite可以将CommonJS转换为JavaSript模块,但在一些边缘情况下它可能无法做到。当然,它还需要支持JavaScript模块的浏览器。

Webpack/Vue CLI不同,Vite无法创建针对旧版浏览器、web components等的捆绑包。

而且,与 Vue CLI 不同,开发服务器和构建工具是不同的系统,导致在生产与开发中可能出现不一致的行为。

Vue CLI vs Vite

Vue CLI 总结:
Vue CLI 优点Vue CLI 缺点
经历过战斗考验,可靠开发服务器速度与依赖数量成反比
与Vue 2兼容
可以捆绑任何类型的依赖关系
插件生态系统
可以针对不同的目标进行构建
Vite 总结:
Vite 优点Vite 缺点
开发服务器比Webpack快10-100倍只能针对现代浏览器(ES2015+)
将code-splitting作为优先事项与CommonJS模块不完全兼容
处于测试阶段,目前仅支持Vue 3
最小的脚手架不包括Vuex、路由器等
不同的开发服务器与构建工具
总结

对于有经验的Vue开发者来说,Vite是一个很好的选择,因为它的开发服务器速度快得离谱,让Webpack看起来像史前时代。

但是,对于一些 Vue 新开发人员来说,或者对于使用遗留模块和需要复杂构建的大型项目来说,Vue CLI 很可能在目前仍然是必不可少的。

Vite 的未来

虽然上面的分析总结都比较主要集中在 ViteVue CLI 的现状上,但仍有几点需要考虑注意:

  • 仅当浏览器中的 JavaScript 模块支持得到改善时,Vite才会有所改善;
  • 随着JS生态系统的追赶,更多的软件包将支持 JavaScript 模块,减少 Vite 无法处理的边缘情况;
  • 目前 Vite 仍处于测试阶段 => 功能可能会有变化;
  • 有可能 Vue CLI 最终会结合 Vite,这样就不用再使用其中一个了。

值得注意的是,Vite 并不是唯一一个利用浏览器中 JavaScript 模块的开发服务器项目。还有更著名的 Snowpack 甚至可能会挤掉 Vite 的发展。时间可能会证明这一点。


八、项目总结

今天做一个小项目,想要使用 Vue3.0 + Element-ui,发现 Element-ui 并不支持在 Vue3 中使用。查看源码发现,Vue3 在插件 install 函数的入参从 Vue原型(类) 改成了 app(Vue的实例e),所以导致 Element-ui 中的 Vue.prototype.*,这样的代码已经全部失效了。所以目前看来,Element-ui 是不能兼容 Vue3 的了。

但是 AntD2.0 测试版 支持 Vue 3.0 已发布。大家可以尝试一下。


Vue3.0 使用总结基本就是这些,后面还会不断学习补充,希望与大家一起进步。加油!

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值