0


导师怀疑我的毕设前端不是自己写的!我把前端模版开发的过程甩他脸上了!

耗时一个月开发的OJ在线判题系统,文末有项目地址,目前还在更新代码~

现在让我们来自主开发打造一套前端开发项目模版

文章目录

确认环境

nodeJS环境版本:

node-v#我的是20npm-v#我的是10

初始化

使用vue-cli脚手架
https://cli.vuejs.org/zh/

1、安装脚手架

npminstall-g @vue/cli

注意:如果出现报错image.png
则使用以下命令,强制安装覆盖新版本脚手架

npminstall-g @vue/cli --force

2、创建项目(项目名居然不能包含大写字母)

vue create yoj-frontend

image.png
3、运行项目,能访问到主页即成功
image.png

image.png

vscode格式化配置Prettier

因为在创建项目时我们选择了Prettier对代码进行检查,所以代码如果写的不规范会报错
此时,我们需要在vscode中进行设置,按规定的语法进行自动格式化
下载插件prettier
image.png
对扩展进行设置
image.pngimage.png
在页面代码处,右键,选择"Format Document",然后选择prettier,alt + shift + f格式化代码,即可按照Prettier的语法规范格式化代码了
image.png
太麻烦了,我选择关闭prettier警告
找到项目里的.eslintrc.js文件,在rules里面添加一句"prettier/prettier": “off”,重启项目;

引入组件库

脚手架自动整合了vue-router:URL地址改变时加载对应的界面

组件库:https://arco.design/
(字节跳动开发的一个组件库)

快速上手: https://arco.design/vue/docs/start

执行命令:

npminstall --save-dev @arco-design/web-vue

在入口文件main.js中完整引入

import{ createApp }from'vue'import ArcoVue from'@arco-design/web-vue';import App from'./App.vue';import'@arco-design/web-vue/dist/arco.css';const app =createApp(App);
app.use(ArcoVue);
app.mount('#app');

项目通用布局实现

新建基础布局BasicLayout

选择组件库的Layout组件,在BasicLayout里面写布局

Arco Design Vue
坐标:src/layouts/BasicLayout

<template><div id="Basiclayout"><a-layout style="height: 400px"><a-layout-header class="header"><GlobalHeader/></a-layout-header><a-layout-content class="content"><roter-view/></a-layout-content><a-layout-footer class="footer"><a href="https://blog.csdn.net/m0_74870396?type=blog" target="_blank">
          诨号无敌鸭
        </a></a-layout-footer></a-layout></div></template><script setup>import GlobalHeader from'@/components/GlobalHeader.vue';</script><style scoped>
#Basiclayout {}
#Basiclayout .header {background: red;
  margin-bottom: 16px;}

#Basiclayout .content {/* 水平方向的渐变背景 */background: linear-gradient(to right, #bbb, #fff); 
  margin-bottom: 16px;}

#Basiclayout .footer {background: #efefef;padding: 16px;position: absolute;bottom:0;left:0;right:0;
  text-align: center;}</style>

在app.vue中引入,记得要有ts的语法支持并且支持vue3

<template><div id="app"><BasicLayout /></div></template><script setup lang="ts">import BasicLayout from"./layouts/BasicLayout.vue";</script><style></style>

新建导航菜单栏

https://arco.design/vue/component/menu

导航菜单也是个通用模块,所以我们单独抽象出来GlobalHeader
坐标:src/components/GlobalHeader

<template><div id="globalHeader"><a-menu mode="horizontal":default-selected-keys="['1']"><a-menu-item
        key="0":style="{ padding: 0, marginRight: '38px' }"
        disabled
      ><div class="title-bar"><img class="logo" src="../assets/icon22.jpg"/><div class="title">YOJ</div></div></a-menu-item><a-menu-item key="1">Home</a-menu-item><a-menu-item key="2">Solution</a-menu-item><a-menu-item key="3">Cloud Service</a-menu-item><a-menu-item key="4">Cooperation</a-menu-item></a-menu></div></template><script setup lang="ts"></script><!-- Add "scoped" attribute to limit CSS to this component only --><style scoped>.title-bar {display: flex;
  align-items: center;}.logo {height: 48px;}.title {color: #444;
  margin-left: 16px;}</style>

现在界面就成了这样分为导航栏,内容,版权信息三部分
image.png

导航菜单路由实现

目的是想让用户点击菜单切换后可以跳转到对应的页面
步骤

1)提取通用路由文件
坐标:src/router/routes

