Vue3徽标数(Badge)

news2025/1/31 3:02:10

APIs

参数说明类型默认值必传
color自定义小圆点的颜色string‘’false
count展示的数字,大于 overflowCount 时显示为 overflowCount+,为 0 时隐藏number | slot0false
overflowCount展示封顶的数字值number99false
showZero当数值为 0 时,是否展示 Badgebooleanfalsefalse
dot不展示数字,只有一个小红点booleanfalsefalse
status设置 Badge 为状态点‘success’ | 'processing | ‘default’ | ‘error’ | ‘warn’undefinedfalse
text在设置了 status 的前提下有效,设置状态点的文本string | slot‘’false
numberStyle设置状态点的样式CSSProperties{}false
title设置鼠标放在状态点上时显示的文字string‘’false
ripple是否开启涟漪动画效果booleantruefalse

效果如下图:在线预览

在这里插入图片描述
在这里插入图片描述

创建徽标数组件Badge.vue

<script setup lang="ts">
import type { CSSProperties } from 'vue'
import { ref, computed, onMounted } from 'vue'
enum Status {
  success = 'success',
  process = 'processing',
  default = 'default',
  error = 'error',
  warn = 'warn'
}
interface Props {
  color?: string // 自定义小圆点的颜色
  count?: number // 展示的数字,大于 overflowCount 时显示为 overflowCount+,为 0 时隐藏;number | slot
  overflowCount?: number // 展示封顶的数字值
  showZero?: boolean // 当数值为 0 时,是否展示 Badge
  dot?: boolean // 不展示数字,只有一个小红点
  status?: Status // 设置 Badge 为状态点
  text?: string // 在设置了 status 的前提下有效,设置状态点的文本 string | slot
  numberStyle?: CSSProperties // 设置状态点的样式
  title?: string // 设置鼠标放在状态点上时显示的文字
  ripple?: boolean // 是否开启涟漪动画效果
}
const props = withDefaults(defineProps<Props>(), {
  color: '',
  count: 0,
  overflowCount: 99,
  showZero: false,
  dot: false,
  status: undefined,
  text: '',
  numberStyle: () => ({}),
  title: '',
  ripple: true
})
const presetColor = ['pink', 'red', 'yellow', 'orange', 'cyan', 'green', 'blue', 'purple', 'geekblue', 'magenta', 'volcano', 'gold', 'lime']
const customStyle = computed(() => {
  if (props.color && !presetColor.includes(props.color)) {
    return {
      color: props.color,
      backgroundColor: props.color
    } 
  }
})
const contentRef = ref()
const showContent = ref(1)
const countRef = ref()
const showCount = ref(1)
onMounted(() => {
  if (!props.status && !props.color) {
    showContent.value = contentRef.value.offsetHeight
    showCount.value = countRef.value.offsetHeight
  }
})
</script>
<template>
  <div class="m-badge" :class="{'badge-status': status}">
    <template v-if="status||color">
      <span class="u-status-dot" :class="[`status-${status||color}`, {'dot-ripple': ripple}]" :style="customStyle"></span>
      <span class="u-status-text">
        <slot>{{ text }}</slot>
      </span>
    </template>
    <template v-else>
      <span ref="contentRef" v-if="showContent">
        <slot></slot>
      </span>
      <span
        ref="countRef"
        v-if="showCount"
        class="m-count"
        :class="{'only-number': !showContent}">
        <slot name="count"></slot>
      </span>
      <Transition name="zoom" v-else>
        <div
          v-show="showZero || count !== 0 || dot"
          class="m-badge-count"
          :class="{'small-num': count < 10, 'only-number': !showContent, 'only-dot': count === 0 && !showZero}"
          :style="numberStyle"
          :title="title || String(count)">
          <span v-if="!dot" class="m-number" style="transition: none 0s ease 0s;">
            <span class="u-number">{{ count > overflowCount ? overflowCount + '+' : count }}</span>
          </span>
        </div>
      </Transition>
    </template>
  </div>
