种子项目:Vite 搭建 Vue3 + TypeScript 项目

7,865 阅读6分钟

技术栈

  • Vue 3.x
  • Typescript
  • Vite 2.x
  • Pinia
  • Vue-Router 4.x
  • Element-plus UI
  • And More...

源码地址 (创作不易,欢迎点颗 star 再走)

初始化项目

npm init vite@latest 项目名
或
yarn create vite 项目名
  1. 选择自己需要的框架和语言(博主选择的是Vue+TS)

  1. npm install 拉取相关依赖
  2. npm run dev 运行项目 出现该页面就可以进行下一步拉~

配置路径别名@

1、安装@types/node
npm install @types/node --save-dev
2、修改vite.config.ts配置路径别名@
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from "path";//这个path用到了上面安装的@types/node

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  //这里进行配置别名
  resolve: {
    alias: {
      '@': path.resolve('./src') // @代替src
    }
  }
})
3、修改tsconfig.json 中的信息
"compilerOptions": {
	//几个常用配置
    "target": "ESNext",// 指定ECMAScript目标版本
    "useDefineForClassFields": true,// 是否校验TypeScript数据类型
    "module": "ESNext",// 生成代码的模板标准
    "removeComments": true,	// 是否删除注释
    "outDir": "./dist", // 指定输出目录
    ......
	//添加如下信息
    "baseUrl": "./",	// 解析非相对模块的基地址,默认是当前目录
    "paths": {"@/*": ["src/*"]}	// 路径映射,相对于baseUrl
  },

TypeScript 的完整配置文件 tsconfig.json

// 全部配置的链接  https://www.cnblogs.com/vant-xie/p/16744406.html
{
  "compilerOptions": {
    // 允许从没有设置默认导出的模块中默认导入。这并不影响代码的输出,仅为了类型检查。
    "allowSyntheticDefaultImports": true,
    // 指定ECMAScript目标版本
    "target": "ESNext",
    // 是否校验TypeScript数据类型
    "useDefineForClassFields": true,
    // 指定生成哪个模块系统代码
    "module": "ESNext",
    // 是否删除注释
    "removeComments": true,
    // 指定输出目录
    "outDir": "./dist",
    // 决定如何处理模块。
    "moduleResolution": "Node",
    // 启用所有严格类型检查选项。
    // 启用 --strict相当于启用 --noImplicitAny, --noImplicitThis, --alwaysStrict,
    // --strictNullChecks和 --strictFunctionTypes和--strictPropertyInitialization。
    "strict": true,
    "jsx": "preserve",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "esModuleInterop": true,
    // 忽略所有的声明文件( *.d.ts)的类型检查。
    "skipLibCheck": true,
    "noEmit": true,
    // 要包含的类型声明文件名列表
    "types": [],
    "baseUrl": "./",	// 解析非相对模块的基地址,默认是当前目录
    // 模块名到基于 baseUrl的路径映射的列表。
    "paths": {
      "@/*": [
        "src/*"
      ]
    },
    // 编译过程中需要引入的库文件的列表。
    "lib": [
      "ESNext",
      "DOM",
      "DOM.Iterable",
      "ScriptHost"
    ]
  },
  "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
  "references": [{ "path": "./tsconfig.node.json" }]
}

安装less/scss

安装less

npm install less less-loader --save-dev
或
yarn add less less-loader --dev

安装scss

npm install sass node-sass --save-dev
或
yarn add sass node-sass --dev

注意:这边如果不加–dev,包会安装到dependencies中,这样会导致编译不通过。需要将less和less-loader迁移到devDependencies中再重新执行安装。

安装Vue-Router

yarn add vue-router@next
1、在 src 目录下新建 router/index.ts,内容如下:
import {createRouter, createWebHistory, RouteRecordRaw} from 'vue-router';
import HelloWorld from '@/components/HelloWorld.vue';

