- A+
千呼万唤始出来,2020 年 9 月 19 日凌晨,Vuejs 3.0 终于发布了,代号:One Piece
作为一名从 Vue 1.x 就开始接触 Vue 的老玩家,心里只有一句话想说:学不动了...
但学不动也得学...
原本打算写一写 2.x 和 3.x 的差异,但仔细捋了一下发现内容还不少,干脆抛弃原本的思维,从零开始学 Vue
所以《Vue 3.x 从零开始》系列可能比较啰嗦。对于 Vue 2.x 的用户,直接阅读官方的迁移指南是最好的选择
当然,如果有兴趣和我一起从零开始,也是一个不错的选择
在开始之前,请确保已经正确安装了 node.js
一、Vue CLI 构建项目
为了快速构建 Vue 项目,Vue 团队开发了脚手架工具 Vue CLI,这个脚手架需要全局安装
yarn global add @vue/cli # OR npm install -g @vue/cli
对于 Vue 3.x 的项目,需要使用 Vue CLI v4.5 以上的版本。如果你的 Vue CLI 版本较低,也需要用上面的命令升级
安装完成后可以在命令行输入 vue -V (注意第二个 V 大写),如果出现版本号则安装成功
然后在需要创建项目的文件夹下启动终端,在命令行输入下面的命令
vue ui
这个命令会在浏览器打开一个页面(http://localhost:8000/project/select)
这是 Vue CLI 提供的可视化工具,可以通过页面上的【创建】标签创建项目
除了这种可视化的方式之外,还可以完全通过命令行创建项目:
vue create my-vue3-demo
# my-vue3-demo 是项目目录的名称
运行命令之后,通过【↑】【↓】键选择条目
这里可以直接选择 Vue 3 然后回车,Vue CLI 就会帮我们完成后续的创建工作
// 也可以选择第三项 “Manually select features”,会有更多的自定义配置,这里暂不介绍
二、项目结构
项目创建之后,会在当前目录下多出一个项目文件夹
通过命令行创建的默认 Vue 3 项目是一个比较纯粹的项目
从它的 package.json 中可以看到只有 vue.js 的核心依赖
然后启动项目试试,在项目根目录运行终端,在命令行输入
npm run serve
在浏览器中打开链接 http://localhost:8080/,就能看到项目的启动页
项目默认使用的端口是 8080,如果想使用别的端口,可以在项目的根目录创建一个 vue.config.js
// vue.config.js module.exports = { outputDir: 'dist', // 打包的目录 lintOnSave: true, // 在保存时校验格式 productionSourceMap: false, // 生产环境是否生成 SourceMap devServer: { open: true, // 启动服务后是否打开浏览器 overlay: { // 错误信息展示到页面 warnings: true, errors: true }, host: '0.0.0.0', port: 8066, // 服务端口 https: false, hotOnly: false, // proxy: { // 设置代理 // '/api': { // target: host, // changeOrigin: true, // pathRewrite: { // '/api': '/', // } // }, // }, }, }
这个文件中的 devServer.port 即启动本地服务的端口(更多配置可以参考官方文档)
项目中有一个 public 文件夹,可以存放一些不需要经过 webpack 打包的文件(参考链接)
这个目录下有一个 index.html 文件,这是整个应用的 html 基础模板,也是打包编译后的项目入口
这个 index.html 文件中有一个 #app 节点:
Vue 的实例会挂载到这个节点
项目的代码在 src 目录下:
现在的 src 目录非常简洁,其中 main.js 是 webpack 打包的入口文件
main.js 只是引入了 App.vue 组件,并挂载到上面提到的 #app 节点下
这里的 createApp 方法是 Vue 3 新增的全局 API,用来创建一个 Vue 应用,并挂载到某个 DOM 节点
在 2.x 的时代,上面的代码是这样写的:// 以下内容为 2.x 的对比,不感兴趣的话可以直接跳到下一节
从表面上看,createApp 只是改良版的 render 函数,但其实他解决了 2.x 中的一些不太优雅用法
2.x 时代的 Vue 没有“应用”的概念,所谓的应用只是一个 Vue 的根实例 new Vue()
当我们需要修改一些全局属性的时候,只能通过 Vue 对象本身来修改,比如:
// 2.x 时代的全局属性 Vue.prototype.$http = axios; Vue.directive('focus', { inserted: el => el.focus() }); Vue.config.errorHandler = errorHandler;
这样的行为会污染 Vue 对象,导致从同一个 Vue 创建的实例会共享相同的全局配置
而通过 createApp 返回的是独立的实例,修改该实例的属性不会影响其他 createApp 创建的实例:
// 3.x createApp const foo = createApp(Foo); foo.directive('focus' /* ... */); const bar = createApp(Bar); bar.directive('focus' /* ... */); // foo 和 bar 都具备了 focus 指令,但这两个指令的内容相互独立
如果确实需要两个应用共享配置,还可以通过 createApp 创建一个工厂函数:
const createMyApp = options => { const app = createApp(options) app.directive('focus' /* ... */) return app } const foo = createMyApp(Foo).mount('#foo') const bar = createMyApp(Bar).mount('#bar') // foo 和 bar 会具备同一个 focus 指令
三、使用 Vite 构建项目
除了上面的 Vue CLI 创建项目之外,Vue 3.x 还可以通过新工具 Vite 创建项目
Vite 是一个由原生 ES 模块驱动的 Web 开发构建工具,支持模块热更新和按需加载
用尤大的话来讲,用了 Vite 之后就可以告别 webpack 了
先来用 Vite 创建一个项目吧:
npm init vite-app <project-name> # 将 <project-name> 改为自己的项目名
项目结构也非常简洁,在 package.json 中只引入了 vue.js
然后安装依赖,并启动项目:
npm install npm run dev
项目地址为 http://localhost:3000/,如果页面没有自动打开,可以手动打开链接查看
如果需要对 Vite 进行配置,也需要在根目录创建一个 config 文件,命名为 vite.config.js(或者 vite.config.ts)
// vite.config.js module.exports = { port: 8077, // 服务端口 proxy: { // 代理 // string shorthand "/foo": "http://localhost:4567/foo", // with options "/api": { target: "http://jsonplaceholder.typicode.com", changeOrigin: true, rewrite: (path) => path.replace(/^/api/, ""), }, }, };
更多配置可以参考源码中的 config.ts。不过大部分的配置项和上面提到的 vue.config.js 是一样的
目前(2020-09-24)Vite 还处于 beta 阶段,用 Vite 创建项目的方式可以了解,但不建议用到项目中
如果想学习更多关于 Vite 的知识,可以查看 @yuuang 写的《Vite 源码分析》
四、TypeScript
Vue 3 有一个重要的特性就是更好的支持 TypeScirpt
在使用 Vue CLI 创建项目的时候,可以选择 "Manually select features" 选项,然后选择 "TypeScript",这样就能直接创建 ts 项目
如果一开始没有创建 ts 项目,但电脑上装有 Vue CLI,可以通过下面的命令将项目改造为 ts 项目:
vue add typescript
不过我们也可以自己动手,一步一步的引入 TypeScript,看看 vue add typescript 到底做了什么
首先安装 typescript 依赖:
npm install typescript -D
然后在项目根目录创建 tsconfig.json 文件:
{ "include": [ "src/**/*.ts", "src/**/*.tsx", "src/**/*.vue", ], "exclude": [ "node_modules" ], "compilerOptions": { // 与 Vue 的浏览器支持保持一致 "target": "es5", // 如果使用 webpack 2+ 或 rollup,可以利用 tree-shake: "module": "es2015", // 这可以对 `this` 上的数据 property 进行更严格的推断 "strict": true, "moduleResolution": "node" } }
然后把 src 目录下的 main.js 文件名改为 main.ts,以及其他 js 文件改为 ts 后缀(config.js => config.ts)
并编写 .d.ts 文件 shims-vue.d.ts 放到 src 目录下,和 main.ts 平级
/* shims-vue.d.ts */ declare module '*.vue' { import { defineComponent } from 'vue'; const component: ReturnType<typeof defineComponent>; export default component; }
由于 Vue 3 是使用 TypeScript 编写的,所以只要在 <script> 标签上声明 lang="ts",就能直接在 .vue 文件中使用 ts 语法
为了让 TypeScript 能够正确推断 Vue 组件中的类型,还需要使用全局方法 defineComponent 来定义组件
Vue 有一些特性和 TypeScript 并不能完美契合 (如 computed 的返回类型)
为了更好的使用 ts,建议提前阅读《TypeScript 支持》
到这里项目内部的改造基本完成,接下来只要将入口文件从 main.js 改为 main.ts 即可
如果是 Vite 创建的项目,直接修改根目录下的 index.html 文件,将 <script> 标签的 src 地址改为 "/src/main.ts"
如果是 Vue CLI 创建的普通项目,只需要安装 @vue/cli-plugin-typescrip
npm install @vue/cli-plugin-typescript -D
搞定~ 接下来就可以启动项目开始愉悦的编码了~