沃梦达 / IT编程 / 前端开发 / 正文

Vue3 携手 TypeScript 搭建完整项目结构

至此,我们就完成了将 Vue 3.x 搭建 TypeScript 环境、搭建完整项目结构的攻略。

一、准备工作
1. 安装 node.js(版本需大于等于 12.0.0) 和 npm(版本需大于等于 6.0.0);
2. 在终端中执行 npm install -g @vue/cli 安装 Vue CLI(版本需大于等于 4.5.0);
3. 在终端中执行 vue create my-project 创建一个 Vue 项目;
4. 在创建项目的时候,选择 Manually select features,然后选择 TypeScript、Router、Vuex、Linter / Formatter;
5. 等待项目的依赖安装完成后,在终端运行 npm run serve 启动项目。

二、Vue3 携手 TypeScript
1. 安装依赖:在终端中运行 npm install --save-dev vue@next @vue/compiler-sfc @vue/test-utils @types/node @types/vue @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint eslint-plugin-vue;
2. 配置 TypeScript:在项目根目录创建 tsconfig.json 文件,并添加以下内容:

{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "moduleResolution": "node",
    "strict": true,
    "jsx": "preserve",
    "sourceMap": true,
    "resolveJsonModule": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "experimentalDecorators": true,
    "skipLibCheck": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist", "test/"]
}
  1. 修改 main.ts:将 import Vue from 'vue' 修改为 import { createApp } from 'vue'Vue.config.productionTip = false 修改为 app.config.productionTip = falsenew Vue({ render: h => h(App) }).$mount('#app') 修改为 app.mount('#app')
  2. 修改样式文件(.css/.less/.scss):在样式文件最顶部添加 lang="scss"(示例为 Sass);
  3. 配置 webpack:在项目根目录创建 vue.config.js 文件,并添加以下内容:
module.exports = {
    chainWebpack: config => {
        // TypeScript Loader
        config.module
            .rule('typescript')
            .test(/\.ts$/)
            .use('babel-loader')
            .loader('babel-loader')
            .end()
            .use('ts-loader')
            .loader('ts-loader')
            .end()
            .include
            .add(/src/)
            .add(/test/)
            .end();
    }
};
  1. 创建组件:在 src/components 目录下创建一个名为 HelloWorld.vue 的组件,并添加以下内容:
<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
  </div>
</template>

<script lang="ts">
import { defineComponent } from 'vue';

export default defineComponent({
  name: 'HelloWorld',
  props: {
    msg: String
  }
});
</script>

<style lang="scss">
.hello {
  h1 {
    font-size: 36px;
  }
}
</style>
  1. 修改 App.vue:在 Vue3.x 中,需要在主组件中使用 defineComponent 定义父组件。修改 src/App.vue 文件,并添加 HelloWorld 组件:
<template>
  <div id="app">
    <HelloWorld msg="Welcome to Your Vue.js + TypeScript App"/>
  </div>
</template>

<script lang="ts">
import { defineComponent } from 'vue';
import HelloWorld from './components/HelloWorld.vue';

export default defineComponent({
  name: 'App',
  components: {
    HelloWorld
  }
})
</script>
  1. 验证效果:在终端中运行 npm run serve,在浏览器中查看项目是否正常运行。

三、搭建完整项目结构
1. 目录结构参考:

my-project/
├── node_modules/
├── public/
├── src/
│   ├── api/
│   │   └── index.ts            // 接口请求工具的定义
│   ├── assets/
│   │   ├── logo.png
│   │   └── ...
│   ├── components/
│   │   └── HelloWorld.vue
│   ├── router/
│   │   └── index.ts            // 路由配置
│   ├── store/
│   │   ├── index.ts            // Vuex store 的定义
│   │   ├── actions.ts
│   │   ├── mutations.ts
│   │   ├── getters.ts
│   │   └── modules/
│   ├── utils/
│   │   ├── index.ts            // 工具函数
│   │   └── ...
│   ├── views/
│   │   ├── Home.vue
│   │   └── ...
│   ├── App.vue
│   └── main.ts
├── tests/
│   ├── e2e/
│   └── unit/
├── .eslintrc.js
├── babel.config.js
├── package-lock.json
├── package.json
└── tsconfig.json
  1. 编写接口请求工具:在 src/api 目录下创建 index.ts 文件,并添加以下内容:
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';

interface RequestOptions extends AxiosRequestConfig {}

interface RequestPromise extends Promise<AxiosResponse<any>> {}

export class Http {
  private static DEFAULT_TIMEOUT = 10000;
  private $http: AxiosInstance;
  private static instance: Http;

  private constructor(config: RequestOptions) {
    this.$http = axios.create(config);
  }

  public static getInstance(config: RequestOptions): Http {
    if (!this.instance) {
      this.instance = new Http({
        timeout: Http.DEFAULT_TIMEOUT,
        ...config
      });
    }
    return this.instance;
  }

  public request(options: RequestOptions) {
    const instance = this.$http;
    return instance(options) as RequestPromise;
  }
}

export const http = Http.getInstance({
  baseURL: 'https://jsonplaceholder.typicode.com/'
});
  1. 配置路由:在 src/router 目录下创建 index.ts 文件,并添加以下内容:
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router';
import Home from '../views/Home.vue';

const routes: Array<RouteRecordRaw> = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
  }
];

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

export default router;
  1. 创建 Vuex store:在 src/store 目录下创建 index.ts 文件,并添加以下内容:
import { createStore } from 'vuex';
import { actions } from './actions';
import { mutations } from './mutations';
import { getters } from './getters';
import { moduleA } from './modules/moduleA';

export default createStore({
  state: {
    count: 0
  },
  mutations,
  actions,
  getters,
  modules: {
    moduleA
  }
});
  1. src/main.ts 中引入路由和 Vuex:在 main.ts 文件中,引入 Router 和 Vuex :
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';

const app = createApp(App);
app.use(router);
app.use(store);
app.mount('#app');
  1. 测试:在浏览器中打开 http://localhost:8080,路由和 Vuex 是否正常运行。

至此,我们就完成了将 Vue 3.x 搭建 TypeScript 环境、搭建完整项目结构的攻略。

示例说明:
1. 在接口请求工具之中,使用 class 和 interface 进行封装,并在外部调用时使用单例的模式返回实例,避免了频繁创建的问题;
2. 在模块化 Vuex store 的过程中,我们使用模块化的方式对 store 进行分层。在 moduleA.ts 文件中,我们看到除了 state、mutations、actions、getters 之外,还会有子模块 children,以此来进行更加细致和完善的 store 管理。

本文标题为:Vue3 携手 TypeScript 搭建完整项目结构