热门标签 | HotTags
当前位置:  开发笔记 > 前端 > 正文

Vue实现Tab标签路由效果并用Animate.css做转场动画效果的代码第1/3页

类似于浏览器窗口一样的路由切换逻辑,看着还是挺高大上的,本以为有很多高级的玩意儿,奈何复杂的东西总是由简单的东西拼接而成的,这个功能也不例外

类似于浏览器窗口一样的路由切换逻辑,看着还是挺高大上的,本以为有很多高级的玩意儿,奈何复杂的东西总是由简单的东西拼接而成的,这个功能也不例外。

本篇文章主要描述两个问题:

如何实现这种Tab标签页的路由效果 如何为路由切换添加转场动画。

该功能的开发主要使用到 AntDesignVue 组件库的Tab组件和 Animate.css

效果如下:

 

Tab标签页实现

首先是该组件的模板部分, ContextMenu 组件是我们自定义的右键菜单,后面会说到。 a-tabs 组件则是 ant 的组件,具体用法不详述,可以查看官方文档。还有一个 PageToggleTransition 组件,是我们用来实现动画切换的组件,非常简单。

/**
 * TabLayout.vue 的模板部分,简单看一下有个印象
 */

原理

维护一个 pageList ,通过监听路由变化动态的添加和删除page。而所谓的page,就是页面的路由对象($route),我们正是通过 $route.fullPath 作为页面的唯一标识的。而删除页面时不光要操作 pageList ,还要利用 keep-alive 组件的 exclude 属性删除缓存。至于 a-tabs 组件的这个插槽,主要是为了绑定一个数据key,以便触发contextmenu事件时,可以更容易的获取到对应页面的key值(fullPath)

理论存在,实践开始。

路由监听

watch: {
 $route: {
 handler (route) {
 this.activePage = route.fullPath
 this.putCache(route)
 const index = this.pageList.findIndex(item => item.fullPath === route.fullPath)
 if (index === -1) {
  this.pageList.push(route)
 }
 },
 immediate: true
 }
}

路由变化时,主要做三件事:

  • 设置当前页(activePage)
  • 将当前页加入缓存,即移出垃圾桶(dustbin)
  • 如果当前页不在pageList中,则添加进来。

页面跳转

methods: {
 changePage (key) {
 this.activePage = key
 this.$router.push(key)
 },
 editPage (key, action) {
 if (action === 'remove') {
 this.remove(key)
 }
 },
 remove (key) {
 if (this.pageList.length <= 1) {
 return message.info('最后一页了哦~')
 }
 let curIndex = this.pageList.findIndex(item => item.fullPath === key)
 const { matched } = this.pageList[curIndex]
 const compOnentName= last(matched).components.default.name
 this.dustbin.push(componentName)
 this.pageList.splice(curIndex, 1)
 // 如果删除的是当前页才需要跳转
 if (key === this.activePage) {
 // 判断向左跳还是向右跳
 curIndex = curIndex >= this.pageList.length &#63; this.pageList.length - 1 : curIndex
 const page = this.pageList[curIndex]
 this.$router.push(page.fullPath).finally(() => {
  this.dustbin.splice(0) // 重置,否则会影响到某些组件的缓存
 })
 }
 }
 ...
 ...
}

这里主要主要说一下remove方法:

  • 如果是最后一页,则忽略
  • 在pageList中找到当前页对应的组件名用于删除缓存(这里不清楚的可以看一下 keep-alive组件 ,和 $route.matched )
  • 如果删除的是当前页,需要进行页面跳转,向左挑还是向右跳呢?

需要强调的时 keep-aliveexclude 属性,当组件名被匹配到的时候就会立即清除缓存,所以, dustbin 添加完之后记得要重置,否则下次就不会缓存了。

自定义contextmenu事件

解释下,contextmenu事件就是右键菜单事件,我们可以通过监听事件,使得右键菜单事件触发的时候显示我们的自定义菜单。

methods: {
 // 自定义右键菜单的关闭功能
 onContextmenu (e) {
 const key = getTabKey(e.target) // 这里的判断,用到了前面在span标签上加的data-key自定义属性
 if (!key) return // 主要是为了控制菜单的显示或隐藏

 e.preventDefault() // 组织默认行为,显示我们的自定义邮件菜单
 this.menuVisible = true
 }
 ...
 ...
}
/**
 * 由于ant-design-vue组件库的TabPane组件暂不支持自定义监听器,无法直接获取到右键target所在标签页的key 。故增加此方法用于
 * 查询右键target所在标签页的标识 key ,以用于自定义右键菜单的事件处理。
 * 注:TabPane组件支持自定义监听器后可去除该方法并重构 ‘自定义右键菜单的事件处理'
 * @param target 查询开始目标
 * @param depth 查询层级深度 (查找层级最多不超过3层,超过3层深度直接返回 null)
 * @returns {String}
 */
function getTabKey (target, depth = 0) {
 if (depth > 2 || !target) {
 return null
 }
 return target.dataset.key || getTabKey(target.firstElementChild, ++depth)
}

另外要说的是,dom元素上以 data- 开头的属性会被收录进元素的 dataset 属性中, data-key 访问时就是 dom.dataset.key

下面就是我们的 ContextMenu 组件了:

效果图:

代码如下:





