若依系统前端项目解读——从使用过程解读

news/2024/11/6 3:23:18 标签: 前端

登录系统 

  • 用户初次登录,浏览器中未存用户信息(token),需向后端请求并保存至浏览器中
  • 用户再次登录系统,向后端发请求会携带token在请求头中,并与后端Redis缓存的token比较,判断token是否还在有效期,若失效需要提示用户重新登录(响应拦截器实现),更新token信息

若依框架登录鉴权详解(动态路由)_若依鉴权-CSDN博客

前端登录鉴权——以若依Ruoyi前后端分离项目为例解读_若依鉴权-CSDN博客

210784ba77084501a7a58ab772f1497d.png

前端基础知识:

axios请求封装,封装请求拦截器和响应拦截器

  • 请求:请求头设置、设置防止重复提交(sessionStorage)
//1.headers中的content-type 默认的大多数情况是 (application/json),就是json序列化的格式

//2.为了判断是否为formdata格式,增加了一个变量为type
//如果type存在,而且是form的话,则代表是UrlSearchParams(application/x-www-form-urlencoded)的格式
    // if (config.type && config.type === 'url-form') {
    // config.headers['Content-Type'] = 'application/x-www-form-urlencoded'
    //   //!!!不是所有浏览器都支持UrlSearchParams,可以用qs库编码数据
    //   if (config.data) {
    //     config.data = qs.stringify(config.data)
    //   }
    // }

//3.FormData ('multipart/form-data'), axios会帮忙处理
//Axios 会将传入数据序列化,因此使用 Axios 提供的 API 可以无需手动处理 FormData
  • 响应:根据响应状态码设置对应操作,例如401表示token失效->重新登录(同时清除浏览器Cookie设置的token\permission\role等信息
 if (code === 401) {
      if (!isRelogin.show) {
        isRelogin.show = true;
        MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning' }).then(() => {
          isRelogin.show = false;
          store.dispatch('LogOut').then(() => {
            location.href = process.env.VUE_APP_CONTEXT_PATH + "index";
          })
      }).catch(() => {
        isRelogin.show = false;
      });
    }
//location.href 是一个通用的 Web API,适用于任何 Web 页面,但它在 Vue.js 应用中可能不是最优选择,因为它会重新加载整个页面并丢失当前页面的状态。
//Vue Router 的 push 方法是专门为 Vue.js 应用设计的,它提供了更灵活、更高效的导航方式,并支持 Vue Router 的所有高级功能。

634b2d4b515d40cead482ad60f829173.png

 页面分析

Vue中渲染函数_vue 渲染函数-CSDN博客

