# Vue3项目的创建与使用

# 前言

本次培训的内容是Vue3项目的创建与使用,创建Vue3项目主要是使用Vue3 (opens new window)+Vite (opens new window)+Typescript (opens new window)+Pinia (opens new window)来创建项目,相比较Vue2全家桶来说,对于刚接触Vue3的同学来说可能有些陌生,并且因为涉及到Ts,这也是Vue3不容易上手的原因,所以想通过此次培训来让大家对Vue3的写法、项目的构建和如何使用ts都有一个初步的了解和认识。下面就让我们看看如何去构建一个Vue3项目。

# 一、构建项目

Vue3官方推荐使用Vite (opens new window)来构建项目,而不再使用webpack。

使用Vite构建项目Vue官方和Vite都提供了构建命令,两者构建项目都可以,区别就是Vue官方提供的构建命令更针对与Vue开发,我们使用Vue官方提供的构建命令就可以了。

# 1、创建项目

Vue3创建项目只需安装好Node后直接执行创建项目的命令即可,选择基于TS+组合式API进行开发,不再使用选项式。

npm create vue@latest

执行后,根据提示进行选择,把TS选项选上。

√ Project name: ... vue-project
√ Add TypeScript? ... No / (Yes)
√ Add JSX Support? ... No / (Yes)
√ Add Vue Router for Single Page Application development? ... No / (Yes)
√ Add Pinia for state management? ... No / (Yes)
√ Add Vitest for Unit Testing? ... (No) / Yes
√ Add an End-to-End Testing Solution? » (No)
√ Add ESLint for code quality? ... (No) / Yes
Scaffolding project in ./<your-project-name>...
Done.

前几个选项都默认安装就行了,而Eslint和Prettier选项对于没有严格要求的项目可以直接选择Yes,它只会进行简单的代码检查,不会有严格的风格要求。对于团队来说不建议使用这种,默认选择No不添加,在项目创建好后手动配置Eslint来满足需要的风格指南。

> cd vue-project
> npm install
> npm run dev

# 2、IDE支持

推荐使用Visual Studio Code进行开发,在VSCode中通过Volar (opens new window) TypeScript Vue Plugin (opens new window)两个插件对代码进行类型检查。在开发中可以很大程度的帮助检查和提示类型出错,如果想要更严格的类型检查,可以通过Eslint+TS相关的代码检查插件进行控制。

  • Volar是官方的 VSCode 扩展,提供了 Vue 单文件组件中的 TypeScript 支持,Volar 取代了我们之前为 Vue 2 提供的官方 VSCode 扩展 Vetur。如果之前已经安装了 Vetur,需要在Vue3项目中禁用。

  • TypeScript Vue Plugin针对*.vue 文件进行类型检查。

# 开启Volar Takeover 模式

在添加Volar插件后~~,Volar 提供了一个叫做“Takeover 模式”的功能。在这个模式下,Volar 能够使用一个 TS 语言服务实例同时为 Vue 和 TS 文件提供支持,要开启这个模式需要在VSCode中禁用默认的TS语言服务。~~

  1. 在当前项目的工作空间下,用Ctrl + Shift + P (mac:Cmd + Shift + P) 唤起命令面板。

  2. 输入built,然后选择“Extensions:Show Built-in Extensions”。

  3. 在插件搜索框内输入typescript (不要删除 @builtin 前缀)。

  4. 点击“TypeScript and JavaScript Language Features”右下角设置,然后选择禁用。

  5. 重新加载工作空间。Takeover 模式将会在你打开一个 Vue 或者 TS 文件时自动启用。

图片

# 3、项目结构设计

项目目录创建好后,构建工程化项目,比如常见的后台应用。

├── public                   # 资源文件
│   └── favicon.ico          
├── sr
│   ├── api                  # Api ajax 等
│   ├── assets               # 本地静态资源
│   │   ├── images           # 项目图片
│   │   ├── css              # reset、common样式
│   │   ├── font             # 字体库
│   │   ├── iconfont         # iconfont库
│   │   └── less/sass        # 公共less/sass文件
│   ├── components           # 业务公共组件
│   ├── config               # 基础配置
│   ├── constants            # 常量文件
│   ├── directive            # 自定义指令
│   ├── hooks                # hook函数
│   ├── json                 # json文件
│   ├── layouts              # 基础布局
│   ├── mock                 # mock假数据
│   ├── router               # Vue-Router
│   ├── stores               # pinia
│   ├── types                # 声明文件
│   ├── utils                # 工具库
│   ├── views                # 业务页面入口和常用模板
│   ├── App.vue              # Vue 模板入口
│   └── main.ts              # Vue 入口 TS
├── .env                     # 环境配置文件
├── .env.development         
├── .eslintignore            # eslint忽略文件
├── .eslintrc.cjs            # eslint配置
├── .gitignore               # git忽略
├── env.d.ts                 # 全局声明文件
├── .gitignore               # git忽略
├── index.html               # Vue 入口模板
├── package.json             # 包管理
├── README.md
├── tsconfig.app.json        # ts配置
├── tsconfig.json            # ts配置
├── tsconfig.node.json       # ts配置
└── vite.config.ts           # vite配置

