el-tabs添加按钮增加点击禁止样式

news2025/4/9 1:54:39

前置文章

一、vue使用element-ui自定义样式思路分享【实操】
二、vue3&ts&el-tabs多个tab表单校验

现状确认

  • 点击添加按钮,没有点击样式,用户感知不明显
  • 没有限制最大的tab添加数量,可以无限添加
    请添加图片描述

调整目标&代码编写

调整目标

  • 点击添加按钮,按钮背景变成蓝色,加号图标变成白色
  • 限制最大的tab添加数量为10,超过10添加按钮设置为灰色不可点击

代码编写

点击添加按钮,按钮背景变成蓝色

在vue使用element-ui自定义样式思路分享【实操】提到了如何给el-tabs按钮自定义样式,文本在按钮已经设置了自定义样式的基础上进行,首先实现点击按钮时,背景颜色变成蓝色,考虑使用伪类选择器active来实现。
蓝色保持与element框架默认提供的一致,可以通过Snipaste来拾取:F1开启截屏,鼠标移动到蓝色区域,Shift切换颜色数据类型,按C完整复制。
在这里插入图片描述
代码调整如下

/*添加按钮点击显示蓝色*/
.asset-tab :deep(.el-tabs__new-tab):active {
  background: #409eff;
}

效果
请添加图片描述

点击添加按钮,加号图标变成白色

观察svg的样式选择器,观察到通过fill设置颜色不生效,修改color颜色才生效,例如下图中设置为红色
在这里插入图片描述
添加代码

/*设置svg点击颜色显示白色*/
.asset-tab :deep(.el-tabs__new-tab):active .is-icon-plus svg {
  color: white;
}

效果
请添加图片描述

js动态禁止按钮点击&设置按钮禁止样式

添加禁止样式(主要关注前面三行)

/*禁止样式*/
.asset-tab :deep(.el-tabs__new-tab.disabled) {
  pointer-events: none;
  opacity: 0.8;
  background: lightgray;
  height: 30px;
  width: 30px;
  border-radius: 15px;
  font-size: 16px;
}

操作document动态添加或去除禁止样式,注意document.querySelector()选择器不需要加:deep(),并将修改逻辑抽取成方法setAddBtnStatus,在增减tab逻辑后调用即可

const setAddBtnStatus = function () {
  const newTab = document.querySelector('.asset-tab .el-tabs__new-tab')
  console.log('newTab', newTab)
  const index = tabs.value.length
  if (index >= 10) {
    newTab?.classList.add('disabled')
  } else {
    newTab?.classList.remove('disabled')
  }
}

最终效果&完整代码

请添加图片描述
完整代码:

<!--AssetCreate.vue-->
<template>
  <div style="margin-bottom: 10px">
    <h3>数据源选择:</h3>
    <el-switch v-model="isUseLocalFlag" active-text="使用本地服务数据" inactive-text="使用mock数据"/>
    <el-button @click="setTabData" style="margin-left: 10px;">给tab赋值</el-button>
    <el-button @click="clearTabData" >清空tab赋值</el-button>
  </div>
  <div class="asset-tab">
    <el-tabs v-model="activeTab" type="card" editable class="demo-tabs" @edit="handleTabsEdit">
      <el-tab-pane v-for="tab in tabs" :key="tab.name" :label="tab.label" :name="tab.name">
        <AssetItem ref="assetItemRefs" :insertForm="tab.insertForm"/>
      </el-tab-pane>
    </el-tabs>
  </div>
  <div class="bottom-btn">
    <el-button @click="submitAsset" type="primary">提交</el-button>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import axios from 'axios'
