一, 前端架构Vben页面结构源码分析

本文详细解释了JeecgBoot框架中,从index.html导入main.ts的流程,包括App.vue的注解、登录路由的设置、页面加载顺序,以及核心组件如菜单管理、页面锁定、头部控制和多重Tab标签栏的实现。同时介绍了路由事件监听和组件挂载机制。
摘要由CSDN通过智能技术生成

(一), 概述

本文总结vben,jeecgboot的页面登录前后的文件执行顺序,注释功能,帮助学习了解系统结构体系,或遇到问题时快速定位,或者扩展额外功能。

(二)index.html导入main.ts

index.html入口页文件

<div class="app-loading">
        <div class="app-loading-wrap">
          <img src="/resource/img/logo.png" class="app-loading-logo" alt="Logo" />
          <div class="app-loading-dots">
            <span class="dot dot-spin"><i></i><i></i><i></i><i></i></span>
          </div>
          <div class="app-loading-title"><%= title %></div>
        </div>
      </div>
    </div>
    <script type="module" src="/src/main.ts"></script>  //导入main.ts
  </body>
</html>

(三) main.ts入口主文件

 import '/@/design/index.less';
// 注册 windi(css 组件化)
import 'virtual:windi-base.css';
import 'virtual:windi-components.css';
import 'virtual:windi-utilities.css';
import 'virtual:windi-devtools';
// 注册图标
import 'virtual:svg-icons-register';
import App from './App.vue';  //导入App


    async function bootstrap() { //开始初始化数据
    
// 应用挂载点
    app.mount('#app', true);

(四)App.vue注解

<template>
  <ConfigProvider :locale="getAntdLocale">
    <AppProvider>     //读取app应用组件配置参数
      <RouterView />  //路由器显示区域占位,将被路由的组件components替换(功能页面在这里显示)
    </AppProvider>
  </ConfigProvider>
</template>

<script lang="ts" setup>
  import { ConfigProvider } from 'ant-design-vue';
  import { AppProvider } from '/@/components/Application';
  import { useTitle } from '/@/hooks/web/useTitle';
  import { useLocale } from '/@/locales/useLocale';

  // support Multi-language
  const { getAntdLocale } = useLocale();

  useTitle();    //src\hooks\web\useTitle.ts   //src\hooks\setting\index.ts
                  //src\utils\env.ts             
//读取env中配置数据
                                  //.env,.env. .env.development, .env. //D:\idea-down\jeecgboot-vue3-master\jeecgboot-vue3-//master\.env.production
</script>


(五)、 登录路由


    src\router\routes\index.ts //App初始化构造路由路径
src\router\index.ts  //生成路由器

根目录:有权限的初始访问路径,登录后可进入
    export const RootRoute: AppRouteRecordRaw = {
  path: '/',
  name: 'Root',
  redirect: PageEnum.BASE_HOME,
  meta: {
    title: 'Root',
  },
};
  无权限:访问登录页
export const LoginRoute: AppRouteRecordRaw = {
  path: '/login',
  name: 'Login',
  component: () => import('/@/views/sys/login/Login.vue'),
  meta: {
    title: t('routes.basic.login'),
  },


```typescript
在这里插入代码片

```(六)、 登录页


src\views\sys\login\Login.vue
src\views\sys\login\LoginForm.vue
<Form class="p-4 enter-x" :model="formData" :rules="getFormRules" ref="formRef" v-show="getShow" @keypress.enter="handleLogin">

在handleLogin()处理登录请求
async function handleLogin() {
        const data = await validForm();    //验证表单
        if (!data) return;
        try {
            loading.value = true;
            const {userInfo} = await userStore.login(      //提交登录请求,处理验证过程 
                toRaw({
                    password: data.password,
                    username: data.account,
                    captcha: data.inputCode,
                    checkKey: randCodeData.checkKey,
                    mode: 'none', //不要默认的错误提示
                })
            );
            if (userInfo) {
                notification.success({
                    message: t('sys.login.loginSuccessTitle'),
                    description: `${t('sys.login.loginSuccessDesc')}: ${userInfo.realname}`,
                    duration: 3,
                });
            }
        } catch (error) {
            notification.error({
              message: t('sys.api.errorTip'),
              description:  error.message || t('sys.api.networkExceptionMsg'),
              duration: 3,
            });
            loading.value = false;
        }
    }

src\store\modules\user.ts  //
/**
     * 登录事件
     */
    async login(
      params: LoginParams & {
        goHome?: boolean;
        mode?: ErrorMessageMode;
      },
    ): Promise<GetUserInfoModel | null> {
      try {
        const { goHome = true, mode, ...loginParams } = params;
        const data = await loginApi(loginParams, mode);     //登录成功,返回结果数据
        const { token } = data;
        // save token保存访问令牌
        this.setToken(token);
        return this.afterLoginAction(goHome,data);          //获取登录用户数据
      } catch (error) {
        return Promise.reject(error);                       //登录失败
      }
    },



**登录完成后处理**

/**
     * 登录完成处理
     * @param goHome
     */
    async afterLoginAction(goHome?: boolean,data?:any): Promise<any | null> {
      if (!this.getToken) return null;
      //获取用户信息
      const userInfo = await this.getUserInfoAction();  //获取用户信息
      const sessionTimeout = this.sessionTimeout;
      if (sessionTimeout) {
        this.setSessionTimeout(false);
      } else {
        const permissionStore = usePermissionStore();
        if (!permissionStore.isDynamicAddedRoute) {
          const routes = await permissionStore.buildRoutesAction();   //构建当前权限许可的用户路由,装入菜单与角色权限
          routes.forEach((route) => {
            router.addRoute(route as unknown as RouteRecordRaw);
          });
          router.addRoute(PAGE_NOT_FOUND_ROUTE as unknown as RouteRecordRaw);
          permissionStore.setDynamicAddedRoute(true);
        }
        await this.setLoginInfo(data);
       goHome && (await router.replace(userInfo && userInfo.homePath || PageEnum.BASE_HOME)); //跳转向用户主页或根目录
      }
      return data;
    },
  
BASE_HOME = '/dashboard/analysis',

根目录:有权限的初始访问路径(首页)
    export const RootRoute: AppRouteRecordRaw = {
  path: '/',
  name: 'Root',
  redirect: PageEnum.BASE_HOME,  //指向BASE_HOME = '/dashboard/analysis'
  meta: {
    title: 'Root',
  },


(七)、 主页生成


src\router\routes\modules\dashboard.ts

   const dashboard: AppRouteModule = {
  path: '/dashboard',
  name: 'Dashboard',
  component: LAYOUT,     //导入 import('/@/layouts/default/index.vue')
  redirect: '/dashboard/analysis',
  meta: {
    orderNo: 10,
    icon: 'ion:grid-outline',
    title: t('routes.dashboard.dashboard'),
  },
  children: [
    {
      path: 'analysis',
      name: 'Analysis',
      component: () => import('/@/views/dashboard/Analysis/index.vue'), //主页文件
      meta: {
        // affix: true,
        title: t('routes.dashboard.analysis'),
      },
    },
    {
      path: 'workbench',
      name: 'Workbench',
      component: () => import('/@/views/dashboard/workbench/index.vue'),  //工作页文件
      meta: {
        title: t('routes.dashboard.workbench'),
      },
    },
  ],
};


(八)、 菜单管理:页面构造与组件访问

菜单设置
父级Dashboard对应组件:layouts\default\index.vue
子级Analysis对应组件:/@/views/dashboard/Analysis/index

(九),主页右边栏布局

文件
src\layouts\default\index.vue

布局页

<template>
  <Layout :class="prefixCls" v-bind="lockEvents">
    <LayoutFeatures />      //页面头部特征值
    <LayoutHeader fixed v-if="getShowFullHeaderRef" /> //头部功能区(不显示)
    <Layout :class="[layoutClass]">
      <LayoutSideBar v-if="getShowSidebar || getIsMobile" /> //左边菜单栏
      <Layout :class="`${prefixCls}-main`">
        <LayoutMultipleHeader />      //右边双层头部栏(头部功能区(显示)) 
        <LayoutContent />              //内容组件挂载区域(中间内容区)
        <LayoutFooter />               //脚部
      </Layout>
    </Layout>
  </Layout>
</template>


src\layouts\default\setting\index.vue

<template>
  <LayoutLockPage />
  <BackTop v-if="getUseOpenBackTop" :target="getTarget" />
  <SettingDrawer v-if="getIsFixedSettingDrawer" :class="prefixCls" />
  <SessionTimeoutLogin v-if="getIsSessionTimeout" />
</template>

配置功能页(导航栏样式,系统主题颜色,等)
src\layouts\default\feature\index.vue

<template>
  <div @click="openDrawer(true)">
    <Icon icon="ion:settings-outline" />
    <SettingDrawer @register="register" />
  </div>
</template>

src\layouts\default\setting\SettingDrawer.tsx
输出

<TypePicker
<ThemeColorPicker

等等
右上角设置
打开设置窗口
布局锁
src\layouts\default\feature\index.vue


 <LayoutLockPage />

(十)页面控制锁功能

src\views\sys\lock\index.vue
用户可以给页面加锁,方针其他人进入页面错误操作

<template>
  <transition name="fade-bottom" mode="out-in">
    <LockPage v-if="getIsLock" />
  </transition>
</template>

页面锁文件
src\views\sys\lock\LockPage.vue

(十一),页面头部控制

<LayoutHeader fixed v-if="getShowFullHeaderRef" />

头部菜单栏
src\layouts\default\header\index.vue
页面头部菜单栏

(十二)、 多重Tab标签栏MultipleTabs

<MultipleTabs v-if="getShowTabs" />

src\layouts\default\tabs\index.vue
(后面还有多重标签栏的控制开闭src\store\modules\multipleTab.ts)
在这里插入图片描述

(十三)、 多重标签栏初始化函数initAffixTabs()

setup() {
      const affixTextList = initAffixTabs();  //初始化标签,增加一个固定标签
      const activeKeyRef = ref('');
      useTabsDrag(affixTextList);
      const tabStore = useMultipleTabStore();//引入标签显示状态存储库
      const userStore = useUserStore();//引入用户首选状态存储库
      const router = useRouter();      //引入路由器
      const { prefixCls } = useDesign('multiple-tabs');
      const go = useGo();              //引入跳转方法
      const { getShowQuick, getShowRedo, getShowFold, getTabsTheme } = useMultipleTabSetting();
      const getTabsState = computed(() => {
        return tabStore.getTabList.filter((item) => !item.meta?.hideTab);
      });

(十四)、 多重菜单栏-左边标签菜单栏

在这里插入图片多重菜单栏-左边标签菜单栏描述

<template v-for="item in getTabsState" :key="item.query ? item.fullPath : item.path">
        <TabPane :closable="!(item && item.meta && item.meta.affix)">
          <template #tab>
            <TabContent :tabItem="item" />
          </template>
        </TabPane>
      </template>

(十五)、 多重菜单栏-右边标签菜单栏
在这里插入图片描述
右侧栏

(十六)、 内容区域挂载

src\layouts\default\content\index.vue

 <div :class="[prefixCls, getLayoutContentMode]" v-loading="getOpenPageLoading && getPageLoading">
    <PageLayout />          //内容组件挂载区
    <!-- update-begin-author:zyf date:20211129 for:qiankun 挂载子应用盒子 -->
    <div id="content" class="app-view-box" v-if="openQianKun=='true'"></div>       //乾坤微服务区
    <!-- update-end-author:zyf date:20211129 for: qiankun 挂载子应用盒子-->
  </div>
</template>

(十七)、 组件挂载

src\layouts\page\index.vue

<template>
  <RouterView>
    <template #default="{ Component, route }">    //传入组件
        <keep-alive v-if="openCache" :include="getCaches">
          <component :is="Component" :key="route.fullPath" />//1,可缓存挂载
        </keep-alive>
        <component v-else :is="Component" :key="route.fullPath" />//2,不缓存挂载
    </template>
  </RouterView>
  <FrameLayout v-if="getCanEmbedIFramePage" />   //3,iframe挂载
</template>

注意:动态组件挂载标签<component :is= 的用法,参考其他博文

(十八)、 多重标签栏的控制useMultipleTabs

从(src\layouts\default\tabs\index.vue)中引入辅助
import { useMultipleTabStore } from ‘/@/store/modules/multipleTab’;(重要!!!)
和src\layouts\default\tabs\useMultipleTabs.ts
src\store\modules\multipleTab.ts

(十九). 1 定义多重标签栏MultipleTab

export const useMultipleTabStore = defineStore({
id: ‘app-multiple-tab’,

(二十).2 跳转标签函数goToPage()

  goToPage(router: Router) {

(二十一).3 增加标签函数addTab()

async addTab(route: RouteLocationNormalized) {

(二十二) .4 关闭标签closeTab()

   async closeTab(tab: RouteLocationNormalized, router: Router) {

(二十三)、 标签栏面板容器TabContent

src\layouts\default\tabs\components\TabContent.vue

标签面板控制(下拉控制栏,控制关闭)
src\layouts\default\tabs\useTabDropdown.ts

标签面板控制

(二十四)、 路由事件监听与触发routeChange

src\logics\mitt\routeChange.ts 路由事件监听与触发
src\utils\mitt.ts 事件维护库(各种事件库)

(二十五)、 左边竖栏(竖型菜单栏)

<LayoutSideBar v-if="getShowSidebar || getIsMobile" />

src\layouts\default\sider\index.vue

<MixSider v-else-if="getIsMixSidebar" />

src\layouts\default\sider\MixSider.vue

<Sider v-else />
<ScrollContainer :class="`${prefixCls}-menu-list__content`">

src\components\Container\src\ScrollContainer.vue

<SimpleMenu>

src\components\SimpleMenu\src\SimpleMenu.vue
输出菜单文字

<SimpleMenuTag>

src\components\SimpleMenu\src\SimpleMenuTag.vue

<Menu>
<MenuItem>

边栏布局
src\layouts\default\sider\LayoutSider.vue

LayoutMenu菜单布局
src\layouts\default\menu\index.vue
选择条件输出SimpleMenu(竖向菜单)或BasicMenu(横向菜单)
renderHeader()和renderMenu()

竖向子菜单

(二十六)、 内容页面组成相关文件

src\components\Page\src\PageWrapper.vue—PageWrapper
src\components\Page\index.ts
src\components\Table\src\components\EditTableHeaderIcon.vue—EditTableHeaderIcon
src\components\Table\src\components\HeaderCell.vue—TableHeaderCell
src\components\Table\src\componentMap.ts页面元素:输入,按钮,等
src\components\Table\src\components\editable\CellComponent.ts
src\components\Table\src\components\editable\helper.ts
src\components\Table\src\components\editable\EditableCell.vue
src\components\Table\src\components\settings\ColumnSetting.vue
src\components\Table\src\components\settings\RedoSetting.vue
src\components\Table\src\components\settings\FullScreenSetting.vue
src\components\Table\src\components\settings\index.vue
BasicTableTitle
BasicTableHeader
BasicTableFooter
src\components\Table\src\BasicTable.vue
TableImage

src\utils\common\renderUtils.ts
src\views\system\user\user.data.ts

src\components\jeecg\thirdApp\jThirdApp.api.ts
src\hooks\system\useListPage.ts

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值