实现 Vue 标签页切换效果的组件开发

在本次开发中,我们将实现一个 Vue 组件,用于展示和切换标签页。
背景有移动动画效果
在这里插入图片描述
在这里插入图片描述

该组件将具有以下功能:

  • 标签页左右滚动
  • 点击标签页切换内容
  • 关闭指定标签页
  • 支持多种标签页风格

以下是实现该组件的具体步骤:

  1. 创建 Vue 组件

    <template>
      <!-- 
    	tag-items-smooth  圆润
    .tag-items-card 卡片
    .tag-items-smart 灵动的
    -->
    	<div class="tacscontainerwidth tag-items-smart" :style="{ width: tabconf.tacscontainerwidth }">
    		<!-- 左箭头按钮 -->
    		<el-icon @click="scrollLeft">
    			<ArrowLeft />
    		</el-icon>
    		<!-- 标签滚动条容器 -->
    		<div class="tacspage" :style="{ width: tabconf.tacspagewidth }" ref="scrollbarRef">
    			<!-- 标签内容容器 -->
    			<div class="tag-items" :style="{ transform: `translateX(` + tabconf.translateX + `px)` }" ref="innerRef">
    				<!-- 标签项 -->
    				<div v-for="(item, index) in tabconf.tacsitems"
    					:class="index === tabconf.activeIndex ? 'basistag basis-tag-item active' : 'basistag basis-tag-item'"
    					style="z-index:99;width: max-content;" ref="tabsRefs" @click="tagitemchange(index)">
    					
    					<!-- 标签内容 -->
    					<div style="width: max-content;">
    						
    						<!-- 标签图标 -->
    						<component :is="item.icon" style="width: 15px;margin-right: 5px;" />
    						<!-- 标签标题 -->
    						<span style="width: max-content;" :data-index="index">{{ item.title }}</span>
    					</div>
    					<!-- 关闭图标 -->
    					<el-icon class="tacscontainerwidth-Close"  @click="closeTagItem(index)" style="">
    						<Close />
    					</el-icon>
    					
    				</div>
    				<!-- 选中标签页的指示框-背景图-->
    				<div :style="activeBoxStyle" class="nav-tabs-active-box"></div>
    			</div>
    		</div>
    		     <!-- 右箭头按钮 -->
    		<el-icon @click="scrollRight">
    			<ArrowRight />
    		</el-icon>
    		<!-- 更多下拉 -->
    		<el-dropdown style="margin-left: 15px;">
    			<span class="username-span">
    				<!-- 更多图标 -->
    				<el-icon>
    					<Grid />
    				</el-icon>
    			</span>
    			<template #dropdown>
    				<el-dropdown-menu>
    					<!-- <el-dropdown-item command="user">刷新</el-dropdown-item> -->
    					<el-dropdown-item @click="CloseTagItemLeft()">关闭左侧</el-dropdown-item>
    					<el-dropdown-item @click="CloseTagItemRight()">关闭右侧</el-dropdown-item>
    					<el-dropdown-item @click="CloseTagItemOther()">关闭其他</el-dropdown-item>
    					<el-dropdown-item @click="CloseTagItemAll()">关闭全部</el-dropdown-item>
    				</el-dropdown-menu>
    			</template>
    		</el-dropdown>
    	</div>
    </template>
    
  2. 引入所需的图标和组件

  3. 定义组件的样式(还没优化好、请自己定义)

    
<style scoped lang="scss">
  .fade-enter-active,
	.fade-leave-active {
		transition: opacity 0.3s;
	}

	.fade-enter,
	.fade-leave-to

	/* .fade-leave-active below version 2.1.8 */
		{
		opacity: 0;
	}

	.tacscontainerwidth {
		display: flex;
		align-items: center;
		position: absolute;

		.tacspage {

			overflow-y: hidden;
			overflow-x: scroll;
			scrollbar-width: none;
			-ms-overflow-style: none;
			/* 隐藏滚动条 */
		}
	}


	.tag-items {
		// white-space: nowrap;position: relative;
		//    transition: transform 0.3s ease; 
		display: flex;
		white-space: nowrap;
		position: relative;
		transition: transform var(--el-transition-duration);
		float: left;
	}

	.tag-items-card .basis-tag-item {
		margin-left: 10px;
		border: 1px solid #ccc;
		display: flex;
		display: flex;
		align-items: center;
		justify-items: center;
	}

	.tag-items-smooth .basis-tag-item {
		margin-left: 10px;
		border: 1px solid #ccc;
		border-radius: 5px;
		// width: 100px;
		display: flex;
		align-items: center;
		justify-items: center;
	}

	.tag-items-smart .basis-tag-item {
		margin-left: 10px;
		border: 0px;
		display: flex;
		align-items: center;
	}

	.basis-tag-item * {
		flex-shrink: 0;
		// display: flex;
		// align-items: center;
		// justify-items: center;

	}

	.nav-tabs-active-box {
		position: absolute;
		height: 5px;
		bottom: 0px;
		border-radius: var(--el-border-radius-base);
		background-color: #fcc;
		box-shadow: var(--el-box-shadow-light);
		transition: all 0.2s;
		-webkit-transition: all 0.2s;
		z-index: 2;
	}

	.basis-tag-item {
		padding: 5px;
	}


	.tag-items-smart .basis-tag-item {
		color: var(--el-color-info-light-3);
		// background-color: var(--el-menu-bg-color);
	}

	.active {
		color: var(--el-menu-text-color);

		// background-color: var(--el-menu-bg-color);
		border-bottom: 2px solid var(--el-menu-text-color);
		// background-color: #cfc;
	}

