前段时间使用了Vite + Typescript + Ant Design Vue搭建项目,写下搭建步骤,方便下次使用~
根据项目的实际情况进行配置
1. Vite 项目初始化配置
初始化
对比 Vue-cli(基于 Webpack),Vite 非常非常快❤!
vite 官方中文文档:cn.vitejs.dev/guide/
个人喜欢用yarn,命令简单统一
-
安装 vite
yarn create vite
按照提示输入就ok了
-
浏览器打开查看效果:http://localhost:3000/
配置别名
修改 vite.config.ts 配置文件
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import path from "path";
const resolve = (dir: string) => path.join(__dirname, dir);
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
"@/": resolve("src/*"),
comps: resolve("src/components"),
store: resolve("src/store"),
},
},
});
-
报错:找不到模块“path”或其相应的类型声明;找不到名称“__dirname”
yarn add @types/node --save-dev
-
报错:Cannot find module 'store/index' or its corresponding type declarations.
在 tsconfig.json 中配置 baseUrl 和 paths
{ "compilerOptions": { "baseUrl": "./", "paths": { "@": ["src/*"], "comps/*": ["src/components/*"], "store/*": ["src/store/*"] } } }
2. 清空默认文件
新建 public/css/reset.css 文件,清除浏览器默认样式,并在main.ts引入 import '../public/css/reset.css'
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
将 src/assets
和 src/components
目录下的所有文件都删除
打开App.vue
文件,删除所有代码,使用快捷键vue生成模板
-
vscode设置模板
【文件】 -> 【首选项】 -> 【用户片段】 -> 【新建全局代码片段文件】 -> 输入文件名
vue-ts-less
-> 粘贴以下代码{ "Print to console": { "prefix": "vue-ts-less", "body": [ "<template></template>", "", "<script lang=\"ts\">", "import { defineComponent } from \"vue\";", "export default defineComponent({", " components: {},", " setup() {", " return {};", " },", "});", "</script>", "", "<style lang=\"less\" scoped>", "</style>", "$2" ], "description": "Vue-ts-less模板" } }
在vue文件输入
vue-ts-less
后按Tab键生成对应的代码块
3. Vuex 配置
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
- 多个组件使用相同数据的
- 组件深嵌套
存在上述情况使用vuex会更为合适
Vuex 官方文档:next.vuex.vuejs.org/
-
安装Vuex,使用4.x版本
yarn add vuex@next --save
-
在 src 目录下创建
store/index.ts
import { InjectionKey } from "vue"; import { createStore, useStore as baseUseStore, Store } from "vuex"; import type { App } from "vue"; // 引入对应的模块 import { users } from "./modules/users"; // 手动声明 state 类型 export interface State { } // 定义注入类型 const key: InjectionKey<Store<State>> = Symbol(); const store = createStore<State>({ state() { }, mutations: {}, actions: {}, // 使用模块 modules: { users }, }); // 将类型注入useStore,项目中引用的均为自定义的这个,覆盖了vuex提供的useStore export function useStore() { return baseUseStore(key); } export function setupStore(app: App<Element>) { app.use(store, key); } export default store;
-
创建
store/modules
文件夹,该文件夹里可以新建各个module文件例如 user.ts
import { createStore } from "vuex"; export interface State { } export const users = createStore<State>({ state: () => ({}), getters: {}, mutations: {}, actions: {}, })
-
在main.ts中加入
import { createApp } from "vue"; import { setupStore } from "./store"; import App from "./App.vue"; const app = createApp(App); setupStore(app); app.mount("#app");
4. Vue Router 4.x 配置
功能包括:
- 嵌套路由映射
- 动态路由选择
- 模块化、基于组件的路由配置
- 路由参数、查询、通配符
- 展示由 Vue.js 的过渡系统提供的过渡效果
- 细致的导航控制
- 自动激活 CSS 类的链接
- HTML5 history 模式或 hash 模式
- 可定制的滚动行为
- URL 的正确编码
Vue Router 官方中文文档:next.router.vuejs.org
-
安装
yarn add vue-router@4
-
修改App.vue文件
加上
router-view
标签才会起作用<template> <router-view></router-view> </template> <script lang="ts"> export default { name: "App", }; </script> <style></style>
-
在 src 目录下新建 router/index.ts
import { createRouter, createWebHistory } from "vue-router"; import type { App } from "vue"; // 导入对应的模块 const Home = () => import("../view/home.vue"); const Login = () => import("../view/login.vue"); // 写路由 const routes = [ { path: "/", component: Home }, { path: "/login", component: Login }, ]; const router = createRouter({ // createWebHashHistory (hash路由) // createWebHistory (history路,需要服务器配置支持) // createMemoryHistory 带缓存 history 路由 // 添加baseUrl,createWebHistory(baseUrl) history: createWebHistory(), routes, }); export function setupRouter(app: App<Element>) { app.use(router); } export default router;
项目大的话可以将路由分模块抽离出来
-
main.ts 修改
import { createApp } from "vue"; import { setupStore } from "./store"; import router, { setupRouter } from "./router"; import App from "./App.vue"; const app = createApp(App); setupRouter(app); setupStore(app); router.isReady().then(() => { app.mount("#app"); });
5. Scass / Scss / Less 预处理器
antd使用的是less
yarn add less
6. Ant Design of Vue 安装及配置
-
安装
yarn add ant-design-vue@next --save
-
在 main.ts 完整引入(不推荐)
import { createApp } from 'vue'; import Antd from 'ant-design-vue'; import App from './App'; import 'ant-design-vue/dist/antd.css'; // 要引入才有样式 const app = createApp(); app.config.productionTip = false; app.use(Antd);
-
局部导入
import { createApp } from 'vue'; import { Button } from 'ant-design-vue'; import 'ant-design-vue/es/button/style'; //同样要引入less样式 import "ant-design-vue/es/button/style/css"; // 加载 CSS import App from './App'; const app = createApp(App); app.use(Button).mount('#app');
-
==按需导入(推荐)==
安装 vite-plugin-imp
yarn add vite-plugin-imp -D
修改 vite.config.ts 文件
import { defineConfig } from "vite"; import vitePluginImp from "vite-plugin-imp"; export default defineConfig({ plugins: [ vue(), vitePluginImp({ libList: [ { libName: "ant-design-vue", // style: (name) => `ant-design-vue/es/${name}/style/css`, // 加载css style: (name) => `ant-design-vue/es/${name}/style`, // 加载less }, ], }), ], css: { preprocessorOptions: { less: { // 自定义定制主题 modifyVars: { "primary-color": "#1188ff" }, javascriptEnabled: true, }, }, }, });
在 src 目录下新增 libs/antdv.ts 文件
import type { App } from "vue"; // 新增组件就在这里进行新增就可以了 import { Button, Radio, Checkbox } from "ant-design-vue"; const components = [Button, Radio, Checkbox]; export function setupAntd(app: App<Element>): void { components.forEach((component: any) => { app.use(component); }); }
修改main.ts文件
import { createApp } from "vue"; import { setupStore } from "./store"; import router, { setupRouter } from "./router"; import { setupAntd } from "./libs/antdv"; // ++ import App from "./App.vue"; const app = createApp(App); setupRouter(app); setupStore(app); setupAntd(app); // ++ router.isReady().then(() => { app.mount("#app"); });
7. Element-plus 安装及配置
这里只讲述使用插件按需导入,其他可以到官网看,和上面的antd差不多
官方文档:element-plus.gitee.io/zh-CN/
-
安装
yarn add element-plus
-
自动导入
yarn add unplugin-vue-components unplugin-auto-import
-
修改 vite.config.ts
import AutoImport from 'unplugin-auto-import/vite' import Components from 'unplugin-vue-components/vite' import { ElementPlusResolver } from 'unplugin-vue-components/resolvers' export default { plugins: [ // ... AutoImport({ resolvers: [ElementPlusResolver()], }), Components({ resolvers: [ElementPlusResolver()], }), ], }
-
同样的,在 src 目录下新增 libs/elem.ts 文件
import type { App } from "vue"; import { ElButton } from 'element-plus' const components = [ElButton]; export function setupElem(app: App<Element>): void { components.forEach((component: any) => { app.use(component); }); }
修改main.ts文件
import { createApp } from "vue"; import { setupStore } from "./store"; import router, { setupRouter } from "./router"; import { setupElem } from "./libs/element-plus"; // ++ import App from "./App.vue"; const app = createApp(App); setupRouter(app); setupStore(app); setupElem(app); // ++ router.isReady().then(() => { app.mount("#app"); });
8. axios 安装及二次封装
Axios 是一个基于 promise 的 HTTP 库,简单的讲就是可以发送get、post等请求
- 可以在浏览器中发送 XMLHttpRequests
- 可以在 node.js 发送 http 请求
- 支持 Promise API
- 拦截请求和响应
- 转换请求数据和响应数据
- 能够取消请求
- 自动转换 JSON 数据
- 客户端支持保护安全免受 XSRF 攻击
github网址:github.com/axios/axios
-
安装
yarn add axios
-
在 src 目录下新建
src/service/request.ts
对axios进行二次封装
import axios, { AxiosRequestConfig, AxiosResponse } from "axios"; import { message } from 'ant-design-vue' import { useRouter } from "vue-router" const router = useRouter() export function request(config: AxiosRequestConfig) { // 1 创建实例 const instance = axios.create({ baseURL: "xxx", timeout: 5000, headers: { "Content-Type": "application/json", }, }); // 2 拦截器 // 请求拦截 instance.interceptors.request.use( (config) => { message.loading(); return config; }, (err) => { console.log(err); } ); // 响应拦截 instance.interceptors.response.use((response: AxiosResponse<any>) => { message.destroy(); return response.data; }), (error: any) => { if (error?.response) { switch (error.response.status) { case 400: message.error('请求错误(400)'); break; case 401: router.push({ name: 'login' }); break; case 403: message.error('拒绝访问(403)'); break; case 404: message.error('请求出错(404)'); break; case 408: message.error('请求超时(408)'); break; case 500: message.error('服务器错误(500)'); break; case 501: message.error('服务未实现(501)'); break; case 502: message.error('网络错误(502)'); break; case 503: message.error('服务不可用(503)'); break; case 504: message.error('网络超时(504)'); break; case 505: message.error('HTTP版本不受支持(505)'); break; default: message.error(`连接出错(${error.response.status})!`); } } else { message.error('连接服务器失败!'); } message.destroy(); console.log(error); }; // 3 返回实例,instance本身就是一个pormise return instance(config); }
-
使用:
在 service 文件夹中新建api文件夹,在此文件夹中对api进行分模块编写
import { request } from "../request"; export function xxxx() { return request({ url: `xxx`, method: 'get', data: {}, params: {} }); }
在使用该api的文件中直接引入即可
<template> <el-button @click="test">测试</el-button> </template> <script lang="ts"> import { defineComponent } from "vue"; import { getSometings } from "../service/api/user"; export default defineComponent({ setup() { const test = async () => { await getSometings().then((res: any) => { console.log(res.data); }); }; return { test }; }, }); </script> <style> </style>
感谢作者:时光足迹 链接:juejin.cn/post/697391… 来源:稀土掘金