使用vue3模拟element-ui中el-tabs的实现

news2024/11/13 15:18:37

一. 最终实现

组件没有背景颜色, 为了凸显组件文字,才设置了背景颜色
在这里插入图片描述

二. 使用

<wq-tabs v-model="activeName" style="background:grey; padding: 20px">
	<wq-tab-pane label="User" name="first">User</wq-tab-pane>
	<wq-tab-pane label="Config" name="second">Config</wq-tab-pane>
	<wq-tab-pane label="Role" name="third">Role</wq-tab-pane>
	<wq-tab-pane label="Task" name="fourth">Task</wq-tab-pane>
</wq-tabs>

嘿嘿

三. 代码

type.ts

export interface WqTabItem {
	label: string; // 标签
	name: string; // 唯一标识
	disabled?: boolean; // 是否禁用
}

constant.ts

export const WQ_TABS_PROVIDE = Symbol();

是的, 这个文件只有一行代码, 主要用于 tabs组件 与 tab-pane 之间使用依赖注入的标识

WqTabs.vue

<template>
	<div class="wq-tabs">
		<tab-nav :active-name="activeName" :on-tab-click="handleTabClick" :tab-item-arr="tabsArr"></tab-nav>
		<slot></slot>
	</div>
</template>

<script setup lang="tsx">
import { computed, onMounted, provide, ref, useSlots } from 'vue';
import tabNav from './wq-tab-nav.vue';
import { WQ_TABS_PROVIDE } from '@/components/WqTabs/constant';
import { WqTabItem } from '@/components/WqTabs/type';

type Props = {
	modelValue: string;
	beforeLeave?: (newTabName: string, oldTabName: string) => boolean | Promise<boolean>;
};

const props = withDefaults(defineProps<Props>(), { beforeLeave: () => true });
const emits = defineEmits<{ (name: 'tabClick', tabItem: any): void; (name: 'update:modelValue', value: string): void }>();
// 需要nav渲染的数据
const tabsArr = ref<any[]>([]);
// 当前激活的name
const activeName = computed({
	get() {
		return props.modelValue;
	},
	set(newVal) {
		emits('update:modelValue', newVal);
	},
});

// 将激活的名字提供给自组件使用
provide(WQ_TABS_PROVIDE, activeName);

const slots = useSlots();
const calcTabItems = () => {
	if (slots.default) {
		// 收集wq-tabs中间的插槽内容
		let slotTabItemArr = slots.default();
		// 收集他们的props数据
		tabsArr.value = slotTabItemArr.map((item) => {
			return { ...item.props };
		});
	} else {
		tabsArr.value = [];
	}
};
calcTabItems();

// 可能有异步
const setCurrentName = async (newTabName: string) => {
	let oldTabName = activeName.value;
	const res = await props.beforeLeave(newTabName, oldTabName);
	if (res) {
		activeName.value = newTabName; // 自身也更新一下
	}
};

const handleTabClick = (tabItem: WqTabItem) => {
	// 触发父组件的事件, 将当前点击的tab作为参数传给父组件
	emits('tabClick', tabItem);
	// 更新
	setCurrentName(tabItem.name);
};
</script>

↑↑↑这里使用了useSlots()来获取插槽内容,
提取props中的数据, 交给nav进行渲染

WqTabNav.vue

<template>
	<div class="wq-tab-nav">
		<div
			v-for="(tabItem, index) in tabItemArr"
			:key="index"
			:class="['wq-tab-nav-item', tabItem.name === activeName ? 'highLight' : '', tabItem.disabled ? 'isForbiddenItem' : '']"
			@click="changeActiveName(tabItem)"
		>
			{{ tabItem.label }}
		</div>
	</div>
</template>
<script setup lang="ts">
import { WqTabItem } from '@/components/WqTabs/type';

type Prop = {
	tabItemArr: WqTabItem[];
	activeName: string;
	onTabClick?: (tabItem: WqTabItem) => void;
};

const props = withDefaults(defineProps<Prop>(), {
	tabItemArr: () => [],
	activeName: '',
	onTabClick: () => {},
});

// 更换激活
const changeActiveName = (tabItem: any) => {
	// 点自己不执行
	if (tabItem.name === props.activeName) {
		return;
	}
	// 禁用不执行
	if (tabItem.disabled) {
		return;
	}
	props.onTabClick(tabItem);
};
</script>
<style lang="scss" scoped>
.wq-tab-nav {
	width: 100%;
	//border-bottom: 1px solid #e9e9e9;
	&-item {
		display: inline-block;
		height: 40px;
		line-height: 40px;
		font-size: 14px;
		font-weight: 500;
		color: #303133;
		margin: 0 12px;
		cursor: pointer;
	}
	&-item:not(.isForbiddenItem):hover {
		color: #409eff;
	}
	// 高亮项样式
	.highLight {
		color: #409eff;
		border-bottom: 2px solid #409eff;
	}
	// 禁用项样式
	.isForbiddenItem {
		cursor: not-allowed;
		color: #aaa;
	}
}
</style>