.tacscontainerwidth-Close{margin-left: 5px;width: 14px;    position: relative;
          font-size: 12px; 
          height: 14px;
          overflow: hidden;
          right: -2px;
          transform-origin: 100% 50%;}
	@keyframes moveBackground {
		0% {
			background-position: left top;
		}

		100% {
			background-position: right top;
		}
	}
    </style>
  1. 定义组件的数据和方法

    <script setup lang="ts">
    import { onMounted, reactive, watchEffect, toRefs, ref, watch } from 'vue';
    
    // 定义组件的数据
    const tabconf = reactive({
      // 偏移量
      max: 0,
      // 偏移量
      translateX: 0,
      // 标签长度
      tacspagewidth: "100%",
      // 激活 tab 的 index
      activeIndex: 3,
      // 激活的 tab
      activeRoute: "",
      // tab 列表
      tacsitems: [
        { id: 1, title: "测试 1", icon: "Edit", path: "path" },
        { id: 2, title: "测试 2", icon: "Edit", path: "path" },
        { id: 3, title: "测试 3", icon: "Edit", path: "path" },
        { id: 4, title: "测试 4", icon: "Edit", path: "path" },
        { id: 5, title: "测试 5", icon: "Edit", path: "path" },
        { id: 6, title: "测试 6", icon: "Edit", path: "path" },
        { id: 7, title: "测试 7", icon: "Edit", path: "path" },
        { id: 8, title: "测试 8", icon: "Edit", path: "path" },
        { id: 9, title: "测试 9", icon: "Edit", path: "path" },
        { id: 10, title: "测试 10", icon: "Edit", path: "path" },
        { id: 11, title: "测试 11", icon: "Edit", path: "path" },
        { id: 12, title: "测试 12", icon: "Edit", path: "path" },
        { id: 13, title: "测试 13 测试测试", icon: "Edit", path: "path" },
        { id: 14, title: "测试 14", icon: "Edit", path: "path" },
        { id: 15, title: "测试 15", icon: "Edit", path: "path" },
        { id: 16, title: "测试 16", icon: "Edit", path: "path" },
        { id: 17, title: "测试 17", icon: "Edit", path: "path" },
        { id: 18, title: "测试 18", icon: "Edit", path: "path" },
        { id: 19, title: "测试 19", icon: "Edit", path: "path" },
        { id: 20, title: "测试 20", icon: "Edit", path: "path" },
      ],
      // 容器宽度
      tacscontainerwidth: "50%"
    });
    
    // 定义组件的方法
    // 向左滚动标签页
    function scrollLeft() {
      tabconf.translateX -= 100;
    }
    
    // 向右滚动标签页
    function scrollRight() {
      tabconf.translateX += 100;
    }
    
    // 关闭所有标签页
    function CloseTagItemAll() {
      tabconf.tacsitems.splice(1, tabconf.tacsitems.length);
      tabconf.activeIndex = 0;
      tabconf.activeRoute = tabconf.tacsitems[0].path;
    }
    
    // 关闭其他标签页
    function CloseTagItemOther() {
      CloseTagItemRight();
      CloseTagItemLeft();
    }
    
    // 关闭左侧标签页
    function CloseTagItemLeft() {
      if (tabconf.activeIndex === 0) {
        tabconf.activeIndex = 0;
        tabconf.activeRoute = tabconf.tacsitems[0].path;
      } else {
        tabconf.tacsitems.splice(1, tabconf.activeIndex - 1);
        tabconf.activeIndex = 1;
        tabconf.activeRoute = tabconf.tacsitems[1].path;
      }
    }
    
    // 关闭右侧标签页
    function CloseTagItemRight() {
      const length = tabconf.tacsitems.length - tabconf.activeIndex;
      tabconf.tacsitems.splice(tabconf.activeIndex + 1, length);
    }
    
    // 关闭指定索引的标签页
    function closeTagItem(index) {
      tabconf.tacsitems.splice(index, 1);
      if (tabconf.activeIndex >= index) {
        tabconf.activeIndex--;
      } else if (tabconf.activeIndex < 0) {
        tabconf.activeIndex = 0;
      }
    }
    
    // 切换标签页
    function tagitemchange(index) {
      tabconf.activeIndex = index;
      tabconf.activeRoute = tabconf.tacsitems[index].path;
    }
    
    // 初始化组件
    onMounted(() => {
      settagitemchange();
    });
    
    // 设置标签页切换的样式
    function settagitemchange() {
      const event = tabsRefs.value[tabconf.activeIndex];
      const element = event;
      const index = tabconf.activeIndex;
      const tacsitems = tabconf.tacsitems;
      tabconf.activeIndex = index;
      tabconf.activeRoute = tabconf.tacsitems[index].path;
    
      // 计算活动标签页的宽度
      const width = element.offsetWidth;
      // 获取元素的水平滚动位置
      const offsetLeft = element.offsetLeft;
      activeBoxStyle.width = width + 'px';
      activeBoxStyle.transform = `translateX(${offsetLeft}px)`;
    }
    
    // 用于更新缓存的函数,当前为空实现
    function UpdateCache() {
    
    }
    </script>
    
  2. 在模板中使用组件