main.js:创建vm实例,实例中渲染函数h返回虚拟dom树,最后虚拟dom树挂载至真实dom(id为app:#app)上

new Vue({
  el: '#app',
  router,
  store,
  render: h => h(App)
})

 App.vue,<router-viewer>标签,占位,用于展示路由对应的组件内容->Vue Router

<template>
  <div id="app">
    <router-view />
    <theme-picker />
  </div>
</template>

router/index.js:设置静态路由与配置动态路由

嵌套组件  ​​​​​

5f0774a04c864378b9b7ce24db2bdc27.png

 嵌套路由:

       嵌套路由配置定义在 Layout 组件内部,意味着当访问与这些子路由匹配的路径时,Layout 组件将作为父容器被渲染,而具体的子组件(如 index 对应的组件)则会在 Layout 组件AppMain内部的某个 <router-view> 中被渲染。


{
    path: '',
    component: Layout,
    redirect: 'index',
    children: [
      {
        path: 'index',
        component: () => import('@/views/index'),
        name: 'Index',
        meta: { title: '首页', icon: 'dashboard', affix: true },
      }
    ]
  },

//Layout(src/layout/index)->AppMain.vue(src/layout/components/AppMain.vue)->动态路由[例() => import('@/views/index')]
//level1 Layout(src/layout/index)
<template>
  <div :class="classObj" class="app-wrapper" :style="{'--current-color': theme}">
    <div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside"/>
    <sidebar v-if="!sidebar.hide" class="sidebar-container"/>
    <div :class="{hasTagsView:needTagsView,sidebarHide:sidebar.hide}" class="main-container">
      <div :class="{'fixed-header':fixedHeader}">
        <navbar/>
        <tags-view v-if="needTagsView"/>
      </div>
      <app-main/>
      <right-panel>
        <settings/>
      </right-panel>
    </div>
  </div>
</template>

//level2 AppMain.vue(src/layout/components/AppMain.vue)
<template>
  <section class="app-main">
    <transition name="fade-transform" mode="out-in">
      <keep-alive :include="cachedViews">
        //level3 动态路由
        <router-view v-if="!$route.meta.link" :key="key" />
      </keep-alive>
    </transition>
    <iframe-toggle />
  </section>
</template>

页面布局

Layout/index

<template>
  <div :class="classObj" class="app-wrapper" :style="{'--current-color': theme}">
    <div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside"/>
    <sidebar v-if="!sidebar.hide" class="sidebar-container"/>
    <div :class="{hasTagsView:needTagsView,sidebarHide:sidebar.hide}" class="main-container">
      <div :class="{'fixed-header':fixedHeader}">
        <navbar/>
        <tags-view v-if="needTagsView"/>
      </div>
      <app-main/>
      <right-panel>
        <settings/>
      </right-panel>
    </div>
  </div>
</template>

设备类型监测,根据设备类型设置右侧SideBar是否显示(v-if)

 封装ResizeHander.js mixin混入

 核心

  • window.addEventListener('resize', this.$_resizeHandler)
  • bootstrap's responsive design
  • Vuex
  • <div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside"/>
import store from '@/store'

const { body } = document
const WIDTH = 992 // refer to Bootstrap's responsive design

export default {
  watch: {
    $route(route) {
      if (this.device === 'mobile' && this.sidebar.opened) {
        store.dispatch('app/closeSideBar', { withoutAnimation: false })
      }
    }
  },
  beforeMount() {
    window.addEventListener('resize', this.$_resizeHandler)
  },
  beforeDestroy() {
    window.removeEventListener('resize', this.$_resizeHandler)
  },
  mounted() {
    const isMobile = this.$_isMobile()
    if (isMobile) {
      store.dispatch('app/toggleDevice', 'mobile')
      store.dispatch('app/closeSideBar', { withoutAnimation: true })
    }
  },
  methods: {
    // use $_ for mixins properties
    // https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
    $_isMobile() {
      const rect = body.getBoundingClientRect()
      return rect.width - 1 < WIDTH
    },
    $_resizeHandler() {
      if (!document.hidden) {
        const isMobile = this.$_isMobile()
        store.dispatch('app/toggleDevice', isMobile ? 'mobile' : 'desktop')

        if (isMobile) {
          store.dispatch('app/closeSideBar', { withoutAnimation: true })
        }
      }
    }
  }
}

更改页面布局配置:主题颜色、布局、大小等(vuex+cookie、screenfull库)

1.封装与注册插件(包括$cache 对象、$tab对象、$modal对象)

//plugins/index.js
tab from './tab'
import auth from './auth'
import cache from './cache'
import modal from './modal'
import download from './download'

export default {
  install(Vue) {
    // 页签操作
    Vue.prototype.$tab = tab
    // 认证对象
    Vue.prototype.$auth = auth
    // 缓存对象
    Vue.prototype.$cache = cache
    // 模态框对象
    Vue.prototype.$modal = modal
    // 下载文件
    Vue.prototype.$download = download
  }
}

//plugins/cache.js->sessionStorage/localStorage
......
export default {
  /**
   * 会话级缓存
   */
  session: sessionCache,
  /**
   * 本地缓存
   */
  local: localCache
}

 

2.SCSS变量应用于Javascript中

// the :export directive is the magic sauce for webpack
// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
:export {
  menuColor: $base-menu-color;
  menuLightColor: $base-menu-light-color;
  menuColorActive: $base-menu-color-active;
  menuBackground: $base-menu-background;
  menuLightBackground: $base-menu-light-background;
  subMenuBackground: $base-sub-menu-background;
  subMenuHover: $base-sub-menu-hover;
  sideBarWidth: $base-sidebar-width;
  logoTitleColor: $base-logo-title-color;
  logoLightTitleColor: $base-logo-light-title-color
}
//Vue组件中
 :background-color="settings.sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground"

3.面包屑中首页/目录1/目录1.1  首页重定向功能

$route(newValue,oldValue)监测路由的变化
//template
<el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path">
        <span v-if="item.redirect === 'noRedirect' || index == levelList.length - 1" class="no-redirect">{{ item.meta.title }}</span>
        <a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>
      </el-breadcrumb-item>
//Javascript
 getBreadcrumb() {
      // only show routes with meta.title
      let matched = this.$route.matched.filter(item => item.meta && item.meta.title)
      const first = matched[0]

      if (!this.isDashboard(first)) {
        //在前面附加一个首页,附加后的“首页/系统管理/部门管理"
        matched = [{ path: '/index', meta: { title: '首页' }}].concat(matched)
      }

      this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
    },

 handleLink(item) {
      const { redirect, path } = item
      if (redirect) {
        this.$router.push(redirect)
        return
      }
      this.$router.push(path)
    }
  }