# 二、Vite相关配置

以前基于webpack的配置现在全部改为基于Vite的配置,所以很多配置都有所改变,最主要的改变就是环境变量、静态资源、config配置等。

# 1、vite.config.ts

Vue3中关于项目的配置全部写在vite.config.ts中,很多基础配置和以前的vue.config.js差不多,具体API可以参考 配置 Vite (opens new window)

// vite.config.ts
import path from 'path'
import { fileURLToPath, URL } from 'node:url'


import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import eslintPlugin from 'vite-plugin-eslint'
import VueSetupExtend from 'vite-plugin-vue-setup-extend'


// https://vitejs.dev/config/
export default defineConfig({
  // base: '/',
  // 本地服务启动配置、跨域配置
  // server: {
  //   host: 'localhost',
  //   port: 8080,
  //   proxy: {
  //     '/api': {
  //       target: 'http://192.168.100.14:3351',
  //       ws: false,
  //       changeOrigin: true
  //     }
  //   }
  // },
  
  // 插件配置
  plugins: [
    vue(),
    vueJsx(),
    // 配置vite在运行的时候自动检测eslint规范
    eslintPlugin({
      include: ['src/**/*.ts', 'src/**/*.js', 'src/**/*.vue', 'src/*.ts', 'src/*.js', 'src/*.vue']
    }),
    // 自定义组件名称
    VueSetupExtend()
  ],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  },
  // less、sass配置
  css: {
    preprocessorOptions: {
      // 配置less全局使用
      less: {
        modifyVars: {
          hack: `true; @import (reference) "${path.resolve('src/assets/less/main.less')}";`,
        },
        javascriptEnabled: true
      }
    }
  }
})

# 2、环境变量

Vite在环境变量.env等文件里配置变量统一使用 VITE_ 进行开头。

// .env
VITE_ENV=production
VITE_APP_API_BASE_URL=/api


// .env.development
VITE_ENV=development
VITE_APP_API_BASE_URL=http://192.168.100.1

获取时通过一个特殊的 import.meta.env 对象上暴露环境变量。不在是以前的process.env对象。

// 创建 axios 实例
const request: AxiosInstance = axios.create({
  // API 请求的默认前缀
  baseURL: import.meta.env.VITE_APP_API_BASE_URL,
  timeout: 1000 * 60 * 10 // 请求超时时间
})


// 判断环境是开发环境时
if (import.meta.env.VITE_ENV === 'development') {
  console.log(1111)
}

在HTML中也能使用环境变量,import.meta.env 中的任何属性都可以通过特殊的 %ENV_NAME% 语法在 HTML 文件中使用。

<h1>当前模式: %VITE_ENV %</h1>
<p>当前接口地址: %VITE_APP_API_BASE_URL%</p>

# 3、静态资源处理

在HTML中引入assets和public是和以前一样的,主要是在js中动态引入方式不同,以前通过requier,现在需要通过 new URL() 方式引入。

<template>
  <div v-for="(src, idx) in imageSrc" :key="idx">
    <img :src="src" style="width: 100%" />
  </div>
</template>
<script setup lang="ts">
const imageSrc = [
  new URL('@/assets/images/banner01.png', import.meta.url).href,
  new URL('@/assets/images/banner02.png', import.meta.url).href,
  new URL('@/assets/images/banner03.png', import.meta.url).href,
  new URL('@/assets/images/banner04.png', import.meta.url).href,
  new URL('@/assets/images/banner05.png', import.meta.url).href
]
const imgUrl = new URL('./img.png', import.meta.url).href


</script>
<style lang="less" scoped>
</style>

图片地址不能直接支持动态参数,不能整个使用变量替换,仅支持模板字符串写法。

function getImageUrl(name) {
  return new URL(`./dir/${name}.png`, import.meta.url).href
}

# 4、使用插件

plugins插件配置就相当于以前webpack的各种loader一样,针对各种文件或者内容进行处理,然后在打包,Vite虽然构建速度快,但是它的插件生态却不如webpack完善。插件在vite.config.ts中进行引入和配置。

import path from 'path'
import { fileURLToPath, URL } from 'node:url'


import { defineConfig } from 'vite'


// 引入插件
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import eslintPlugin from 'vite-plugin-eslint'
import VueSetupExtend from 'vite-plugin-vue-setup-extend'


// https://vitejs.dev/config/
export default defineConfig({
  // 插件配置
  plugins: [
    vue(),
    vueJsx(),
    // 配置vite在运行的时候自动检测eslint规范
    eslintPlugin({
      include: ['src/**/*.ts', 'src/**/*.js', 'src/**/*.vue', 'src/*.ts', 'src/*.js', 'src/*.vue']
    }),
    // 自定义组件名称
    VueSetupExtend()
  ]
})