wq-tab-pane.vue

<template>
	<div v-show="isActive" class="wq-tab-pane">
		<slot></slot>
	</div>
</template>
<script setup lang="ts">
import { computed, inject, Ref } from 'vue';
import { WQ_TABS_PROVIDE } from '@/components/WqTabs/constant';

type Props = {
	label: string;
	name: string;
	disable?: boolean;
};

const props = withDefaults(defineProps<Props>(), {
	disable: false,
});

// 激活状态
const isActive = computed(() => {
	// 使用 inject 获取被激活的内容
	const navActive = inject<Ref<string>>(WQ_TABS_PROVIDE);
	const activeName = navActive?.value;
	const currentName = props.name;
	return activeName === currentName;
});
</script>

<style lang="scss" scoped>
.wq-tab-pane {
	padding: 12px;
}
</style>

四. 缺陷

写的不是很灵活, 不能动态更新
若tab-pane是动态的, 会有nav不刷新的情况

嘿嘿~

等组件再实现的灵活一些再来填坑

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

多任务高斯过程数学原理和Pytorch实现示例

高斯过程其在回归任务中的应用我们都很熟悉了&#xff0c;但是我们一般介绍的都是针对单个任务的&#xff0c;也就是单个输出。本文我们将讨论扩展到多任务gp&#xff0c;强调它们的好处和实际实现。 本文将介绍如何通过共区域化的内在模型(ICM)和共区域化的线性模型(LMC)&…

驱动LSM6DS3TR-C实现高效运动检测与数据采集(10)----融合磁力计进行姿态解算

驱动LSM6DS3TR-C实现高效运动检测与数据采集.10--融合磁力计进行姿态解算 概述视频教学样品申请源码下载硬件准备DataLogFusion磁力计校准过程初始化磁力计MFX_Arithmetic_Init卡尔曼滤波算法演示 概述 MotionFX库包含用于校准陀螺仪、加速度计和磁力计传感器的例程。 将磁力计…

【网络】windows和linux互通收发

windows和linux互通收发 一、windows的udp客户端代码1、代码剖析2、总体代码 二、linux服务器代码三、成果展示 一、windows的udp客户端代码 1、代码剖析 首先我们需要包含头文件以及lib的一个库&#xff1a; #include <iostream> #include <WinSock2.h> #inclu…

swiftui中onChange函数的使用,监听变量的变化

在 SwiftUI 中&#xff0c;onChange 修饰符用于在指定值发生变化时执行某些操作。它允许你监听一个状态或绑定值的变化&#xff0c;并在变化发生时运行一些代码。这个功能非常适合需要对状态变化做出响应的场景。 使用示例&#xff1a; struct AppStorageTest: View {State p…

友力科技数据中心搬迁方案

将当前运行机房中的所有设备、应用系统安全搬迁至新数据中心机房&#xff0c;实现平滑切换、平稳过渡&#xff0c;最大限度地降低搬迁工作对业务的影响。 为了确保企事业单位能够顺利完成数据中心机房搬迁工作&#xff0c;我们根据实际经验提供了4个基本原则&#xff0c;希望能…

【Linux】编辑器vscode与linux的联动

1.vscode简单学习 vscode是编辑器&#xff0c;可以写各种语言的程序 下载链接&#xff1a;Download Visual Studio Code - Mac, Linux, Windows 来用一下vscode 我们保存了就能在我们的那个文件夹里面看到这个 这个就是编辑器&#xff0c;跟我们的文本文件好像差不多&#…

RPM、YUM 安装 xtrabackup 8 (mysql 热备系列一)包含rpm安装 mysql 8 配置主从

RPM安装 percona-xtrabackup-80-8.0.35-30.1.el7.x86_64.rpm 官网&#xff1a; https://www.percona.com/ 下载地址&#xff1a; https://www.percona.com/downloads wget https://downloads.percona.com/downloads/percona-distribution-mysql-ps/percona-distribution-mysq…

51单片机14(独立按键实验)

一、按键介绍 1、按键是一种电子开关&#xff0c;使用的时候&#xff0c;只要轻轻的按下我们的这个按钮&#xff0c;按钮就可以使这个开关导通。 2、当松开这个手的时候&#xff0c;我们的这个开关&#xff0c;就断开开发板上使用的这个按键&#xff0c;它的内部结构&#xff…

从千台到十万台,浪潮信息InManage V7解锁智能运维密码