</template>
<style lang="less" scoped>
.zoom-enter-active {
  animation: zoomBadgeIn .3s cubic-bezier(0.12, 0.4, 0.29, 1.46);
  animation-fill-mode: both;
}
.zoom-leave-active {
  animation: zoomBadgeOut .3s cubic-bezier(0.12, 0.4, 0.29, 1.46);
  animation-fill-mode: both;
}
@keyframes zoomBadgeIn {
  0% {
    transform: scale(0) translate(50%, -50%);
    opacity: 0;
  }
  100% {
    transform: scale(1) translate(50%, -50%);
  }
}
@keyframes zoomBadgeOut {
  0% {
    transform: scale(1) translate(50%, -50%);
  }
  100% {
    transform: scale(0) translate(50%, -50%);
    opacity: 0;
  }
}
.m-badge {
  color: rgba(0, 0, 0, .88);
  font-size: 14px;
  line-height: 1;
  position: relative;
  display: inline-block;
  width: fit-content;
  .u-status-dot {
    position: relative;
    top: -1px;
    display: inline-block;
    width: 6px;
    height: 6px;
    vertical-align: middle;
    border-radius: 50%;
  }
  .dot-ripple {
    &::after {
      box-sizing: border-box;
      position: absolute;
      top: 0;
      inset-inline-start: 0;
      width: 100%;
      height: 100%;
      border-width: 1px;
      border-style: solid;
      border-color: inherit;
      border-radius: 50%;
      animation-name: dotRipple;
      animation-duration: 1.2s;
      animation-iteration-count: infinite;
      animation-timing-function: ease-in-out;
      content: "";
    }
    @keyframes dotRipple {
      0% {
        transform: scale(.8);
        opacity: .5;
      }
      100% {
        transform: scale(2.4);
        opacity: 0;
      }
    }
  }
  .status-success {
    color: #52c41a;
    background-color: #52c41a;
  }
  .status-error {
    color: #ff4d4f;
    background-color: #ff4d4f;
  }
  .status-default {
    color: rgba(0, 0, 0, .25);
    background-color: rgba(0, 0, 0, .25);
  }
  .status-processing {
    color: #1677ff;
    background-color: #1677ff;
  }
  .status-warn {
    color: #faad14;
    background-color: #faad14;
  }
  .status-pink {
    color: #eb2f96;
    background-color: #eb2f96;;
  }
  .status-red {
    color: #f5222d;
    background-color: #f5222d;
  }
  .status-yellow {
    color: #fadb14;
    background-color: #fadb14;
  }
  .status-orange {
    color: #fa8c16;
    background-color: #fa8c16;
  }
  .status-cyan {
    color: #13c2c2;
    background-color: #13c2c2;
  }
  .status-green {
    color: #52c41a;
    background-color: #52c41a;
  }
  .status-blue {
    color: #1677ff;
    background-color: #1677ff;
  }
  .status-purple {
    color: #722ed1;
    background-color: #722ed1;
  }
  .status-geekblue {
    color: #2f54eb;
    background-color: #2f54eb;
  }
  .status-magenta {
    color: #eb2f96;
    background-color: #eb2f96;
  }
  .status-volcano {
    color: #fa541c;
    background-color: #fa541c;
  }
  .status-gold {
    color: #faad14;
    background-color: #faad14;
  }
  .status-lime {
    color: #a0d911;
    background-color: #a0d911;
  }
  .u-status-text {
    margin-inline-start: 8px;
    color: rgba(0, 0, 0, .88);
    font-size: 14px;
  }
  .m-count {
    position: absolute;
    top: 0;
    inset-inline-end: 0;
    transform: translate(50%, -50%);
    transform-origin: 100% 0%;
  }
  .m-badge-count {
    .m-count();
    overflow: hidden;
    padding: 0 8px;
    z-index: auto;
    min-width: 20px;
    height: 20px;
    color: #ffffff;
    font-weight: normal;
    font-size: 12px;
    line-height: 20px;
    white-space: nowrap;
    text-align: center;
    background: #ff4d4f;
    border-radius: 10px;
    box-shadow: 0 0 0 1px #ffffff;
    transition: background .2s;
    .m-number {
      position: relative;
      display: inline-block;
      height: 20px;
      transition: all .3s cubic-bezier(0.12, 0.4, 0.29, 1.46);
      -webkit-transform-style: preserve-3d; // 设置元素的子元素是位于 3D 空间中还是平面中 flat | preserve-3d
      -webkit-backface-visibility: hidden; // 当元素背面朝向观察者时是否可见 hidden | visible
      .u-number {
        display: inline-block;
        height: 20px;
        margin: 0;
        -webkit-transform-style: preserve-3d;
        -webkit-backface-visibility: hidden;
      }
    }
  }
  .small-num {
    padding: 0;
  }
  .only-number {
    position: relative;
    top: auto;
    display: block;
    transform-origin: 50% 50%;
    transform: none;
  }
  .only-dot {
    z-index: auto;
    width: 6px;
    min-width: 6px;
    height: 6px;
    background: #ff4d4f;
    border-radius: 100%;
    box-shadow: 0 0 0 1px #ffffff;
    padding: 0;
    transition: background .3s;
  }
}
.badge-status {
  line-height: inherit;
  vertical-align: baseline;
}
</style>