这里需要强调的是钩子函数 created 的内容:

1.首先全局事件需要成对出现,有添加就要有移除,否则可能造成内存泄漏,并导致一些其他的bug。就比如在模块热替换的项目中,会造成反复绑定的问题。

2.为什么这里要给window绑定contextmenu事件和click事件,之前不是绑过了吗?这里的click事件主要是为了关闭菜单,右键菜单的特点是,不论点了什么点了哪里,只要点一下就会关闭。这里的contextmenu事件主要是为了获取到事件对象 event ,以此来设置菜单的位置。而之前绑定在 a-tabs 组件上的contextmenu事件主要是为了阻止默认事件,我们只拦截了该组件,而不需要拦截全局范围。

自定义右键菜单主要是为了 从 event.target 中获取到我们需要的key并以事件的形式传递出来 ,便于分发后面的逻辑,即:

onMenuSelect (key, target) {
 const tabKey = getTabKey(target)
 switch (key) {
 case '1': this.closeLeft(tabKey); break
 case '2': this.closeRight(tabKey); break
 case '3': this.closeOthers(tabKey); break
 default: break
 }
}

这三种情况的逻辑是基本一致的,主要做了三件事:

  1. 清除缓存
  2. 删除页面,并设置当前页面
  3.  页面跳转

以closeOthers为例:

closeOthers (tabKey) {
 const index = this.pageList.findIndex(item => item.fullPath === tabKey) // 找到触发事件时鼠标停留在那个tab上
 for (const route of this.pageList) {
 if (route.fullPath !== tabKey) {
  this.clearCache(route) // 清缓存
 }
 }
 const page = this.pageList[index]
 this.pageList = 
                            
123下一页阅读全文

推荐阅读
  • CSS 百分比单位的取值依据是什么
    本文详细探讨了 CSS 中百分比单位的取值依据,包括不同定位方式下的包含块概念及其应用。通过具体的示例和代码,帮助读者更好地理解和掌握这一知识点。 ... [详细]
  • 本文介绍了 Go 语言中的高性能、可扩展、轻量级 Web 框架 Echo。Echo 框架简单易用,仅需几行代码即可启动一个高性能 HTTP 服务。 ... [详细]
  • malloc 是 C 语言中的一个标准库函数,全称为 memory allocation,即动态内存分配。它用于在程序运行时申请一块指定大小的连续内存区域,并返回该区域的起始地址。当无法预先确定内存的具体位置时,可以通过 malloc 动态分配内存。 ... [详细]
  • 本文介绍了多种开源数据库及其核心数据结构和算法,包括MySQL的B+树、MVCC和WAL,MongoDB的tokuDB和cola,boltDB的追加仅树和mmap,levelDB的LSM树,以及内存缓存中的一致性哈希。 ... [详细]
  • Python多线程详解与示例
    本文介绍了Python中的多线程编程,包括僵尸进程和孤儿进程的概念,并提供了具体的代码示例。同时,详细解释了0号进程和1号进程在系统中的作用。 ... [详细]
  • 本文详细介绍了Linux系统中用于管理IPC(Inter-Process Communication)资源的两个重要命令:ipcs和ipcrm。通过这些命令,用户可以查看和删除系统中的消息队列、共享内存和信号量。 ... [详细]
  • A*算法在AI路径规划中的应用
    路径规划算法用于在地图上找到从起点到终点的最佳路径,特别是在存在障碍物的情况下。A*算法是一种高效且广泛使用的路径规划算法,适用于静态和动态环境。 ... [详细]
  • NX二次开发:UFUN点收集器UF_UI_select_point_collection详解
    本文介绍了如何在NX中使用UFUN库进行点收集器的二次开发,包括必要的头文件包含、初始化和选择点集合的具体实现。 ... [详细]
  • 解决SQL Server数据库sa登录名无法连接的问题
    在安装SQL Server数据库后,使用Windows身份验证成功,但使用SQL Server身份验证时遇到问题。本文将介绍如何通过设置sa登录名的密码、启用登录名状态以及开启TCP协议来解决这一问题。 ... [详细]
  • MySQL 数据库连接方法
    本文介绍了如何使用 MySQL 命令行工具连接到指定的数据库。 ... [详细]
  • 如何解决8080端口被占用问题
    本文介绍了如何通过命令行和任务管理器查找并终止占用8080端口的进程,以确保该端口能够正常使用。 ... [详细]
  • 本文详细介绍了如何在项目中引入和配置KindEditor网页编辑器,包括脚本引用、初始化编辑器以及文件上传功能的实现。 ... [详细]
  • 本文详细介绍了 HTML 中 a 标签的 href 属性的多种用法,包括实现超链接、锚点以及调用 JavaScript 方法。通过具体的示例和解释,帮助开发者更好地理解和应用这些技术。 ... [详细]
  • Excel 数据分析基础
    Excel 是数据分析中最基本且强大的工具之一,具备多种实用功能和操作方法。本文将简要介绍 Excel 的不同版本及其兼容性问题,并探讨在处理大数据时的替代方案。 ... [详细]
  • 本文介绍了如何在 ASP.NET 中设置 Excel 单元格格式为文本,获取多个单元格区域并作为表头,以及进行单元格合并、赋值、格式设置等操作。 ... [详细]
author-avatar
手机用户2502881923
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有