随着大模型技术的深度渗透&#xff0c;金融行业正经历着前所未有的智能化变革。从“投顾助手”精准导航投资蓝海&#xff0c;到“智能客服”秒速响应客户需求&#xff0c;大模型以其对海量金融数据的深度挖掘与高效利用&#xff0c;正显著提升金融服务的智能化水准&#xff0c;…

Java:拦截器简介和应用示例(多个拦截器+校验token是否为空)

JAVA 拦截器 简介 拦截器和过滤器均可以拦截http请求&#xff0c;过滤器偏向于基础设施工作&#xff0c;拦截器偏向于业务&#xff0c;拦截器允许在执行Controller之前做验证预处理&#xff0c;在Controller执行之后对返回对象做加工处理。可以用于&#xff1a;权限检查、日志…

2014年全国大学生数学建模竞赛C题生猪养殖管理(含word论文和源代码资源)

文章目录 一、部分题目二、部分论文三、部分源代码四、完整word版论文和源代码 一、部分题目 2014高教社杯全国大学生数学建模竞赛题目 C题 生猪养殖场的经营管理 某养猪场最多能养10000头猪&#xff0c;该养猪场利用自己的种猪进行繁育。养猪的一般过程是&#xff1a;母猪配…

第3关 -- Git 基础知识

任务1: 破冰活动&#xff1a;自我介绍 任务2: 实践项目&#xff1a;构建个人项目 MeiHuaYiShu

【BUG】已解决:ModuleNotFoundError: No module named ‘_ctypes‘

已解决&#xff1a;ModuleNotFoundError: No module named ‘_ctypes‘ 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c;我是博主英杰&#xff0c;211科班出身&#xff0c;就职于医疗科技公司&#xff0c;热衷分享知识&#xff0c;武汉城…

【Langchain大语言模型开发教程】记忆

&#x1f517; LangChain for LLM Application Development - DeepLearning.AI 学习目标 1、Langchain的历史记忆 ConversationBufferMemory 2、基于窗口限制的临时记忆 ConversationBufferWindowMemory 3、基于Token数量的临时记忆 ConversationTokenBufferMemory 4、基于历史…

双笼转子感应电机建模仿真(2):任意速旋转坐标系下xy/xy数学模型及仿真模型

1.概述 2. 双笼转子三相感应电机数学模型 2.1. 定子基准下ABC/qd数学模型 2.2. 任意速旋转坐标系下xy/xy数学模型 2.3. 空间矢量数学模型 3. 双笼转子三相感应电动机仿真模型 3.1 基于任意速xy/xy坐标系数学模型(1)~(5)的仿真模型 3.2. 基于任意速xy/xy坐标系中瞬态等效电…

MATLAB图像处理分析基础(一)

一、引言 MATLAB软件得到许多数字图像处理学生、老师和科研工作者的喜爱&#xff0c;成为数字图像处理领域不可或缺的工具之一&#xff0c;其与其他软件相比有以下诸多显著优点。首先&#xff0c;MATLAB 拥有强大的内置函数库&#xff0c;涵盖了图像读取、显示、处理及分析的全…

OpenCV 遍历Mat,像素操作,使用TrackBar 调整图像的亮度和对比度 C++实现

文章目录 1.使用C遍历Mat,完成颜色反转1.1 常规遍历方式1.2 迭代器遍历方式1.3指针访问方式遍历&#xff08;最快&#xff09;1.4不同遍历方式的时间对比 2.图像像素操作&#xff0c;提高图像的亮度3.TrackBar 进度条操作3.1使用TrackBar 调整图像的亮度3.2使用TrackBar 调整图…

【JavaEE进阶】——Spring事务和事务传播机制

目录 &#x1f6a9;事务 &#x1f388;为什么需要事务? &#x1f388;事务的操作 &#x1f6a9;Spring 中事务的实现 &#x1f388;数据准备 &#x1f388;Spring 编程式事务(了解) &#x1f388;Spring 声明式事务 Transactional &#x1f36d;Transactional 详解 &…

2013年全国大学生数学建模竞赛B题碎纸片复原(含word论文和源代码资源)

文章目录 一、部分题目二、部分论文三、部分源代码四、完整word版论文和源代码&#xff08;两种获取方式&#xff09; 一、部分题目 2013高教社杯全国大学生数学建模竞赛题目 B题 碎纸片的拼接复原 破碎文件的拼接在司法物证复原、历史文献修复以及军事情报获取等领域都有着重…

基于术语词典干预的机器翻译挑战赛笔记Task2 #Datawhale AI 夏令营

上回&#xff1a; 基于术语词典干预的机器翻译挑战赛笔记Task1 跑通baseline Datawhale AI 夏令营-CSDN博客文章浏览阅读718次&#xff0c;点赞11次&#xff0c;收藏8次。基于术语词典干预的机器翻译挑战赛笔记Task1 跑通baselinehttps://blog.csdn.net/qq_23311271/article/d…