Vben Admin 多标签页状态管理源码学习

目录
  • 引言
  • multipleTab.ts 系统锁屏
    • State/Getter
    • Actions

引言

本文将对 Vue-Vben-Admin 的状态管理实现源码进行分析解读,耐心读完,相信您一定会有所收获!

multipleTab.ts 系统锁屏

文件 src\store\modules\multipleTab.ts 声明导出一个store实例 useMultipleTabStore 、一个方法 useMultipleTabWithOutStore()用于没有使用 setup 组件时使用。

// 多标签页信息存储
export const useMultipleTabStore = defineStore({
  id: 'app-multiple-tab',
  state: { /*...*/ },
  getters: { /*...*/ }
  actions:{ /*...*/ }
});
export function useMultipleTabWithOutStore() {
  return useMultipleTabStore(store);
}

State/Getter

状态对象定义了标签页路由列表、缓存标签页名称以及最后一次拖动标签的索引。同时提供了对应方法用于获取该状态值。

// 多标签页状态
export interface MultipleTabState {
  cacheTabList: Set<string>;  // 缓存标签页路由名称
  // 标签页路由列表   RouteLocationNormalized  路由记录的标准化版本
  tabList: RouteLocationNormalized[];
  lastDragEndIndex: number; // 最后一次拖动标签的索引
}
state: (): MultipleTabState => ({
  cacheTabList: new Set(),
  tabList: cacheTab ? Persistent.getLocal(MULTIPLE_TABS_KEY) || [] : [],  // 优先加载缓存/本地存储内容
  lastDragEndIndex: 0,
}),
getters: {
  // 获取标签页路由列表
  getTabList(): RouteLocationNormalized[] {
    return this.tabList;
  },
  // 获取缓存标签页路由名称列表
  getCachedTabList(): string[] {
    return Array.from(this.cacheTabList);
  },
  // 获取最后一次拖动标签的索引
  getLastDragEndIndex(): number {
    return this.lastDragEndIndex;
  },
},

Actions

方法 addTab 方法用于打开标签页。

  • 判断当前打开是否特殊页面(错误处理/登录/重定向)。
  • 若存在已经打开路径相同的标tianj签页,更新其标签页路由记录,否则添加新页面路由记录。
  • 更新需要缓存的标签页路由名称,使用本地存储持久化。
// 打开标签页
async addTab(route: RouteLocationNormalized) {
  // 路由基本属性
  const { path, name, fullPath, params, query, meta } = getRawRoute(route);
  // 错误处理页面 登录 重定向 等页面
  if (
    path === PageEnum.ERROR_PAGE ||
    path === PageEnum.BASE_LOGIN ||
    !name ||
    [REDIRECT_ROUTE.name, PAGE_NOT_FOUND_ROUTE.name].includes(name as string)
  ) {
    return;
  }
  let updateIndex = -1;
  // 标签页已经存在,不在重复添加标签
  const tabHasExits = this.tabList.some((tab, index) => {
    updateIndex = index;
    return (tab.fullPath || tab.path) === (fullPath || path);
  });
  // 标签已经存在,执行更新操作
  if (tabHasExits) {
    const curTab = toRaw(this.tabList)[updateIndex]; // 获取当前标签页路由记录
    if (!curTab) {
      return;
    }
    curTab.params = params || curTab.params; // 从 path 中提取的已解码参数字典
    curTab.query = query || curTab.query; // 从 URL 的 search 部分提取的已解码查询参数的字典。
    curTab.fullPath = fullPath || curTab.fullPath; // URL 编码与路由地址有关。包括 path、 query 和 hash。
    this.tabList.splice(updateIndex, 1, curTab); // 替换原有的标签页路由记录
  } else {
    // 添加标签页
    // 获取动态路由打开数,超过 0 即代表需要控制打开数
    const dynamicLevel = meta?.dynamicLevel ?? -1;
    if (dynamicLevel > 0) {
      // 如果设置大于 0 了,那么就要限制该路由的打开数限制了
      // 首先获取到真实的路由,使用配置方式减少计算开销.
      // const realName: string = path.match(/(\S*)\//)![1];
      const realPath = meta?.realPath ?? '';
      // 获取到已经打开的动态路由数, 判断是否大于某一个值
      if (
        this.tabList.filter((e) => e.meta?.realPath ?? '' === realPath).length >= dynamicLevel
      ) {
        // 关闭第一个
        const index = this.tabList.findIndex((item) => item.meta.realPath === realPath);
        index !== -1 && this.tabList.splice(index, 1);
      }
    }
    this.tabList.push(route); // 添加至路由列表中
  }
  this.updateCacheTab();
  // 使用本地存储持久化
  cacheTab && Persistent.setLocal(MULTIPLE_TABS_KEY, this.tabList);
},