在要使用的页面引入

其中引入使用了 Vue3间距(Space)

<script setup lang="ts">
import Badge from './Badge.vue'
import { ref } from 'vue'
const show = ref(true)
const colors = [
  'pink',
  'red',
  'yellow',
  'orange',
  'cyan',
  'green',
  'blue',
  'purple',
  'geekblue',
  'magenta',
  'volcano',
  'gold',
  'lime',
]
</script>
<template>
  <div>
    <h1>Badge 徽标数</h1>
    <h2 class="mt30 mb10">基本使用</h2>
    <Space :size="20">
      <Badge :count="5">
        <span class="u-cube"></span>
      </Badge>
      <Badge :count="0" show-zero>
        <span class="u-cube"></span>
      </Badge>
      <Badge>
        <template #count>
          <svg focusable="false" class="u-svg" data-icon="clock-circle" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"></path><path d="M686.7 638.6L544.1 535.5V288c0-4.4-3.6-8-8-8H488c-4.4 0-8 3.6-8 8v275.4c0 2.6 1.2 5 3.3 6.5l165.4 120.6c3.6 2.6 8.6 1.8 11.2-1.7l28.6-39c2.6-3.7 1.8-8.7-1.8-11.2z"></path></svg>
        </template>
        <span class="u-cube"></span>
      </Badge>
    </Space>
    <h2 class="mt30 mb10">独立使用</h2>
    <Space :size="20">
      <Badge :count="25" />
      <Badge
        :count="4"
        :number-style="{
          backgroundColor: '#fff',
          color: '#999',
          boxShadow: '0 0 0 1px #d9d9d9 inset',
        }"
      />
      <Badge :count="109" :number-style="{ backgroundColor: '#52c41a' }" />
    </Space>
    <h2 class="mt30 mb10">封顶数字</h2>
    <Space :size="30">
      <Badge :count="99">
        <span class="u-cube"></span>
      </Badge>
      <Badge :count="100">
        <span class="u-cube"></span>
      </Badge>
      <Badge :count="99" :overflow-count="10">
        <span class="u-cube"></span>
      </Badge>
      <Badge :count="1000" :overflow-count="999">
        <span class="u-cube"></span>
      </Badge>
    </Space>
    <h2 class="mt30 mb10">小红点</h2>
    <Badge dot>
      <a href="#">Link something</a>
    </Badge>
    <h2 class="mt30 mb10">状态点</h2>
    <Space :size="10">
      <Badge status="success" />
      <Badge status="error" />
      <Badge status="default" />
      <Badge status="processing" />
      <Badge status="warn" />
    </Space>
    <br/>
    <Space style="margin-top: 10px;" direction="vertical" :size="10">
      <Badge status="success" text="Success" />
      <Badge status="error" text="Error" />
      <Badge status="default" text="Default" />
      <Badge status="processing" text="Processing" />
      <Badge status="warn" text="warning" />
    </Space>
    <h2 class="mt30 mb10">动态</h2>
    <Space :size="20" align="center">
      <Badge :dot="show">
        <span class="u-cube"></span>
      </Badge>
      <Switch v-model:checked="show" />
    </Space>
    <h2 class="mt30 mb10">自定义悬浮状态点的显示文字</h2>
    <Badge :count="5" title="Custom hover text">
      <span class="u-cube"></span>
    </Badge>
    <h2 class="mt30 mb10">多彩徽标</h2>
    <h4 class="mb10">Presets</h4>
    <Space wrap :size="20">
      <Badge
        v-for="color in colors" :key="color"
        :color="color"
        :text="color" />
    </Space>
    <h4 class="mt10 mb10">Custom</h4>
    <Space wrap :size="20">
      <Badge color="#f50" text="#f50" />
      <Badge color="#2db7f5" text="#2db7f5" />
      <Badge color="#87d068" text="#87d068" />
      <Badge color="#108ee9" text="#108ee9" />
    </Space>
  </div>
