一、介绍
- vue
- vite
- TypeScript
- Scss
- Element Plus
- Route
- axios
- Vuex
二、步骤
2.1、创建项目
-
使用Vite快速构建项目
- Vite 是一种新型前端构建工具,能够显著提升前端开发体验。
# 项目名称不建议用大写,容易报错 $ npm init vite@latest vue.admin √ Select a framework: » Vue √ Select a variant: » TypeScript Scaffolding project in D:\vsdemo\vs2022\HisApi\vue.admin... Done. Now run: cd vue.admin npm install npm run dev $ cd vue.admin $ npm install added 44 packages, and audited 45 packages in 19s 4 packages are looking for funding run `npm fund` for details found 0 vulnerabilities $ npm run dev > [email protected] dev > vite VITE v3.1.8 ready in 440 ms ➜ Local: http://localhost:5173/ ➜ Network: use --host to expose
-
目录介绍
- node_modules:模块包
- public:公共资源
- src:项目目录
- assets:静态资源
- components:组件
- App.vue:根组件
- main.ts:根函数入口、全局配置生效的地方
- style.css:
- vite-env.d.ts
- package.json:项目配置文件、项目的标题、版本、模块版本等信息
- tsconfig.json:ts配置文件
- vite.config.ts:vite的配置文件
2.2、pnpm
-
节省磁盘空间并提升安装速度
-
安装
$ npm install -g pnpm $ pnpm -v 7.13.6 ## 启动 $ pnpm dev > [email protected] dev D:\vsdemo\vs2022\HisApi\vue.admin > vite VITE v3.1.8 ready in 413 ms ➜ Local: http://localhost:5173/ ➜ Network: use --host to expose
2.3、scss
$ pnpm install sass --save
Progress: resolved 0, reused 1, downloaded 0, added 0
Progress: resolved 5, reused 5, downloaded 0, added 0
Progress: resolved 75, reused 48, downloaded 1, added 0
Progress: resolved 85, reused 48, downloaded 12, added 0
Packages: +17 -1
+++++++++++++++++-
dependencies:
+ sass 1.55.0
2.4、Element Plus
$ pnpm install element-plus
Progress: resolved 0, reused 1, downloaded 0, added 0
Progress: resolved 6, reused 6, downloaded 0, added 0
Progress: resolved 89, reused 63, downloaded 1, added 0
Progress: resolved 103, reused 64, downloaded 9, added 0
Packages: +21
+++++++++++++++++++++
Progress: resolved 107, reused 64, downloaded 18, added 17
Progress: resolved 107, reused 64, downloaded 20, added 20
Progress: resolved 107, reused 64, downloaded 21, added 20
.../node_modules/vue-demi postinstall$ node ./scripts/postinstall.js
.../node_modules/vue-demi postinstall: Done
Progress: resolved 107, reused 64, downloaded 21, added 21, done
dependencies:
+ element-plus 2.2.19
Done in 8.5s
-
自动导入(推荐)
$ pnpm install -D unplugin-vue-components unplugin-auto-import Progress: resolved 0, reused 1, downloaded 0, added 0 Progress: resolved 8, reused 7, downloaded 0, added 0 Progress: resolved 94, reused 72, downloaded 3, added 0 Progress: resolved 135, reused 85, downloaded 24, added 0 Packages: +34 ++++++++++++++++++++++++++++++++++ devDependencies: + unplugin-auto-import 0.11.2 + unplugin-vue-components 0.22.8 Done in 4.3s Progress: resolved 141, reused 85, downloaded 34, added 34, done
-
修改 vite.config.ts
import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import AutoImport from 'unplugin-auto-import/vite' import Components from 'unplugin-vue-components/vite' import { ElementPlusResolver } from 'unplugin-vue-components/resolvers' // https://vitejs.dev/config/ export default defineConfig({ plugins: [vue(), // ... AutoImport({ resolvers: [ElementPlusResolver()], }), Components({ resolvers: [ElementPlusResolver()], }),] })
2.5、router
-
安装
$ pnpm install vue-router@next --save Progress: resolved 0, reused 1, downloaded 0, added 0 Progress: resolved 9, reused 9, downloaded 0, added 0 Progress: resolved 107, reused 105, downloaded 1, added 0 Packages: +2 ++ dependencies: + vue-router 4.0.13 (4.1.5 is available) Done in 3.3s Progress: resolved 143, reused 119, downloaded 2, added 2, done
-
src目录下新建文件夹router,文件夹新建 路由文件index.ts 写入页面和路由映射关系
import { createRouter, createWebHistory } from "vue-router"; import Login from "./views/index/LoginPage.vue"; const router = createRouter({ history: createWebHistory(), routes: [{ path: "/login", component: Login }], }); export default router;
-
main.ts
import { createApp } from "vue"; import "./style.css"; import App from "./App.vue"; import router from "./router"; createApp(App).use(router).mount("#app");
-
在App.vue里面加上路由标签
<router-view></router-view>
2.6、Vuex
-
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
-
$ pnpm install vuex@next --save Progress: resolved 0, reused 1, downloaded 0, added 0 Progress: resolved 11, reused 10, downloaded 0, added 0 Packages: +1 + Progress: resolved 144, reused 121, downloaded 1, added 1, done dependencies: + vuex 4.0.2 (4.1.0 is available)
-
src目录下新建文件夹store,新建文件index.ts
import { createStore } from "vuex"; const store = createStore({ // 状态变量 state() { return { Token: "", NikeName: "", }; }, // 方法 mutations: { SettingNikeName(state: any, NickName) { state.NickName = NickName; }, SettingToken(state: any, Token) { state.Token = Token; }, }, }); export default store;
-
main.ts
import store from "./store/index"; createApp(App).use(store).use(router).mount("#app");
2.7、echarts
-
安装
$ pnpm install echarts --save Progress: resolved 0, reused 1, downloaded 0, added 0 Progress: resolved 11, reused 11, downloaded 0, added 0 Progress: resolved 117, reused 114, downloaded 0, added 0 Packages: +3 +++ Progress: resolved 147, reused 122, downloaded 2, added 1 Progress: resolved 147, reused 122, downloaded 2, added 2 dependencies: + echarts 5.4.0 Done in 5.5s Progress: resolved 147, reused 122, downloaded 3, added 3, done
2.8、axios
-
安装
$ pnpm install axios --save Progress: resolved 0, reused 1, downloaded 0, added 0 Progress: resolved 22, reused 21, downloaded 0, added 0 Progress: resolved 151, reused 125, downloaded 3, added 0 Progress: resolved 153, reused 125, downloaded 6, added 0 Packages: +9 +++++++++ Progress: resolved 156, reused 125, downloaded 9, added 9, done dependencies: + axios 1.1.3 Done in 4.6s
-
src目录下新建http文件夹,新建index.ts文件
import axios from 'axios' //需要拦截器的地方使用instance对象, 有自定义返回逻辑的地方沿用axios,在组件内部处理返回结果即可 import instance from './filter' const http = "/api"; //获取token,,因为instance开启了withCredentials 所以这里要用axios,因为instance有连接器功效,必须携带token export const getToken = (name: string, password: string) => { return axios.get(http + '/Login/GetToken?name=' + name + '&password=' + password); }; //菜单模块 //获取列表 export const getMenuDataNew = async (parms: {}) => { instance.defaults.headers.common['Authorization'] = "Bearer " + localStorage["token"]; return instance.post(http + "/Menu/GetMenus", parms) } //添加 export const addMenu = async (parms: {}) => { instance.defaults.headers.common['Authorization'] = "Bearer " + localStorage["token"]; return instance.post(http + "/Menu/Add", parms) } //修改 export const editMenu = async (parms: {}) => { instance.defaults.headers.common['Authorization'] = "Bearer " + localStorage["token"]; return instance.post(http + "/Menu/Edit", parms) } //删除 export const delMenu = async (id: number) => { instance.defaults.headers.common['Authorization'] = "Bearer " + localStorage["token"]; return instance.get(http + "/Menu/Del?id=" + id) } //BatchDel export const batchDelMenu = async (ids: string) => { instance.defaults.headers.common['Authorization'] = "Bearer " + localStorage["token"]; return instance.get(http + "/Menu/BatchDel?ids=" + ids) } //分配菜单 export const settingMenu = async (rid: string,mids: string) => { instance.defaults.headers.common['Authorization'] = "Bearer " + localStorage["token"]; return instance.get(`${http}/Menu/SettingMenu?rid=${rid}&mids=${mids}`) } //角色模块 //获取列表 export const getRoleData = async (parms: {}) => { instance.defaults.headers.common['Authorization'] = "Bearer " + localStorage["token"]; return instance.post(http + "/Role/GetRoles", parms) } //添加 export const addRole = async (parms: {}) => { instance.defaults.headers.common['Authorization'] = "Bearer " + localStorage["token"]; return instance.post(http + "/Role/Add", parms) } //修改 export const editRole = async (parms: {}) => { instance.defaults.headers.common['Authorization'] = "Bearer " + localStorage["token"]; return instance.post(http + "/Role/Edit", parms) } //删除 export const delRole = async (id: number) => { instance.defaults.headers.common['Authorization'] = "Bearer " + localStorage["token"]; return instance.get(http + "/Role/Del?id=" + id) } //BatchDel export const batchDelRole = async (ids: string) => { instance.defaults.headers.common['Authorization'] = "Bearer " + localStorage["token"]; return instance.get(http + "/Role/BatchDel?ids=" + ids) } //用户模块 //获取列表 export const getUserData = async (parms: {}) => { instance.defaults.headers.common['Authorization'] = "Bearer " + localStorage["token"]; return instance.post(http + "/Users/GetUsers", parms) } //添加 export const addUsers = async (parms: {}) => { instance.defaults.headers.common['Authorization'] = "Bearer " + localStorage["token"]; return instance.post(http + "/Users/Add", parms) } //修改 export const editUsers = async (parms: {}) => { instance.defaults.headers.common['Authorization'] = "Bearer " + localStorage["token"]; return instance.post(http + "/Users/Edit", parms) } //删除 export const delUsers = async (id: number) => { instance.defaults.headers.common['Authorization'] = "Bearer " + localStorage["token"]; return instance.get(http + "/Users/Del?id=" + id) } //BatchDel export const batchDelUsers = async (ids: string) => { instance.defaults.headers.common['Authorization'] = "Bearer " + localStorage["token"]; return instance.get(http + "/Users/BatchDel?ids=" + ids) } //分配 export const settingRole = async (pid: string,rids: string) => { instance.defaults.headers.common['Authorization'] = "Bearer " + localStorage["token"]; return instance.get(`${http}/Users/SettingRole?pid=${pid}&rids=${rids}`) } //根据角色获取菜单 export const getUserMenus = async () => { instance.defaults.headers.common['Authorization'] = "Bearer " + localStorage["token"]; return instance.get(`${http}/Menu/GetUserMenus`) } //个人中心修改用户昵称和密码 export const editNickNameOrPassword = async (nickName: string,password: string) => { instance.defaults.headers.common['Authorization'] = "Bearer " + localStorage["token"]; return instance.get(`${http}/Users/EditNickNameOrPassword?nickName=${nickName}&password=${password}`) }
-
在需要使用的组件里导入http中的方法即可
import { getToken } from '../../http/index' //请求后端数据,获取token,并将token放入localStorage const token = await getToken(form.userName, form.passWord) as any as string const user: UserInfo = JSON.parse(new Tool().FormatToken(token)) localStorage["token"] = token localStorage["nickname"] = user.NickName store.commit("SettingNickName",user.NickName) store.commit("SettingToken",token) router.push({ path: '/desktop' });
-
拦截器:
- 对api的返回结果解析,返回统一的格式。
- 对于错误信息,在拦截器中弹窗提示,业务层页面只需关注页面,无需过度关注交互
//导入axios import axios from 'axios' import { ElMessage } from 'element-plus' //创建一个axios实例 const instance = axios.create({ headers: { 'content-type': 'application/json', }, // true:在跨域请求时,会携带用户凭证 // false(默认):在跨域请求时,不会携带用户凭证;返回的 response 里也会忽略 cookie // withCredentials: true, timeout: 5000 //5秒 }) //http 拦截器 instance.interceptors.response.use( response=>{ //拦截请求,统一相应 if (response.data.isSuccess) { return response.data.result } else { ElMessage.error(response.data.msg) return response.data.result } }, //error也可以处理 error=>{ if (error.response) { switch (error.response.status) { case 401: ElMessage.warning("资源没有访问权限!") break case 404: ElMessage.warning("接口不存在,请检查接口地址是否正确!") break case 500: ElMessage.warning("内部服务器错误,请联系系统管理员!") break default: return Promise.reject(error.response.data) // 返回接口返回的错误信息 } } else { ElMessage.error("遇到跨域错误,请设置代理或者修改后端允许跨域访问!") } } ) export default instance
2.9、icons-vue
-
安装
pnpm install @element-plus/icons-vue
-
使用
<script lang="ts" setup> import { CoffeeCup, Apple, Drizzling, Headset } from '@element-plus/icons-vue' // import { defineProps } from 'vue'; // 新版不需要引用 import { CardModel } from '../class/CardModel' defineProps({ info: CardModel }) </script> <div class="left"> <coffee-cup v-if="info?.Icon == 'CoffeeCup'" /> <apple v-if="info?.Icon == 'Apple'" /> <drizzling v-if="info?.Icon == 'Drizzling'" /> <headset v-if="info?.Icon == 'Headset'" /> </div>
2.10、前端解决跨域问题
-
和后端解决是两种方案,而不是必须前后端都解决跨域问题;
-
代码 vite.config.ts
// vite.config.ts server:{ port:3000, open:true, proxy:{ '/api':{ target:'http://localhost:5294/api', changeOrigin:true, rewrite:(path) => path.replace(/^\/api/,'') } }, }
2.11、ts的class
-
创建类
export class CardModel { Icon: string = ''; Title: string = ''; Count: number = 0; }
-
使用
import { CardModel } from '../class/CardModel' defineProps({ info: CardModel })