import type { TabPaneName } from 'element-plus'
import { removeRedundantFields } from '@/utils/methodUtil'
import AssetItem from '@/components/asset/AssetItem.vue'
import type { AssetFormData } from '@/types'
import { ElMessage } from 'element-plus'
// 当前激活的tab
const activeTab = ref('表单 1')
// tabs初始数据
const tabs = ref([
  { label: '表单 1', name: '表单 1', insertForm: {} }
])
const isUseLocalFlag = ref(true)
const clearTabData = function () {
  tabs.value = [{ label: '表单 1', name: '表单 1', insertForm: {} }]
  activeTab.value = '表单 1'
  setAddBtnStatus()
}
const setTabData = async function () {
  const bizId = '0777c40218114c35a29b0d4d84355668'
  if (isUseLocalFlag.value) {
    await axios.post(`/asset/assetInfo/${bizId}/byBizId`).then(result => {
      if (result.status === 200) {
        tabs.value = []
        const assetInfoList = result?.data?.data?.assetInfoList
        const removeResult = removeRedundantFields(assetInfoList, ['extAttribute11', 'extAttribute12',
          'extAttribute13', 'extAttribute14', 'extAttribute15', 'extAttribute16', 'extAttribute17', 'extAttribute18',
          'extAttribute19', 'extAttribute20'])
        removeResult.forEach((item, index) => {
          const newTabName = `表单 ${index + 1}`
          tabs.value.push({
            label: newTabName,
            name: newTabName,
            insertForm: item
          })
          setAddBtnStatus()
          activeTab.value = newTabName
        })
      }
    })
  } else {
    // 请求mock数据
    await axios.post('/mock/asset/assetInfo', { bizId }).then(result => {
      const assetInfoList: Array<AssetFormData> = result?.data?.data?.assetInfoList
      tabs.value = []
      assetInfoList.forEach((asset, idx) => {
        const newTabName = `表单 ${idx + 1}`
        tabs.value.push({
          label: newTabName,
          name: newTabName,
          insertForm: asset
        })
        setAddBtnStatus()
        activeTab.value = newTabName
      })
    })
  }
}
const assetItemRefs = ref<InstanceType<typeof AssetItem>[]>([])
const handleTabsEdit = (
  targetName: TabPaneName | undefined,
  action: 'remove' | 'add'
) => {
  if (action === 'add') {
    let index = tabs.value.length
    if (index >= 10) return
    const newTabName = `表单 ${++index}`
    tabs.value.push({
      label: newTabName,
      name: newTabName,
      insertForm: {}
    })
    activeTab.value = newTabName
  } else if (action === 'remove') {
    const activeName = activeTab.value
    if (tabs.value.length === 1) return
    tabs.value = tabs.value.filter((tab) => tab.name !== targetName)
    tabs.value.forEach((item, index) => {
      item.name = `表单 ${++index}`
      item.label = item.name
    })
    const currentExist = tabs.value.some((item, index) => {
      if (item.name === activeName) {
        return index
      }
      return false
    })
    if (!currentExist) activeTab.value = tabs.value[tabs.value.length - 1].name
  }
  setAddBtnStatus()
}
const setAddBtnStatus = function () {
  const newTab = document.querySelector('.asset-tab .el-tabs__new-tab')
  const index = tabs.value.length
  if (index >= 10) {
    newTab?.classList.add('disabled')
  } else {
    newTab?.classList.remove('disabled')
  }
}
const verifyPass = ref(true)
const submitAsset = async function () {
  for (const index in assetItemRefs.value) {
    const verifyResult = await assetItemRefs.value[index].submitForm()
    // 定位到第一个校验失败的tab
    if (!verifyResult) {
      verifyPass.value = false
      activeTab.value = `表单 ${Number(index) + 1}`
      break
    } else {
      verifyPass.value = true
    }
  }
  if (verifyPass.value) ElMessage({ message: '表单校验通过', type: 'success' })
}
</script>

<style scoped>
/*禁止样式*/
.asset-tab :deep(.el-tabs__new-tab.disabled) {
  pointer-events: none;
  opacity: 0.8;
  background: lightgray;
  height: 30px;
  width: 30px;
  border-radius: 15px;
  font-size: 16px;
}
.asset-tab :deep(.el-tabs__new-tab) {
  height: 30px;
  width: 30px;
  border-radius: 15px;
  font-size: 16px;
}

/*添加按钮点击显示蓝色*/
.asset-tab :deep(.el-tabs__new-tab):active {
  background: #409eff;
}
/*设置svg点击颜色显示白色*/
.asset-tab :deep(.el-tabs__new-tab):active .is-icon-plus svg {
  color: white;
}
.bottom-btn {
  text-align: center;
  margin-bottom: 10px;
}
</style>