</template>
<style lang="less" scoped>
.u-cube {
  display: inline-block;
  border-radius: 8px;
  width: 40px;
  height: 40px;
  background: rgba(0, 0, 0, 0.25);
}
.u-svg {
  fill: #f5222d;
}
</style>

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

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

相关文章

干货 | 清华大学叶晓俊:GB/T 35274-2023《信息安全技术 大数据服务安全能力要求》解读...

全国信息技术安全标准化委员会&#xff08;简称信安标委或TC260&#xff09;在2021年通过了编制组申请的GB/T 35274-2017《信息安全技术 大数据服务安全能力要求》修订项目&#xff0c; 新版标准报批稿在2022年年底提交给国标委进行最后的形式化审查&#xff0c;从国标委标准进…

TCP的三次握手和四次挥手······详解

1、三次握手 三次握手是建立连接的过程 如图大致为三次握手的流程图&#xff1a; 当客户端对服务端发起连接时&#xff0c;会先发一个包连接请求数据&#xff0c;去询问能否建立连接&#xff0c;该数据包称为 “SYN”包 然后&#xff0c;如果对方同意连接&#xff0c;那么…

思科单臂路由、lacp链路聚合、NAT实验

实验拓扑图&#xff1a; 实验目的&#xff1a; 如图所示配置相应IP地址和VLAN&#xff0c;并通过在AR1上配置单臂路由&#xff0c;实现VLAN10和VLAN20的主机能够在VLAN间通信&#xff1b;在SW1和SW2的三条链路实施链路聚合&#xff0c;使用静态LACP模式&#xff0c;使一条链…

【linux--->网络层协议】

文章目录 [TOC](文章目录) 一、概念1.网络层概念2.IP地址概念 二、IP协议报文结构1.首部长度2.总长度(total length)3.协议4.版本号(version)5.服务类型(Type Of Service)6.生存时间间(Time To Live, TTL) 三、网段划分1.5类IP划分法.2.CIDR(Classless Interdomain Routing)划分…

STM32刷Micropython固件参考指南

STM32刷Micropython固件指南 其实刷固件和普通的程序下载烧录无多大的差异&#xff0c;主要是其他因数的影响导致刷固件或刷完固件无法运行的情况和相关问题。 &#x1f4d1;刷固件教程 固件下载。目前所支持的stm32型号有这些&#xff1a; stm32f0, stm32f4, stm32f7, stm32g…

《零基础入门学习Python》第076讲:GUI的终极选择:Tkinter13

这节课我们来学习 Tkinter 的布局管理器&#xff0c;那什么是布局管理器呢&#xff1f;说白了&#xff0c;就是用于管理你的组件如何排列。Tkinter 提供了 3 大布局管理器&#xff1a;pack、grid 和 place。 pack 是按添加顺序排列组件grid 是按行/列形式排列组件place 则允许…

qt富文本编辑基本知识(QTextBlockFormat、QTextListFormat)

可以参考该文章&#xff1a;QTextBlockFormat、QTextListFormat - 程序员大本营 核心知识如下&#xff1a; 如果想开发一个富文本编辑器&#xff08;html&#xff0c;markdown等常见格式&#xff09;&#xff0c;Qt已经为用户完成了几乎所有与编辑有关的具体工作&#xff0c;…

工厂模式(FactoryPattern)

工厂模式 工厂模式&#xff08;Factory Pattern&#xff09;是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式&#xff0c;它提供了一种创建对象的最佳方式。 工厂模式提供了一种将对象的实例化过程封装在工厂类中的方式。通过使用工厂模式&#xff0c;可以…

Java:JDK8之后新的时间(推荐使用) ZoneId、 Instant、DataTimeFormatter、Period的相关API

ZoneId //目标:了解时区和带时区的时间。 //1、ZoneId的常见方法: // public static ZoneId systemDefault():获取系统默认的时区 zoneId zoneId ZoneId.systemDefault(); system.out.println(zoneId.getId()); system.out.println(zoneId);// public static Set<String>…

SOME/IP学习笔记1