# 三、TS使用指南

在项目中全部使用ts文件进行开发,不在使用js。开发TS项目时,需要配置TS相关的内容,Vite为我们预先在tsconfig.json文件中配置了,我们只需在其中修改即可。并且Volar插件提供了对TS的代码校验,在开发中需要进行类型校验的都会给与提示和补全,根据这些提示进行修改可以很大程度帮助我们解决报错和标红。

# 1、ts配置文件

tsconfig.json就是ts的配置文件,放在根目录,它指定了用来编译该项目的根文件和编译选项,所有ts相关的配置都放在其中,在Vite中配置文件被拆出tsconfig.app.json和tsconfig.node.json两个文件进行引入,在 tsconfig.app.json中是基础配置。

在tsconfig.app.json配置文件中 include 和 exclude 选项可以指定该项目需要使用ts进行编译的文件和不需要编译的文件,compilerOptions中是其他相关配置。如果在项目中新建的文件无法被ts所识别第一考虑就是此配置中添加include。

{
  "extends": "@vue/tsconfig/tsconfig.dom.json",
  "include": ["env.d.ts", "src/**/*", "src/**/*.vue", "src/**/*.json", "src/**/*.d.ts", "./.eslintrc.cjs", "./vite.config.ts"],
  "exclude": ["src/**/__tests__/*"],
  "compilerOptions": {
    "composite": true,
    "resolveJsonModule": true,
    "esModuleInterop": true,
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}

# 2、声明文件

在开发时,我们可以为变量或者函数定义类型和返回值进行类型约束,定义什么就约束什么,这是针对当前所开发的代码,当我们引入第三方库或者插件,使用其变量、函数或实例化类时ts识别不了。这些插件或库就需要提供一个以 .d.ts 为后缀的声明文件来声明类型编写类型声明,让ts可以识别进行类型检查。

# 1、安装声明文件

一般流行的第三方库都支持ts的类型声明,有的插件会自动安装好对应的声明文件或者直接在安装包里提供声明文件,如果默认没有声明文件,可以去@types organization (opens new window) 上去搜对应的声明文件,搜索加上@types,通过 npm install @types/模块名 -D 去下载其社区为其声明的文件。安装好后在使用插件需要标注类型时,一般都会有相关的类型提示,如果可以就去node_modules里去找,安装的声明文件包在@/node_modules/@types里,如果@/node_modules/@type里没有就直接去对应的包里去找 .d.ts 声明文件。

# 2、自定义声明文件

如果一个插件没有提供声明文件,或者声明文件没有我们需要的类型声明,我们可以根据已有的类型声明导入组装自定义新的声明文件,或者直接为其创建声明文件。自定义的声明文件可以像插件一样发布到npm插件库中去。

添加声明文件或全局公共类型标注文件,一般约定在src目录下创建types文件夹来保存文件,创建好后,在项目根目录下有一个 env.d.ts 文件,这个文件是全局声明文件的入口,可以在此文件中直接引入其他 .d.ts 文件,然后就会全局生效。env.d.ts在tsconfig.json中通过include引入解析。

// eslint-disable-next-line @typescript-eslint/triple-slash-reference
/// <reference types="vite/client" />
/// <reference types="./src/types/global.d.ts" />
/// <reference types="./src/types/api.d.ts" />


/**
 * 全局声明文件
 * 在此自定义一些全局声明或者引入声明文件
 * 在此通过reference引入types中的声明文件
 * <reference types="./src/types/api.d.ts" />
 * */


// store声明
// declare module 'store'

自定义一些常见的声明

// 声明全局...
declare var a:number
declare function fn(params:number):void {}
declare class Vue {}
declare enum Color {}


// 申明外部 npm 插件模块
declare module 'splitpanes'
declare module 'js-cookie'
declare module '@wangeditor/editor-for-vue' {
  import { DefineComponent } from 'vue'
  const Editor: DefineComponent<{}, {}, any>
  const Toolbar: DefineComponent<{}, {}, any>
  export { Editor, Toolbar }
}


// 声明一个模块,防止引入文件时报错
declare module '*.json'
declare module '*.png'
declare module '*.jpg'
declare module '*.scss'
declare module '*.ts'
declare module '*.js'


// 声明文件,*.vue 后缀的文件交给 vue 模块来处理
declare module '*.vue' {
  import type { DefineComponent } from 'vue'
  const component: DefineComponent<{}, {}, any>
  export default component
}


// 声明文件,定义全局变量
/* eslint-disable */
declare interface Window {
  isMobile: boolean
}

# 四、开发指南

如何在vue中写ts、ref/reactive、props、emit如何用ts标注类型、公共组件事件传递、获取this、代码风格指南。

# setup 语法