代码仓:hello_vue3

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

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

相关文章

LINUX 5 vim cat zip unzip

dd u撤销 ctrlr取消撤销 q!刚才的操作不做保存 刚才是编辑模式 现在是可视化模式 多行注释

PDFBox渲染生成pdf文档

使用PDFBox可以渲染生成pdf文档&#xff0c;并且自定义程度高&#xff0c;只是比较麻烦&#xff0c;pdf的内容位置都需要手动设置x&#xff08;横向&#xff09;和y&#xff08;纵向&#xff09;绝对位置&#xff0c;但是每个企业的单据都是不一样的&#xff0c;一般来说都会设…

Batch Normalization:深度学习训练的加速引擎

引言 在深度学习的发展历程中&#xff0c;训练深度神经网络一直是一项极具挑战性的任务。随着网络层数的增加&#xff0c;梯度消失、梯度爆炸以及训练过程中的内部协变量偏移&#xff08;Internal Covariate Shift&#xff09;问题愈发严重&#xff0c;极大地影响了模型的收敛…

低空经济基础设施建设方向与展望

随着科技的不断进步&#xff0c;低空经济正逐渐成为推动国家经济发展的新引擎。低空经济&#xff0c;指的是在低空范围内进行的各种经济活动&#xff0c;包括但不限于无人机物流、空中交通管理、低空旅游、农业监测等。本文将探讨低空经济基础设施建设的方向与未来展望。 1. 低…

如何保证RabbitMQ消息的可靠传输?

在这个图中&#xff0c;消息可能丢失的场景是1&#xff0c;2&#xff0c;3 1.在生产者将消息发送给RabbitMQ的时候&#xff0c;消息到底有没有正确的到达服务器呢&#xff0c;RabbitMQ提供了两种解决方案&#xff1a; a. 通过事务机制实现&#xff08;比较消耗性能&#xff0…

Sentinel核心源码分析(上)

文章目录 前言一、客户端与Spring Boot整合二、SphU.entry2.1、构建责任链2.2、调用责任链2.2.1、NodeSelectorSlot2.2.2、ClusterBuilderSlot2.2.3、LogSlot2.2.4、StatisticSlot2.2.5、AuthoritySlot2.2.6、SystemSlot2.2.7、FlowSlot2.2.7.1、selectNodeByRequesterAndStrat…

Systemd安全加密备份系统与智能通知

实训背景 你是一家金融科技公司的系统架构师&#xff0c;需为敏感数据设计一套安全备份系统&#xff0c;满足以下需求&#xff1a; 加密存储&#xff1a;自动解密插入的LUKS加密USB设备&#xff0c;挂载到安全目录。备份验证&#xff1a;备份完成后校验文件完整性&#xff0c…

6.0 使用Qt+ OpenCV+Python加载图片