// @ts-ignore
const routes: Array<RouteRecordRaw> = [
  {
    path: '',
    redirect: (_) => {
      return {path: '/home'};
    }
  },
  {
    path: '/home',
    name: 'HelloWorld',
    component: HelloWorld
  },
  {
    path: '/about',
    name: 'About',
    component: () =>
      import(/* webpackChunkName: "About" */ '@/pages/About.vue')
  },
  {
    path: '/:currentPath(.*)*', // 路由未匹配到,进入这个
    redirect: (_) => {
      return {path: '/404'};
    }
  }
];
const router = createRouter({
  history: createWebHistory(''),
  routes,
  scrollBehavior(to, from, savedPosition) {
    return {
      el: '#app',
      top: 0,
      behavior: 'smooth'
    };
  }
});
export default router;
2、在 src 目录下再新建一个 pages/About.vue 文件,内容如下:
<template>
  <h1>{{ msg }}</h1>
  </template>

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

const msg = ref<string>('About Page')
  </script>

  <style scoped>

  </style>
3、在main.ts写入:
import {createApp} from 'vue';
import router from "./router";
import './style.css';
import App from './App.vue';

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

接下来只要运行服务,就可以看到所配置的页面了

注:router安装好了,其它(页面)要自己配置,404页面未配置

安装element-plus

element-plus是vue3目前大流行组件库,用法基本和element ui一样

npm install element-plus --save
引入 Element Plus

你可以引入整个 Element Plus,或是根据需要仅引入部分组件。我们先介绍如何引入完整的 Element。

完整引入

在 main.js 中写入以下内容:

import {createApp} from 'vue';
import router from "./router";
import ElementPlus from 'element-plus';
// 需要注意的是,样式文件需要单独引入。
import 'element-plus/dist/index.css'
import './style.css';
import App from './App.vue';

createApp(App)
  .use(ElementPlus)
  .use(router)
  .mount('#app');
按需引入

自动引入element-plus组件

npm install -D unplugin-vue-components unplugin-auto-import

在 vite.config.js中配置:

import { defineConfig } from 'vite'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'

export default defineConfig({
  // ...
  plugins: [
    // ...
    AutoImport({
      resolvers: [ElementPlusResolver()],
    }),
    Components({
      resolvers: [ElementPlusResolver()],
    }),
  ],
})

然后就可以直接使用element-plus组件拉~

安装pinia

Pinia中文官网

npm install pinia
1、main.ts引入
import {createApp} from 'vue';
import router from "./router";
import './style.css';
import App from './App.vue';

//pinia
import { createPinia } from 'pinia'
const pinia = createPinia()

createApp(App)
  .use(router)
  .use(pinia)
  .mount('#app');
2、在src下创建一个 store/home.ts 文件

什么名字可以,因为pinia它有一个根文件,会把 defineStore 第一个参数当id值,相当于vuex中的 module 自动引入,也会在Vue.js devtools 插件中以第一个参数名展示(下面展示)

注意:defineStore第一个参数很重要,而且是唯一值。它的命名能让开发者在Devtools快速找到相关数据,方便调试

import {defineStore} from 'pinia';

export const useMain = defineStore('main', {
  // 相当于data
  state: () => {
    return {
      // 所有这些属性都将自动推断其类型,如果推断失败可以试下 as xxx
      counter: 0,
      name: 'Eduardo'
    };
  },
  // 相当于计算属性
  getters: {
    doubleCount: (state) => {
      return state.counter * 2;
    }
  },
  // 相当于vuex的 mutation + action,可以同时写同步和异步的代码
  actions: {
    increment() {
      this.counter++;
    },
    randomizeCounter() {
      setTimeout(() => {
        this.counter = Math.round(100 * Math.random());
      }, 0);
    }
  }
});
3、在About中测试使用pinia
<template>
    <div>counter:{{counter}}</div>
    <div>doubleCount:{{doubleCount}}</div>
    <el-button @click="main.randomizeCounter()">counter(round)</el-button>
    <el-button type="primary" @click="main.increment()">counter++</el-button>

    <div>{{name}}</div>
    <el-button @click="amend()">修改</el-button>
</template>
<script setup lang='ts'>
//引入想要的pinia文件 {} 里面就是对应导出的名字
import { useMain } from '@/store/home'
import { storeToRefs } from 'pinia';

const main = useMain()
// 解构main里面的state和getters的数据,
// 使用storeToRefs解构才有响应式,响应式可以直接修改数据,这里只用来渲染
let { counter,name ,doubleCount } = storeToRefs(main)

