Vite + TypeScript+ Ant Design Vue 从零开始搭建后台管理系统(一)
1. Vite 项目初始化配置
vite 官方中文文档:cn.vitejs.dev/guide/
- 安装 vite
$ npm init @vitejs/app
复制代码
- 初始化 vite 项目模板:选择模板为 vue-ts
$ npm init @vitejs/app shanglv-vite-antdv -- --template vue
复制代码
-
模板安装好后,运行环境
- 进入安装目录:cd shanglv-vite-antdv
- 安装依赖:npm install
- 启动:npm run dev
-
浏览器打开查看效果:http://localhost:3000/
2. Vuex 配置
Vuex 官方文档:next.vuex.vuejs.org/
- 安装 Vuex,目前 4.x 还没有中文文档,可参考 3.x 中文文档一起阅读
$ npm install vuex@next --save
复制代码
- 在 src 目录下创建 store/index.ts
import { InjectionKey } from "vue";
import { createStore, useStore as baseUseStore, Store } from "vuex";
import type { App } from "vue";
// InjectionKey 将store安装到Vue应用程序时提供类型,将类型传递InjectionKey给useStore方法
// 手动声明 state 类型
export interface State {
count: number;
}
// 定义注入类型
const key: InjectionKey<Store<State>> = Symbol();
const store =
createStore <
State >
{
state() {
return {
count: 0,
};
},
mutations: {
increment(state: State) {
state.count++;
},
},
};
// 将类型注入useStore
// 以后项目中引用的均为自定义的这个,而不是vuex默认导出的useStore
export function useStore() {
return baseUseStore(key);
}
export function setupStore(app: App<Element>) {
app.use(store, key);
}
export default store;
复制代码
- main.ts 修改
import { createApp } from "vue";
import { setupStore } from "./store"; // 状态管理
import App from "./App.vue";
const app = createApp(App);
setupStore(app); // 引入状态管理
app.mount("#app");
复制代码
- components/HelloWorld.vue 修改
<template>
<h1>{{ msg }}</h1>
<button type="button" @click="increment">count is: {{ count }}</button>
</template>
<script lang="ts">
import { defineComponent, computed } from "vue";
// 注意此处,引入的useStore为自定义的,而不是vuex默认导出的;为了引入方便,此处需要配置别名
// import { useStore } from 'vuex'
import { useStore } from "store/index";
export default defineComponent({
name: "HelloWorld",
props: {
msg: {
type: String,
required: true,
},
},
setup: () => {
const store = useStore();
return {
count: computed(() => store.state.count),
increment: () => store.commit("increment"),
};
},
});
</script>
<style scoped></style>
复制代码
- vite 配置别名:修改 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”。
解决办法:
npm install @types/node --save-dev
复制代码
报错二:Cannot find module ‘store/index’ or its corresponding type declarations.Vetur(2307)
原因分析:以当前项目的上级目录为根目录,可能 Vetur 不知道当前哪一层文件夹才是真正的根目录。
解决办法:
(1)在 tsconfig.json 中配置 baseUrl 和 paths
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"@": ["src/*"],
"comps/*": ["src/components/*"],
"store/*": ["src/store/*"]
}
}
}
复制代码
(2)在 vscode 里新打开一个以当前项目根目录为顶级目录的窗口;并且改项目文件必须放在第一个。
- 配置后效果展示:
3. Vue Router 4.x 配置
Vue Router 官方中文文档:next.router.vuejs.org/zh/introduc…
- 安装命令
$ npm install vue-router@4
复制代码
- 修改 App.vue 文件
<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 HelloWorld = () => import("../components/HelloWorld.vue");
const About = { template: "<div>About</div>" };
const User = {
template: `
<div>
<h2>User {{ $route.params.id }}</h2>
<router-view></router-view>
</div>`,
};
const routes = [
{ path: "/", component: HelloWorld },
{ path: "/about", component: About },
{ path: "/users/:id", component: User },
];
const router = createRouter({
// createWebHashHistory (hash路由 Hash模式 #)
// createWebHistory (history路由 HTML5 模式 推荐,需要服务器配置支持)
// 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");
});
复制代码
- 问题解决
警告一:[Vue warn]: Missing required prop: “msg” at <HelloWorld onVnodeUnmounted=fn ref=Ref< undefined >
// HelloWorld.vue 中的 required 去掉
export default defineComponent({
name: 'HelloWorld',
props: {
msg: {
type: String,
// required: true,
default: 'Hello Vue 3 + TypeScript + Vite'
}
}
...
})
复制代码
警告二:访问”/about”时报错,[Vue warn]: Component provided template option but runtime compilation is not supported in this build of Vue. Configure your bundler to alias “vue” to “vue/dist/vue.esm-bundler.js”.
翻译:组件提供模板选项,但是在 Vue 的这个构建中不支持运行时编译,配置你的 bundler 别名 vue: vue/dist/vue.esm-bundler.js
// 在vite.config.ts中配置别名
// 可参考文档:https://blog.csdn.net/qq_41499782/article/details/112505665
export default defineConfig({
resolve: {
alias: {
vue: "vue/dist/vue.esm-bundler.js",
},
},
});
复制代码
4. Sass/Scss 预处理器
$ npm install -D sass sass-loader
复制代码
5. Ant Design of Vue 安装及配置
$ npm i --save ant-design-vue@next
复制代码
(1)全局引入
在 src 目录下新增 libs/antdv.ts 文件
// (1)全局引入
import type { App } from "vue";
import Antd from "ant-design-vue";
import "ant-design-vue/dist/antd.css";
export function setupAntd(app: App<Element>): void {
app.use(Antd);
}
复制代码
修改 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");
});
复制代码
警告提示:You are using a whole package of antd, please use www.npmjs.com/package/bab… to reduce app bundle size. Not support Vite !!!
解决方法:需要进行按需加载,可使用 babel-plugin-import 插件,但是该插件不支持 vite。以下采用手动按需加载和 vite-plugin-imp 插件按需加载。
(2)手动按需引入
修改 antdv.ts 文件
import type { App } from "vue";
import Button from "ant-design-vue/es/button"; // 加载 JS
import "ant-design-vue/es/button/style/css"; // 加载 CSS
// import 'ant-design-vue/es/button/style'; // 加载 LESS
import Radio from "ant-design-vue/es/radio";
import "ant-design-vue/es/radio/style/css";
import Checkbox from "ant-design-vue/es/checkbox";
import "ant-design-vue/es/checkbox/style/css";
export function setupAntd(app: App<Element>): void {
app.use(Button);
app.use(Radio);
app.use(Checkbox);
}
复制代码
(3)使用插件按需引入
按照上面的方式按需引入,每一个都要单独写,有点麻烦。因此采用 vite-plugin-imp 插件帮我们引入,实现效果是一样的。
安装 vite-plugin-imp
$ npm i 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,
},
},
},
});
复制代码
加载 less 文件时,需要安装 less 依赖,此时可以自定义主题样式,覆盖默认的样式;加载 css 文件,则不需要安装
$ npm i less -D
复制代码
修改 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);
});
}
复制代码
修改 components/HelloWorld.vue 组件
<a-button type="primary" @click="increment">count is: {{ count }}</a-button>
<a-radio checked>Radio</a-radio>
<a-checkbox checked>Checkbox</a-checkbox>
复制代码
实现效果