通过以上步骤,我们实现了一个具有标签页切换功能的 Vue 组件。在实际应用中,可以根据需要进一步扩展和定制组件的功能。

希望这篇开发博客对你有所帮助!如果你有任何问题或建议,请随时留言。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/651645.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

APM2.8下载固件的方法(两种办法详解)

1.把APM飞控用安卓手机的USB线插入电脑。 选择COM口&#xff0c;不要选择auto&#xff0c;如果你没有COM口说明你驱动安装有问题。 波特率115200。点击相应的图标就可以下载固件到飞控板。 请注意&#xff1a;烧录APM必须选择INSTALL FIRMWARE LEAGACY,第一个是用于刷pixhawk的…

数据泄露防护:企业如何通过软件限制U盘使用

在数字化办公时代&#xff0c;数据安全已成为企业运营中的一个关键议题。U盘作为一种便携式的数据存储和传输工具&#xff0c;其使用在企业内部非常普遍。然而&#xff0c;U盘的不当使用也可能导致严重的数据泄露问题。本文将探讨企业如何通过软件解决方案&#xff0c;有效限制…

2024 年科技裁员综合清单

推荐阅读&#xff1a; 独立国家的共同财富 美国千禧一代的收入低于父辈 创造大量就业机会却毁掉了财富 这四件事是创造国家财富的关键 全球财富报告证实联盟自始至终无能 美国人已陷入无休止债务循环中&#xff0c;这正在耗尽他们的财务生命 2024 年&#xff0c;科技行业…

告别低效率||智能BI财务分析软件

在当今信息爆炸的时代&#xff0c;财务数据作为企业运营的核心&#xff0c;其处理和分析的效率直接关系到企业的决策速度和市场竞争力。奥威BI软件凭借其卓越的性能和智能化的分析功能&#xff0c;为企业提供了一套高效、准确的财务分析解决方案。 奥威BI软件在财务分析中的优…

行为设计模式之职责链模式

文章目录 概述原理代码实现小结 概述 职责链模式(chain of responsibility pattern) 定义: 避免将一个请求的发送者与接收者耦合在一起,让多个对象都有机会处理请求.将接收请求的对象连接成一条链,并且沿着这条链传递请求,直到有一个对象能够处理它为止. 在职责链模式中&…

【Mybatis】映射文件获取新增记录的id

我们在讲JDBC的时候讲过在插入新数据值的时候需要获得到自动生成的那个主键id的值 ①获取PreparedStatement的对象的时候 PreparedStatement st conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS ); ②在执行SQL语句后 st.executeUpdate();ResultSet rs st.ge…

Springboot项目——博客平台

前言&#xff1a;为巩固之前学习的知识&#xff0c;同时锻炼自己的代码能力&#xff0c;项目经验&#xff0c;熟悉前后端交互方式等&#xff0c;特此完成一个博客平台系统。&#xff08;总之&#xff0c;为了学习&#xff0c;为了进步&#xff09; 博客平台&#xff1a;本项目…

QQ名片满级会员装x助手HTML源码

源码介绍 QQ名片满级会员展示生成HTML源码&#xff0c;源码由HTMLCSSJS组成&#xff0c;双击html文件可以本地运行效果&#xff0c;也可以上传到服务器里面&#xff0c;保存素材去选择QQ个性名片-选择大图模板-把图上传照片墙即可 源码效果 源码下载 蓝奏云&#xff1a;http…