方法updateCacheTab用于更新需要缓存的标签页路由名称,返回一个 Set 集合。若路由中meta中设置ignoreKeepAlivetrue,该标签页不会被缓存。

// 根据当前打开的标签更新缓存
async updateCacheTab() {
  // Set 集合存储
  const cacheMap: Set<string> = new Set();
  for (const tab of this.tabList) {
    const item = getRawRoute(tab);
    // 若忽略KeepAlive缓存 不缓存
    const needCache = !item.meta?.ignoreKeepAlive;
    if (!needCache) {
      continue;
    }
    const name = item.name as string;
    cacheMap.add(name);
  }
  this.cacheTabList = cacheMap; // 存储路由记录名称的 Set 集合
},

方法setTabTitle使用meta属性,将最新标题内容附加到路由上。

// 设置标签标题
async setTabTitle(title: string, route: RouteLocationNormalized) {
  const findTab = this.getTabList.find((item) => item === route);
  if (findTab) {
    findTab.meta.title = title; // meta实现 设置每个页面的title标题
    await this.updateCacheTab();
  }
},

在标签页组件中,根据传入打开页面路由记录tabItem,标签页标题名称绑定计算属性 getTitle

// src\layouts\default\tabs\components\TabContent.vue
<template>
  <Dropdown :dropMenuList="getDropMenuList" :trigger="getTrigger" @menu-event="handleMenuEvent">
    <div :class="`${prefixCls}__info`" @contextmenu="handleContext" v-if="getIsTabs">
      <span class="ml-1">{{ getTitle }}</span>
    </div>
  </Dropdown>
</template>
props: {
  tabItem: {
    type: Object as PropType<RouteLocationNormalized>,
    default: null,
  },
  isExtra: Boolean,
},
// 获取标题信息
const getTitle = computed(() => {
  const { tabItem: { meta } = {} } = props;
  return meta && t(meta.title as string);
});

以上就是Vben Admin 多标签页状态管理源码学习的详细内容,更多关于Vben Admin 多标签页状态管理的资料请关注我们其它相关文章!

(0)