4.flex布局与流式布局

CSS常见适配布局方式_css百分比布局-CSDN博客

 


http://www.niftyadmin.cn/n/5740109.html

相关文章

uniapp在js方法中,获取当前用户的uid(uni-id-user)表中的用户id

// 1.判断当前用的权限 let uid uniCloud.getCurrentUserInfo().uid //获取当前用户的uid // 用户uid等于发布者id或者用户权限等于admin或者用户角色等于webmaster if (uid this.item.user_id[0]._id || this.uniIDHasRole…

只允许指定ip远程连接ssh

我们都会使用securtcrt或者xshell等软件进行远程登录&#xff0c;这样虽然会给我们带来很多便捷&#xff0c;但是同样会存在一定的风险。有很多人专门通过重复的扫描试图破解我们的linux服务器&#xff0c;从而获取免费的“肉鸡”。因此我们可以通过设置hosts.allow和hosts.den…

一个最简单的网络编程

今天总结一下&#xff0c;我至今学的第一个网络编程&#xff0c;也是一个最简单的网络编程。 这篇博客只是将如何用代码实现一个网络编程&#xff0c;具体细节不讲解&#xff0c;后续会介绍详细细节。 网络编程会涉及到客户端和服务器的实现。 1.服务器的实现 首先&#xf…

【图像与点云融合教程(五)】海康相机 ROS2 多机分布式实时通信功能包

0. 前言 Github 仓库链接&#xff1a;Hikvision Camera ROS2 package 0.1 问题背景 上一篇[博客](【图像与点云融合教程&#xff08;四&#xff09;】海康相机 ROS2 功能包 - 古月居 (guyuehome.com))介绍了我开源的海康相机 ROS2 功能包&#xff0c;在本地机器上可以实时订…

【scikit-learn 1.2版本后】sklearn.datasets中load_boston报错 使用 fetch_openml 函数来加载波士顿房价

ImportError: load_boston has been removed from scikit-learn since version 1.2. 由于 load_boston 已经在 scikit-learn 1.2 版本中被移除&#xff0c;需要使用 fetch_openml 函数来加载波士顿房价数据集。 # 导入sklearn数据集模块 from sklearn import datasets # 导入波…

Scala的属性访问权限(一)默认访问权限

//eg:银行账户存钱取钱 // 账户类&#xff1a; // -balance() 余额 // -deposit() 存钱 // -withdraw() 取钱 // -transfer(to:账户,amount:Dobule)转账 package Test1104 //银行账户class BankAccount(private var balance:Int){def showMoney():Unit {println(s"…

针对初学者的PyTorch项目推荐

文章目录 1. MNIST手写数字识别2. CIFAR-10图像分类3. 图像风格迁移4. 文本生成&#xff08;使用RNN&#xff09;5. 简单的问答系统6. 简单的生成对抗网络&#xff08;GAN&#xff09;7. 简单的推荐系统 对于初学者来说&#xff0c;选择一些简单且具有教育意义的项目来实践PyTo…

吴恩达深度学习笔记(11)13.

人脸检校&#xff1a;输入某人的照片以及姓名或ID&#xff0c;判断是不是他所说的那个人 人脸识别&#xff1a; 单样本学习&#xff1a; 大多数人脸识别的问题需要在样本中只有一张照片的情况下认出一个人。 相似性函数&#xff1a;利用神经网络训练一个函数&#xff0c;可…