SOA概念 在SOA中,每个服务就好像我们每一个人在社会中扮演的角色,在对别人提供着服务的同时,同时也享受着别人提供出来的服务,人与人之间,既是彼此独立的,又是需要互相通讯的。服务提供者将功能具象为一组接口,这样使用者就能知道如何调用服务,完成某件事情,得到某个…

亚马逊引流方式有哪些

亚马逊引流是指将潜在的买家从其他渠道引导到亚马逊平台上购买产品。以下是一些常见的亚马逊引流方式&#xff1a; 1、社交媒体营销&#xff1a;通过社交媒体平台如Facebook、Instagram、Twitter等发布有关你产品的信息、广告和优惠活动。吸引潜在客户点击链接&#xff0c;直接…

第七章 递归组件(树组件为例)

递归组件 封装树组件 App.vue <template><div class"App">App<MyTree :dataList"dataList"></MyTree></div> </template><script setup lang"ts"> import { ref, reactive } from "vue"…

Java当中更改源码/修复CVE-2016-1000027漏洞分析

Java当中更改源码/修复CVE-2016-1000027漏洞分析 文章目录 Java当中更改源码/修复CVE-2016-1000027漏洞分析1.基础知识&#xff1a;2.漏洞成因&#xff1a;3.解决方法:4.修改源码: 1.基础知识&#xff1a; ​ 要想分析首先要了解什么是Spring HTTP Invoker&#xff0c;HttpInv…

【考古】Java8 集合工具类Arrays

文章目录 一、概述二、常用方法三、简单使用3.1 Arrays的sort排序3.2 Arrays的binarySearch查找3.3 Arrays的fill填充3.4 Arrays的copyOf复制数组3.5 Arrays的copyOfRange复制部分Arrays的asList数组转链表 四、总结 一、概述 在 Java 的util包中提供了一个Arrays工具类用来操作…

深入了解Redis-实战篇-分布式锁

深入了解Redis-实战篇-分布式锁 一、故事背景二、知识点主要构成1、分布式锁基本原理2、不同实现方式对比3、基于redis的分布式锁3.1、获取锁3.2、释放锁 4、Redisson的可重入锁原理5、Redisson的锁重试和WatchDog机制 三、总结提升 一、故事背景 最近在系统的回顾redis相关的…

系列3-常见的高可用MySQL解决方案

高可用主要解决两个问题&#xff0c;如何实现数据共享和同步数据、如何处理failover&#xff0c;数据共享的解决方案一般是SAN&#xff0c;数据同步通过rsync和drbd技术来实现。 1、主从复制解决方案 这是MySQL自身的高可用解决方案&#xff0c;数据同步方法采用的是MySQL rep…

Eclipse进行debug

目录 基本步骤三种执行方式 -- 键盘快捷键variables面板移除debug过的项目通过eclipse调用具有软件界面的项目进行debug各个variable颜色具有的意义 基本步骤 点击eclipse右上角debug按钮 调出debug面板 点击小蜘蛛图标&#xff08;不是点绿色三角的Run&#xff09; 此时会进…

FPGA实现NIC 100G UDP协议栈网卡,UltraScale+ 100G Ethernet Subsystem驱动,提供工程源码和技术支持

目录 1、前言2、我这里已有的UDP方案3、本25G/100G网卡基本性能简介4、详细设计方案接口概述PCIe HIPDMA IFAXI总线接口时钟同步处理TXQ和RXQ队列TXCQ和RXCQ队列完成EQ MAC PHYUltraScale 100G Ethernet Subsystem流水线队列管理发送调度程序端口和接口数据路径以及发送和接收…

怎么把图片变成表格?几个步骤轻松转换

如果您需要将一张图片中的数据转换成表格&#xff0c;这里有几个简单的步骤&#xff0c;可以帮助您完成这个转换过程。以下是需要注意的事项。 首先&#xff0c;我们先了解OCR&#xff08;Optical Character Recognition&#xff0c;光学字符识别&#xff09;技术。然后合理运用…

前端vue uni-app自定义精美海报生成组件

在当前技术飞速发展的时代&#xff0c;软件开发的复杂度也在不断提高。传统的开发方式往往将一个系统做成整块应用&#xff0c;一个小的改动或者一个小功能的增加都可能引起整体逻辑的修改&#xff0c;从而造成牵一发而动全身的情况。为了解决这个问题&#xff0c;组件化开发逐…