Clean Frontend Architecture:整洁前端架构 | clean-frontend
https://github.com/eduardomoroni/react-clean-architecture
https://github.com/im-a-giraffe/angular-clean-architecture
https://github.com/phodal/clean-frontend
https://github.com/android10/Android-CleanArchitecture
总结
权限控制怎么放置?路由首位中?
模块化,modules自动加载,如route/modules
通过配置化方式,路由能力的增强,meta.roles 可进行路由权限控制
vue-element-admin阅读
permission 有菜单路由级别,按钮级别,
https://github.com/PanJiaChen/vue-element-admin/tree/master/src
vue-vben-admin 项目阅读
router路由,路由配置和路由守护
enums 常量,
design 样式
api
logics
settings
hooks
store
utils
里面还各有各种分层,命名很清晰
**
**
看入口文件, main.ts
有点应用程序的感觉,
bootstarp(),需要先启动加载很多部分,然后才能执行app.mount加载渲染
// 核心的启动函数async function bootstrap() {const app = createApp(App);// Configure storesetupStore(app);// Initialize internal system configurationinitAppConfigStore();// Register global componentsregisterGlobComp(app);// Multilingual configurationawait setupI18n(app);// Configure routingsetupRouter(app);// router-guardsetupRouterGuard();// Register global directivesetupGlobDirectives(app);// Configure global error handlingsetupErrorHandle(app);// Mount when the route is ready// https://next.router.vuejs.org/api/#isreadyawait router.isReady();app.mount('#app', true);}void bootstrap();
入口文件 App.vue
<template><ConfigProvider :locale="getAntdLocale"><AppProvider><RouterView /></AppProvider></ConfigProvider></template>
AppProvider是做什么用?为何不直接使用一个Store来管理变量和逻辑?以及ConfigProvider的作用
核心路由 router 路由配置增强
- guard
- helper
- menus
- routes
- index.ts
路由守卫做了什么?
初始化逻辑,获取当前url状态在哪里?应该在store中,还是router中?
vscode中都是在一起,在bootstrap代码中,有restore逻辑
basicMenu中有 listenerRouteChange 中 setOpenKeys ,有设置菜单展开的逻辑,handleMenuChange中有 setOpenKeys
如果菜单变更, items
路由模块化,路由配置增强
写在modules中,会被自动加载
里面包含了很多逻辑,如权限控制的 meta.roles
路由配置还包含了各种配置项,
菜单文件 Menu 菜单初始化激活 菜单更变逻辑
layout的结构
也是层层结构,需要控制折叠展开,菜单根据打开的url初始化激活,

当前激活的菜单,如过url中有hash或path,需要初始化展开的菜单
初始化时,获取并激活当前应该展开的菜单
SimpleMenu.vue
和菜单变更的逻辑都集中化
const { setOpenKeys, getOpenKeys } = useOpenKeys(1 展开相关的变化watch(() => props.collapse,(collapse) => {if (collapse) {menuState.openNames = [];} else {// 激活当前应该展开的菜单setOpenKeys(currentRoute.value.path);}},{ immediate: true });2 侧边栏items的变化watch(() => props.items,() => {...setOpenKeys(currentRoute.value.path);},{ flush: 'post' })// 路由相关的变化listenerRouteChange((route) {handleMenuChange(if(...) {setOpenKeys()}});async function handleMenuChange(route?: RouteLocationNormalizedLoaded) {async function handleSelect(key: string) {
网络请求 utils/http/axios
- index.ts 入口
**
初始化VAxios,传入业务
并通过transform定制了业务逻辑
transformRequestHooks 后hook,根据code统一的错误弹窗,登录超时的错误提示。
responseInterceptorsCatch 的调用checkStatus,根据网络错误code,展示友好的中文提示。
requestInterceptors 在header中添加token
- Axios.ts 封装了VAxios,
Axios做了什么?
对外暴露一些定制参数,如接口url,是否忽略重复请求等,背后添加的是辅助的能力
对外暴露了transform参数,抽象了请求过程的几个生命周期,供外部进行定制。
beforeRequestHook请求前hook,transformRequestHook,请求后hookrequestInterceptors请求前拦截器,responseInterceptors请求后拦截器requestInterceptorsCatch请求前拦截错误处理,responseInterceptorsCatch
封装了upload上传文件的util
- checkStatus.ts
这个逻辑独立出来,在
Logics?
errorHandle
mitt/routeChange
theme
Hooks 很多逻辑都封装在这里
vue自身也使用了很多hooks的封装
import { useRouter } from 'vue-router';setup(props, { attrs, emit }) {// 这个currentRoute拿到的是响应式的变量const { currentRoute } = useRouter();}
event/useBreakPoint.ts 封装了窗口大小改变的自适应逻辑
一些有用的hooks
useModal
useTable
一些逻辑的封装hooks
顶上的折叠,展开侧边栏的功能。底层数据保存在 vuex 中的 appStore 中,但是不会通过 commit 等方式直接修改数据。而是通过useMenuSetting,提供了方便的get和set的相关API。
// HeaderTrigger// SidebarTriggersetup(){const { getCollapsed, toggleCollapsed } = useMenuSetting();return { getCollapsed, toggleCollapsed };}// useMenuSetting.tsimport { useAppStore } from '/@/store/modules/app';const appStore = useAppStore();const getCollapsed = computed(() => appStore.getMenuSetting.collapsed);// Set menu configurationfunction setMenuSetting(menuSetting: Partial<MenuSetting>): void {appStore.setProjectConfig({ menuSetting });}function toggleCollapsed() {setMenuSetting({collapsed: !unref(getCollapsed),});}
权限 Permession逻辑
底层还是用vuex来存储,商城用usePermisson来提供hooks
// usePermission.tsimport { usePermissionStore } from '/@/store/modules/permission';// 使用Permission的地方import { usePermission } from '/@/hooks/web/usePermission';const { changeRole, hasPermission, togglePermissionMode, refreshMenu } = usePermission();
store/modules/user.ts
login
有内层和外层的 try catch 的处理
logout
阅读的感受
入口清晰,整个应用的 main.ts 和 App.vue ,每个模块部分的 index.ts
逻辑清晰,由浅入深,抽象层次一致,如main.ts中的bootstrap()代码,如 router/guard/index.ts 中
封装,对外暴露参数,如 axios部分 ,业务逻辑和定制部分,都在 index.ts 中可阅读到,其它部分都封装了依赖。
命名,分类清晰
**
// 配置,项目配置import projectSetting from '/@/settings/projectSetting';// app常亮import { PermissionModeEnum } from '/@/enums/appEnum';// 基础的路由import { ERROR_LOG_ROUTE, PAGE_NOT_FOUND_ROUTE } from '/@/router/routes/basic';// sys系统相关的接口import { getMenuList } from '/@/api/sys/menu';import { getPermCode } from '/@/api/sys/user';
都模块化,方便维度router/routes/modulesrouter/menus/modulesstore/modules
异常处理
见 LoginForm 和 userStore.login 的逻辑
有哪些缺点?
逻辑分散?
AppProvider 中有 createBreakpointListen 开启自行应逻辑
SimpleMenu 中有 菜单初始化激活,也许放一起更好?
业务逻辑都写在了store中,如userStore中的login包含了 登录请求,获取用户信息等复杂业务逻辑。是否应该有个service来做处理。
antd pro
登录逻辑,都在redux的effects中,
https://github.com/ant-design/ant-design-pro/blob/master/src/models/login.ts
modles/login
login()
logout()