import{ RouteRecordRaw }from"vue-router";import HomeView from"../views/HomeView.vue";exportconstroutes: Array<RouteRecordRaw>=[{path:"/",name:"home",component: HomeView,},{path:"/about",name:"about",// route level code-splitting// this generates a separate chunk (about.[hash].js) for this route// which is lazy-loaded when the route is visited.component:()=>import(/* webpackChunkName: "about" */"../views/AboutView.vue"),},];

修改src/router/index.ts

import{ createRouter, createWebHistory, RouteRecordRaw }from"vue-router";import{ routes }from"./routes";const router =createRouter({history:createWebHistory(process.env.BASE_URL),
  routes,});exportdefault router;

2)菜单组件读取路由,动态渲染菜单项
修改src/components/GlobalHeader 实现能通过遍历路由展示菜单项

<a-menu-item v-for="item in routes":key="item.path">{{item.name}}</a-menu-item><script setup lang="ts">import{routes}from"../router/routes";</script>

image.png

3)绑定跳转事件
接下来我们需要点击菜单后,跳转到对应的路由,查看官网API,得到点击事件API
image.png
修改src/components/GlobalHeader实现点击菜单跳转到对应的页面

<a-menu mode="horizontal":default-selected-keys="['1']" @menu-item-click="doMenuClick"><script setup lang="ts">import{routes}from"../router/routes";import{ useRouter }from"vue-router";const router =useRouter();constdoMenuClick=(key:string)=>{
  router.push({path:key,});}</script>

这样就实现了点击菜单跳转到对应的页面

4)同步路由的更新到菜单项高亮

现在情况是用户刷新后,路由还是那个路由,但是菜单项就没了

刷新前
image.png

刷新后

image.png

所以我们需要同步路由的更新到菜单项高亮上

继续修改src/components/GlobalHeader

:selected-keys="secretedKeys"@menu-item-click="doMenuClick">import{ref}from"vue";const secretedKeys =ref(["/"]);//响应式变量// 一个生命周期,vue路由改变后再执行该函数
router.afterEach((to, from, failure)=>{
  secretedKeys.value =[to.path];});

这样刷新后菜单项也会跟路由一致

整体流程:点击菜单项 => 更新路由 => 同步菜单项

栅格组件

https://arco.design/vue/component/grid
用里面的flex,因为左侧菜单栏是不固定的,右侧用户信息是固定的
将用户头像放到导航栏的右侧,复制示例代码,把外层div去掉,把菜单栏放到auto这一列,用户放到固定的那一列
image.png
给栅格最外面添加align="center"属性,垂直布局,可以让用户名与菜单栏都上下居中对齐

全局状态管理

所有页面共享的变量,而不是局限在某一个页面中。
适合作为全局状态的数据:已登录用户信息(每个页面几乎都要用)
工具:Vuex:https://vuex.vuejs.org/zh/guide/(vue-cli 脚手架已自动引入)
Vuex的本质:给你提供了一套增删改查全局变量的API,只不过可能多了一些功能(比如时间旅行)
image.png
state:存储的状态信息,比如用户信息
mutation(尽量同步):定义了对变量进行增删改的方法
action(支持异步):执行异步操作,并且触发mutation的更改,调用mutation
modules(模块):把一个大的state(全局变量)划分为多个小模块,比如user专门存用户的信息
实现
定义store/user.ts ,存储用户信息

// initial stateimport{ StoreOptions }from"vuex";exportdefault{namespaced:true,state:()=>({loginUser:{userName:"未登录",},}),actions:{getLoginUser({ commit, state }, payload){commit("updateUser",{userName:"鱼皮"});},},mutations:{updateUser(state, payload){
      state.loginUser = payload;},},}as StoreOptions<any>;

在index.ts文件中导入user模块

import{ createStore }from"vuex";import user from"./user";exportdefaultcreateStore({mutations:{},actions:{},modules:{
    user,},});

在Vue页面中可以获取已存储的状态变量

const store =useStore();
store.state.user?.loginUser

在Vue页面中可以修改状态变量

使用dispatch来调用之前定义好的actions,路径是模块名/方法名,传入参数userName

store.dispatch("user/getLoginUser",{userName:"鱼皮",});

全局权限管理

我们希望能够直接以一套通用的机制,去定义哪个页面需要那些权限,而不用每个页面独立去判断权限,提高效率
思路
1、在路由配置文件,定义某个路由的访问权限
2、在全局页面组件app.vue中,绑定一个全局路由监听,每次访问页面时,根据用户要访问页面的路由信息,先判断用户是否有对应的访问权限,(vue生命周期的跳转路由前)
3、如果有,跳转到原页面,如果没有权限,拦截或跳转到401或登录页
步骤
1,route.ts中配置页面的访问权限,meta.access