如何远程访问Redis?

远程访问Redis是一种常见的需求&#xff0c;特别是在分布式系统或跨地域网络中。通过远程访问&#xff0c;我们可以轻松地对远程的Redis数据库进行操作和管理。 天联保障数据安全 对于远程访问Redis的安全性问题&#xff0c;我们可以借助天联来保障数据的安全。天联是一种基于…

mybatisplus填充公共字段MetaObjectHandler后不生效解决方式

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; import org.apache.ibatis.reflection.MetaObject; import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Component;import java.util.Date;/*** 拦截处理公共字…

开发一个comfyui的自定义节点

文章目录 目标功能开发环境comfyui自定义节点的实现原理仓库地址完整代码目标功能 开发一个comfyui的自定义节点,该节点的功能是:可以对comfyui工作流中最终输出的图像添加一些自定义文案,且可以指定文案在图像上的位置、文案的字体样式、字体大小、字体颜色等。最终效果如…

全网讲的最详细的Docker镜像分层存储原理

先说结论&#xff0c;容器镜像分层存储图示 欢迎关注 实验环境准备 当前实验docker版本24.0.7如下&#xff0c;当前docker版本使用overlay2机制存储镜像 Client: Docker Engine - CommunityVersion: 24.0.7API version: 1.43Go version: go1.20.10…

YOLOv8+PyQt5西红柿成熟度检测系统完整资源集合(yolov8模型,从图像、视频和摄像头三种路径识别检测,包含登陆页面、注册页面和检测页面)

西红柿成熟度检测&#xff08;https://mbd.pub/o/bread/mbd-ZpWbk5ly&#xff09;_哔哩哔哩_bilibili 资源包含可视化的西红柿成熟度检测系统&#xff0c;基于最新的YOLOv8训练的西红柿成熟度检测模型&#xff0c;和基于PyQt5制作的可视化西红柿成熟度检测系统&#xff0c;包含…

系统思考—战略沙盘推演咨询服务

今日与JSTO团队一起学习了《战略沙盘推演咨询服务》。通过沙盘体验&#xff0c;我深刻感受到组织与战略就像一张皮的正反两面。在转型过程中&#xff0c;即使战略非常明确&#xff0c;团队成员由于恐惧和顾虑&#xff0c;往往不愿意挑战新的业务&#xff0c;从而难以实现战略目…

创新实训2024.05.28日志:记忆化机制、基于MTPE与CoT技术的混合LLM对话机制

1. 带有记忆的会话 1.1. 查询会话历史记录 在利用大模型自身能力进行对话与解答时&#xff0c;最好对用户当前会话的历史记录进行还原&#xff0c;大模型能够更好地联系上下文进行解答。 在langchain chat chat的chat函数中&#xff0c;通过实现langchain框架提供的ChatMemo…

虚拟化技术 分布式资源调度

一、实验内容 实现分布式资源调度 二、实验主要仪器设备及材料 安装有64位Windows操作系统的台式电脑或笔记本电脑&#xff0c;建议4C8G或以上配置已安装VMware Workstation Pro已安装Windows Server 2008 R2 x64已安装vCenter Server 三、实验步骤 将主机esxi1和esxi2加入…

【找出缺失的观测数据】python

思路&#xff1a; 主要在于分配剩余的部分分配问题 代码&#xff1a; class Solution:def missingRolls(self, rolls: List[int], mean: int, n: int) -> List[int]:m len(rolls)total_sum (n m) * meantoset total_sum - sum(rolls)# 检查 toset 是否在可能的范围内i…

R可视化:可发表的prism点图

介绍 可发表的prism点图 加载R包 knitr::opts_chunk$set(echo = TRUE, message = FALSE, warning = FALSE) library(tidyverse) library(ggpubr) library(ggprism)rm(list = ls()) options(stringsAsFactors = F)导入数据 data("iris")head(iris)处理数据 plotd…

git stash 命令

线上版本出现了bug&#xff0c;我们应该放下手头上的开发工作先将线上的bug修复&#xff0c;这个时候dev分支下的改动怎么处理&#xff1f; 是向分支行上提交代码还是直接切换到master分支下&#xff1f; 首先我们的开发工作还未完成&#xff0c;就把代码提交到分支上&#xf…

安装ROS 2 Jazzy Jalisco

参考&#xff1a; https://docs.ros.org/en/jazzy/Installation/Ubuntu-Install-Debians.html 先要安装一个ubuntu&#xff0c;对老旧硬件最友好的版本Lubuntu&#xff1a; 安装Lubuntu24.04-CSDN博客 过程&#xff1a; 按文档一步步走下去&#xff1a; 遇到问题查找通用案…