本例作为python图像处理的入门课程1,使用Qt+ OpenCV+Python加载图片。 主要有如下几个地方需要注意: 1. OpenCV 默认使用 BGR 格式,而 Qt 使用 RGB。显示前需要转换:cv2.cvtColor(img, cv2.COLOR_BGR2RGB),一般使用某个QLabel控件进行显示。 pic = cv2.cvtColor(pic, cv2.C…

【Mac 从 0 到 1 保姆级配置教程 11】- Mac 基础配置 Finder、触控板、常用快捷键等

文章目录 前言配置 Finder1. 把我们的家目录请出来2. 显示文件扩展名3. 展示隐藏文件4. 显示路径栏和状态栏5. 固定文件夹到工具栏 基础快捷键1. Finder 导航快捷键2. 文件操作快捷键3. 视图和显示快捷键4. 搜索和选择快捷键5. 实用技巧6. 关于文件创建 配置触控板1. 右键设置2…

C++Primer - 动态内存管理

欢迎阅读我的 【CPrimer】专栏 专栏简介&#xff1a;本专栏主要面向C初学者&#xff0c;解释C的一些基本概念和基础语言特性&#xff0c;涉及C标准库的用法&#xff0c;面向对象特性&#xff0c;泛型特性高级用法。通过使用标准库中定义的抽象设施&#xff0c;使你更加适应高级…

DeepSeek本地部署(Ollama)

1. Ollama 安装 Ollama 官网地址&#xff1a; https://ollama.com/安装包网盘地址: https://pan.baidu.com 2. Deepseek 部署 根据自己电脑配置和应用需求选择不同模型&#xff0c;配置不足会导致运行时候卡顿。 版本安装指令模型大小硬盘&#xff08;存储&#xff09;显卡…

第二期:深入理解 Spring Web MVC [特殊字符](核心注解 + 进阶开发)

前言&#xff1a; 欢迎来到 Spring Web MVC 深入学习 的第二期&#xff01;在第一期中&#xff0c;我们介绍了 Spring Web MVC 的基础知识&#xff0c;学习了如何 搭建开发环境、配置 Spring MVC、编写第一个应用&#xff0c;并初步了解了 控制器、视图解析、请求处理流程 等核…

论伺服电机在轨道式巡检机器人中的优势及应用实践​

一、引言​ 1.1 研究背景与意义​ 在现代工业生产、电力系统、轨道交通等诸多领域&#xff0c;保障设施设备的安全稳定运行至关重要。轨道式巡检机器人作为一种高效、智能的巡检工具&#xff0c;正逐渐在这些领域崭露头角。它能够沿着预设轨道&#xff0c;对目标区域进行全方位…

(51单片机)独立按键控制流水灯LED流向(独立按键教程)(LED使用教程)

源代码 如上图将7个文放在Keli5 中即可&#xff0c;然后烧录在单片机中就行了 烧录软件用的是STC-ISP&#xff0c;不知道怎么安装的可以去看江科大的视频&#xff1a; 【51单片机入门教程-2020版 程序全程纯手打 从零开始入门】https://www.bilibili.com/video/BV1Mb411e7re?…

react-router children路由报错

项目场景&#xff1a; 写个路由页面&#xff0c;引发的问题 问题描述 报错&#xff1a; An absolute child route path must start with the combined path of all its parent routes. 代码&#xff1a; import { createBrowserRouter } from "react-router-dom";…

Socket编程TCP

Socket编程TCP 1、V1——EchoServer单进程版2、V2——EchoServer多进程版3、V3——EchoServer多线程版4、V4——EchoServer线程池版5、V5——多线程远程命令执行6、验证TCP——Windows作为client访问Linux7、connect的断线重连 1、V1——EchoServer单进程版 在TcpServer.hpp中实…

文件映射mmap与管道文件

在用户态申请内存&#xff0c;内存内容和磁盘内容建立一一映射 读写内存等价于读写磁盘 支持随机访问 简单来说&#xff0c;把磁盘里的数据与内存的用户态建立一一映射关系&#xff0c;让读写内存等价于读写磁盘&#xff0c;支持随机访问。 管道文件&#xff1a;进程间通信机…

代码随想录回溯算法03

93.复原IP地址 本期本来是很有难度的&#xff0c;不过 大家做完 分割回文串 之后&#xff0c;本题就容易很多了 题目链接/文章讲解&#xff1a;代码随想录 视频讲解&#xff1a;回溯算法如何分割字符串并判断是合法IP&#xff1f;| LeetCode&#xff1a;93.复原IP地址_哔哩哔…

批量改CAD图层颜色——CAD c#二次开发

一个文件夹下大量图纸&#xff08;几百甚至几千个文件&#xff09;需要改图层颜色时&#xff0c;可采用插件实现&#xff0c;效果如下&#xff1a; 转换前&#xff1a; 转换后&#xff1a; 使用方式如下&#xff1a;netload加载此dll插件&#xff0c;输入xx运行。 附部分代码如…

【内网安全】DHCP 饿死攻击和防护

正常情况&#xff1a;PC2可以正常获取到DHCP SERVER分别的IP地址查看DHCP SERCER 的ip pool地址池可以看到分配了一个地址、Total 253个 Used 1个 使用kali工具进行模拟攻击 进行DHCP DISCOVER攻击 此时查看DHCP SERVER d大量的抓包&#xff1a;大量的DHCP Discover包 此时模…