//(常用方法三种)
//常用方法一: 使用数据
console.log( counter );
//使用方法(方法目前不能解构)
main.increment()
// 常用方法二:修改数据
counter = 9999

//常用方法三:
//进阶使用$patch,多个修改
const amend=()=>{
    main.$patch((state) => {
        state.counter += 10;
        state.name = '张三'
    })
}

</script>

4、devtools查看和示例页面

axios请求封装

1、安装axios

使用axios,封装统一的请求头处理,便于接口的统一管理,以及解决出现回调地狱。

npm install axios

2、在 src 目录下新建 utils /request.ts,内容如下:

配置指路:(Vue3+Vite使用环境变量.env的一些配置 - 掘金 (juejin.cn)

import axios, {AxiosInstance, AxiosRequestConfig, AxiosResponse, AxiosError} from 'axios';
import {ElMessage} from 'element-plus';

console.log('import.meta.env', import.meta.env);
const request: AxiosInstance = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL, // API 请求的默认前缀,可根据环境变量自行配置
  timeout: 60000 // 请求超时时间
});

// 异常拦截处理器
const errorHandler = (error: AxiosError) => {
  if (error.response) {
    switch (error.response.status) {
      case 401:
        // 登录过期错误处理
        break;
      case 500:
        // 服务器错误处理
        break;
      default:
        ElMessage.error(`${error}`);
    }
  }
  return Promise.reject(error);
};

// 前置拦截器(发起请求之前的拦截)
request.interceptors.request.use((config: AxiosRequestConfig) => {
  /**
   * 如果token 存在,则给请求头加token
   */
  const token = sessionStorage.getItem('token');
  if (token) {
    config.headers['Authorization'] = `Bearer ${JSON.parse(token)}`;
  }
  console.log(config);
  return config;
}, errorHandler);

// 后置拦截器(获取到响应时的拦截)
request.interceptors.response.use((response: AxiosResponse) => {
  /**
   * 根据你的项目实际情况来对 response 和 error 做处理
   * 这里对 response 和 error 不做任何处理,直接返回
   */
  return response.data;
}, errorHandler);

export default request;

3、分别创建src/api文件夹、src/api/user.ts文件

import request from '@/utils/request';

const base = import.meta.env.VITE_API_BASE_URL;

const getDict = (data?: any) => {
  return request.get(base + '/config-saas/sysDict/tree', data);
};

export default {
  base,
  getDict
};

测试接口vue文件

<template>
    <div>测试接口页面</div>
</template>

<script setup lang="ts">
import { onMounted } from 'vue'
import userApi from '@/api/user'

onMounted(() => {
    userApi.getDict().then(res => {
        console.log(res);
    })
})
</script>

<style scoped></style>

4、使用mock模拟后台接口(没有后台接口时跳过第三步)

注:mockjs提供的接口,只是一个更接近真实环境的接口,但不代表它能替代真实接口。

  • 下载mock
npm i mockjs -S 
npm i vite-plugin-mock -D
// or
yarn add mockjs -S 
yarn add vite-plugin-mock -D
  • 配置依赖 找到vite.config.ts文件,在里面添加如下代码
import { viteMockServe } from 'vite-plugin-mock'
export default ({mode}) => defineConfig({
  plugins: [vue(), viteMockServe()],
})
  • 在项目根目录下面创建mock/user.ts
import {MockMethod} from "vite-plugin-mock";

const mock: Array<MockMethod> = [
  {
    url: "/api/test",
    method: "get",
    response: () => {
      return {
        code: 0,
        message: "ok",
        'data|5':[{
          'id|+1':0,
          username:'@cname',
          date:'@date(yyyy-MM-dd)',
          // description:'@paragraph',
          email:'@email()',
          'age|18-50' :18
        }]
      }
    }
  }
];
export default mock;
  • 调用接口
<template>
  <div>
    <h3>测试mock</h3>
    <div>{{info}}</div>
  </div>
</template>

<script setup lang="ts">
import {ref} from 'vue';
import {onMounted} from 'vue';
import userApi from '@/api/user';

const info = ref<any>([])
onMounted(() => {
  userApi.getTest().then(res => {
    console.log('test info:', res)
    info.value = res.data
  });
});
</script>

调用时axios的baseURL必须与项目启动使用的端口号一致;如:http://localhost:5173

完结撒花