相关推荐

  • Vue-admin-template 报Uncaught (in promise) error问题及解决

    目录 Vue-admin-template 报Uncaught (in promise) error 问题描述 解决问题 Vue常见错误解决 Vue-admin-template 报Uncaught (in promise) error 问题描述 在使用Vue-admin-template时,配置好后端,在请求时,突然报错 而且后端接到请求了,并且返回数据了. 解决问题 找了半天,发现问题在request.js中. 可以发现,是因为状态码不匹配,所以,直接被抛出异常了! 将状态码2000改成自己

  • vue2模拟vue-element-admin手写角色权限的实现

    目录 权限 路由权限 store存储路由 router添加路由 菜单权限 按钮权限 准备:存储按钮标识 指令 函数 权限 路由权限 静态路由:固定的路由,没有权限.如login页面 动态路由:根据不同的角色,后端返回不同的路由接口.通过meta中的roles去做筛选 store存储路由 //地址:store/modules/permission import { routes as constantRoutes } from '@/router' ​ // 根据meta.roles去判断该角色是

  • vue-element-admin按钮级权限管控的实现

    目录 思路 表结构与数据 实现 按钮调用 随着软件的发展,网站从最初的满足用户业务需求到提升用户.就比如一个按钮只要求权限方面的管控我们可以通过 shiro,注解等方式来实现,但是页面上用户点击后没反应或者点击后弹框没权限,这显然不是一个好的用户体验,因此通过前端来实现权限管控也是很有必要的. 思路 1.获取按钮权限2.按钮权限保存在前端全局中 vuex3.页面加载按钮时通过判断权限的存在与否,控制按钮的显示隐藏或者样式选择 PS:事实证明,思路清晰,实现起来就很容易,没几行代码 表结构与数据

  • vue-element-admin开发教程(v4.0.0之后)

    目录 安装&准备工作&ESLint配置 连接后台真数据 Mock 假数据 不需要 Mock 虚拟数据怎么办? 前端拦截器 登陆功能 自定义 vuex 参数 Mock 数据部分代码 由于 vue-element-admin 的架构再 4.0.0 版本后做了重构,所以写这个文章,对改动比较大的部分做个讲解,方便大家入门学习.虽说项目做了重构,但是整体结构上和之前的还是很相似的,所以有些和之前差不多的我会直接放之前文章的链接 由于 Markdown 实在不太会用,这里手动列下目录,毕竟东西有点杂

  • 关于vue-admin-template模板连接后端改造登录功能

    首先修改统一请求路径为我们自己的登陆接口,在.env.development文件中 # base api VUE_APP_BASE_API = 'http://localhost:8081/api/dsxs/company' 打开登陆页面,src/views/login/index.vue <template> <div class="login-container"> <el-form ref="loginForm" :model=&

  • vue-admin-template解决登录和跨域问题解决

    目录 一.下载安装项目 二.修改登录访问地址 三.解决跨域问题 一.下载安装项目 git地址:https://github.com/PanJiaChen/vue-admin-template.git 二.修改登录访问地址 找到 .env.develpment文件 # just a flag ENV = 'development' # base api # VUE_APP_BASE_API = '/dev-api' VUE_APP_BASE_API = 'http://localhost:9001

  • Vben Admin 多标签页状态管理源码学习

    目录 引言 multipleTab.ts 系统锁屏 State/Getter Actions 引言 本文将对 Vue-Vben-Admin 的状态管理实现源码进行分析解读,耐心读完,相信您一定会有所收获! multipleTab.ts 系统锁屏 文件 src\store\modules\multipleTab.ts 声明导出一个store实例 useMultipleTabStore .一个方法 useMultipleTabWithOutStore()用于没有使用 setup 组件时使用. //

  • 详解vue2.0 使用动态组件实现 Tab 标签页切换效果(vue-cli)

    在 vue 中,实现 Tab 切换主要有三种方式:使用动态组件,使用 vue-router 路由,使用第三方插件. 因为这次完成的功能只是简单切换组件,再则觉得使用路由切换需要改变地址略微麻烦,所以使用的是动态组件实现,如果是在大型应用上,可能使用 vue-router 会方便一些. 先看下最终实现的效果,结构比较简单,顶部的三个 Tab 标签用于切换,内容区域分别为三个子组件. 效果预览 关键代码及分析如下: <template> // 每一个 tab 绑定了一个点击事件,传入的参数对应着

  • JS实现仿饿了么在浏览器标签页失去焦点时网页Title改变

    说在前面:必须是基于支持H5的浏览器才可以 这个 API 本身非常简单,由以下三部分组成. document.hidden:表示页面是否隐藏的布尔值.页面隐藏包括 页面在后台标签页中 或者 浏览器最小化 (注意,页面被其他软件遮盖并不算隐藏,比如打开的 sublime 遮住了浏览器). document.visibilityState:表示下面 4 个可能状态的值 hidden:页面在后台标签页中或者浏览器最小化 visible:页面在前台标签页中 prerender:页面在屏幕外执行预渲染处理

  • vue.js实现标签页切换效果

    第二个实例是关于标签页切换的,先看一下效果: 这也是一个很常见的交互效果,以往正常的javascript写法是给各个按钮绑定事件来切换不同的层,当然也可以用纯css写,给上面的三个切换的层分别添加一个单选按钮的兄弟节点,再用绝对定位把单选按钮定位在三个button上面,这样就可以用:checked伪类来单选按钮的兄弟元素,即对应的不同的层,我简单的写了一下DOM结构,大概就是这样: 那么用vue.js实现上述的效果,其实也有两种途径,一种使用vue-router,vue-router是vue.j

  • 如何在Vue.js中实现标签页组件详解

    前言 标签页组件,即实现选项卡切换,常用于平级内容的收纳与展示. 因为每个标签页的内容是由使用组件的父级控制的,即这部分内容为一个 slot.所以一般的设计方案是,在 slot 中定义多个 div,然后在接到切换消息时,再显示或隐藏相关的 div.这里面就把相关的交互逻辑也编写进来了,我们希望在组件中处理这些交互逻辑,slot 只单纯处理业务逻辑.这可以通过再定义一个 pane 组件来实现,pane 组件嵌在 tabs 组件中. 1 基础版 因为 tabs 组件中的标题是在 pane 组件中定义

  • android实现滑动标签页效果的代码解析

    实现效果: 实现功能: ViewPager+Fragment实现加载界面 SQLite数据获取并显示到ListView上 ListView的item监听并携带数据跳转到其他界面 使用SharedPreference存储部分测试数据 实现过程: 各方法和变量的作用请详见代码注释. listview的数据显示请见Android Studio获取SQLite数据并显示到ListView上Fragment+ViewParger实现界面加载 首先要创建两个类并继承Fragment,在viewpager中实

  • 原生JavaScript写出Tabs标签页的实例代码

    最近在重新学习JavaScript,手写了一个tabs标签页. 话不多说,直接开始. 首先,是前端页面. 图1 tabs 先来把tabs分解一下: 图2 tabs分解 首先,一个大的框div,上面红色的框是导航栏nav,导航栏里是一个无序列表ul,里面三个li标签(黄色的框),li标签里两个绿色标签是两个span,一个用来放导航的名字,一个用来放导航关闭的icon,右边是一个button,用来添加新的导航栏及内容:下方是导航栏的内容section. 导航tabs.html代码如下: <!DOCT

  • Ant Design Blazor 组件库的路由复用多标签页功能

    最近,在 Ant Design Blazor 组件库中实现多标签页组件的呼声日益高涨.于是,我利用周末时间,结合 Blazor 内置路由组件实现了基于 `Tabs` 组件的 `ReuseTabs` 组件. 最近,在 Ant Design Blazor 组件库中实现多标签页组件的呼声日益高涨.于是,我利用周末时间,结合 Blazor 内置路由组件实现了基于 Tabs 组件的 ReuseTabs 组件. 前言 Blazor 是 .NET 最新的前端框架,可以基于 WebAssembly 或 Sign

  • Python+Selenium实现浏览器标签页的切换

    目录 selenium 实现浏览器标签页句柄的切换 浏览器标签页本地文件准备 利用 selenium 实现浏览器页面的切换 在实际工作中,我们经常会遇到页面切换的情况.就比如当点击了某个功能的按钮后,浏览器出现了新的标签页,需要在这些标签页之间进行切换.要如何通过 selenium 来实现这样的场景呢?这就是我们今天要学习的内容. selenium 实现浏览器标签页句柄的切换 浏览器标签页本地文件准备 这一段纯粹是因为内容太少,拿来凑字数的... 同样的,这里所使用的是我们本地的 multi.h

  • 浏览器切换到其他标签页或最小化js定时器是否准时测试

    目录 前言 浏览器可见和不可见状态 setInterval setTimeout requestAnimationFrame 总结 如何解决 前言 这是我最近开发碰到的一个问题,本文是我测试出来的实践结果,供大家参考. 关于js定时器,setInterval和setTimeout,作为我们日常开发经常使用到的方法,大家一定非常熟悉.比如下面一个例子: setInterval(() => { console.log('1'); }, 500); 作为刚学前端没多久的新人也能知道,这段代码就是每过5

随机推荐