{path:"/noAuth",name:"无权限",component: NoAuthView,},{path:"/admin",name:"管理员可见",component: AdminView,meta:{access:"canAdmin",},},

2、app.Vue中设置监听函数,在路由跳转之前校验

const router =useRouter();const store =useStore();
router.beforeEach((to, from, next)=>{if(to.meta?.access ==="canAdmin"){if(store.state.user.loginUser?.role !=="admin"){next("/noAuth");return;}}next();});

这样以后,如果用户不是管理员并且还访问了需要管理员权限的界面,就会被重定向到无权限界面

根据配置控制菜单项的显隐

1)routes.ts给路由新增一个标志位,用于判断路由是否显隐

{path:"/hide",name:"隐藏页面",component: HomeView,meta:{hideInMenu:true,},},

2)先过滤只需要展示的元素数组

/ 展示在菜单的路由数组
const visibleRoutes = routes.filter((item, index)=>{if(item.meta?.hideInMenu){//这个属性为true则不能通过过滤returnfalse;}returntrue;});

前面路由遍历改成过滤后的路由数组

<a-menu-item v-for="item in visible":key="item.path">{{ item.name }}</a-menu-item>

注意:v-for和v-if一起用,会先循环所有的元素,导致性能的浪费

根据权限隐藏菜单

需求:只有具有权限的菜单,才对用户可见
思路:类似上面的控制路由显示隐藏,只要判断用户没有这个权限,就直接过滤掉
1)新建access/accessEnum

/**
 * 权限定义
 */constACCESS_ENUM={NOT_LOGIN:"notLogin",USER:"user",ADMIN:"admin",};exportdefaultACCESS_ENUM;

2)定义一个公共的权限校验方法
access/checkAccess.ts

importACCESS_ENUMfrom"@/access/accessEnum";/**
 * 检查权限(判断当前登录用户是否具有某个权限)
 * @param loginUser 当前登录用户
 * @param needAccess 需要有的权限
 * @return boolean 有无权限
 */constcheckAccess=(loginUser: any, needAccess =ACCESS_ENUM.NOT_LOGIN)=>{// 获取当前登录用户具有的权限(如果没有 loginUser,则表示未登录)const loginUserAccess = loginUser?.userRole ??ACCESS_ENUM.NOT_LOGIN;if(needAccess ===ACCESS_ENUM.NOT_LOGIN){returntrue;}// 如果用户登录才能访问if(needAccess ===ACCESS_ENUM.USER){// 如果用户没登录,那么表示无权限if(loginUserAccess ===ACCESS_ENUM.NOT_LOGIN){returnfalse;}}// 如果需要管理员权限if(needAccess ===ACCESS_ENUM.ADMIN){// 如果不为管理员,表示无权限if(loginUserAccess !==ACCESS_ENUM.ADMIN){returnfalse;}}returntrue;};exportdefault checkAccess;

3)修改GlobalHeader动态菜单组件,根据权限来过滤菜单
注意:要使用计算属性computed,使其当登录用户信息发生变更时,触发菜单栏的重新渲染,展示新增权限的菜单项

const visibleRoutes =computed(()=>{return routes.filter((item, index)=>{if(item.meta?.hideInMenu){returnfalse;}// 根据权限过滤菜单if(!checkAccess(store.state.user.loginUser, item?.meta?.access as string)){returnfalse;}returntrue;});});

全局项目入口

app.vue中预留一个可以编写全局初始化逻辑的代码

/**
 * 全局初始化函数,有全局单次调用的代码,都可以写到这里
 */constdoInit=()=>{
  console.log("hello 欢迎来到我的项目");};onMounted(()=>{doInit();});

项目地址

(求求大佬们赏个star~)

前端:https://github.com/IMZHEYA/yoj-frontend
后端:https://github.com/IMZHEYA/yoj-backend
代码沙箱:https://github.com/IMZHEYA/yoj-code-sandbox

标签: spring spring boot java

本文转载自: https://blog.csdn.net/m0_74870396/article/details/140277019
版权归原作者 诨号无敌鸭 所有, 如有侵权,请联系我们删除。

“导师怀疑我的毕设前端不是自己写的!我把前端模版开发的过程甩他脸上了!”的评论:

还没有评论