msg-cards-xh
msg-cards · 消息卡片推送组件库
基于 Vue 3 + TypeScript + Vite 的科技风消息卡片组件库,提供异常告警、机房参数展示、数据仓、机房监控全景图、告警数值、地理位置标签等 8 种卡片样式,适用于数据大屏 / 监控看板 / 指挥中心消息推送场景。
所有组件均支持 手动关闭(× 按钮) 和 倒计时自动关闭,并在关闭时触发统一的 @close 事件。
一、环境要求
| 工具 | 推荐版本 |
|---|---|
| Node.js | >= 16.0,建议 18.x / 20.x |
| Vue | ^3.2.0(已声明为 peerDependency) |
| 包管理器 | npm / pnpm / yarn 均可 |
二、快速接入(三步使用)
1. 安装依赖
在已有 Vue 3 项目中执行:
npm install msg-cards
# 或
pnpm add msg-cards
# 或
yarn add msg-cards2. 引入样式(重要)
组件的样式(主题色、阴影、切角等)单独打包在 msg-cards/dist/style.css。需在应用入口全局引入一次。
// src/main.ts
import { createApp } from 'vue'
import App from './App.vue'
// 必须引入样式文件(只引入一次)
import 'msg-cards/dist/style.css'
createApp(App).mount('#app')3. 注册组件(任选其一)
方式 A:全局注册(适合整站统一使用)
// src/main.ts
import { createApp } from 'vue'
import App from './App.vue'
import MsgCards from 'msg-cards'
import 'msg-cards/dist/style.css'
createApp(App)
.use(MsgCards) // 一次性全局注册 8 个组件
.mount('#app')在任意 .vue 模板中直接写标签:
<template>
<MsgCard28 title="异常告警" :items="alerts" />
<MsgCard34 label="告警数据" :value="128" />
</template>方式 B:按需引入(推荐,打包体积最小)
<script setup lang="ts">
import { MsgCard28, MsgCard31, MsgCard34 } from 'msg-cards'
import type { AlertItem } from 'msg-cards'
const alerts: AlertItem[] = [
{ label: '数据中心01', value: '温度正常', level: 'success' },
{ label: '数据中心02', value: '异常', level: 'danger' }
]
</script>
<template>
<MsgCard28 title="异常告警" :items="alerts" />
<MsgCard31
title="机房参数展示"
:items="[
{ label: 'CPU', value: '62%', ratio: 0.62 },
{ label: '内存', value: '48%', ratio: 0.48 },
{ label: '磁盘', value: '81%', ratio: 0.81 }
]"
/>
<MsgCard34 label="今日告警" :value="128" />
</template>三、通用 Props / Events(所有组件均支持)
| 属性 / 事件 | 类型 | 默认值 | 说明 |
|---|---|---|---|
duration |
number |
0 |
倒计时秒数;> 0 自动关闭,0 只能手动点 × 关闭 |
@close |
Event |
— | 关闭触发(倒计时归零、点 × 或点蒙层均触发) |
overlay |
boolean |
true |
是否显示深色蒙层 |
centered |
boolean |
true |
是否在屏幕居中(需 overlay=true;设为 false 则卡片保持原有页面流式定位) |
position |
'top' | 'center' | 'bottom' |
'center' |
居中时垂直对齐位置(仅 centered=true 时生效) |
overlayClosable |
boolean |
true |
点击蒙层是否关闭卡片 |
overlayOpacity |
number |
0.6 |
蒙层透明度(0-1) |
pulse |
boolean |
true |
是否开启警报闪烁动效;关闭后卡片使用正常静态样式 |
使用示例:
<template>
<!-- 居中蒙层(默认),点击蒙层或倒计时结束关闭 -->
<MsgCard28 title="告警" :items="items" :duration="5" @close="onClosed" />
<!-- 顶部弹出,居中显示 -->
<MsgCard31 title="参数展示" :position="'top'" :overlay-opacity="0.4" :duration="8" @close="onClosed" />
<!-- 无蒙层,保持原有页面布局(用于页面内嵌入) -->
<MsgCard33 title="数据中心" :overlay="false" :centered="false" />
<!-- 底部弹出,不允许点击蒙层关闭 -->
<MsgCard34 label="告警数据" :value="128" :position="'bottom'" :overlay-closable="false" />
</template>关闭按钮(×)位于卡片标题栏右上角,hover 高亮;倒计时数字显示在关闭按钮左侧(仅 duration > 0 时出现)。蒙层点击关闭时同样触发 @close 事件。
四、在 TS 文件中命令式调用(不依赖 Vue 模板)
当你在 .ts / .tsx 工具模块(例如数据推送服务、全局通知中心、事件处理函数)中,希望直接「发一条卡片消息」,可使用 msg-cards 提供的命令式 API:
// src/services/message-push.ts
import { pushCard28, pushCard34 } from 'msg-cards'
import 'msg-cards/dist/style.css'
// 方式 1:使用类型化快捷接口(推荐)
const card = pushCard28(
{
title: '异常告警',
duration: 8,
items: [
{ label: '数据中心01', value: '温度正常', level: 'success' },
{ label: '数据中心02', value: '异常', level: 'danger' }
]
},
{ zIndex: 9999 }
)
// 返回值提供 close() 方法,可手动提前关闭
setTimeout(() => card.close(), 2000)// 方式 2:通用 pushCard,手动传入任意组件
import { h } from 'vue'
import { pushCard, MsgCard31 } from 'msg-cards'
const card = pushCard(
MsgCard31,
{
tagLabel: '告警',
title: '数据中心01机房参数展示',
items: [
{ label: 'CPU', value: '62%', ratio: 0.62 },
{ label: '内存', value: '48%', ratio: 0.48 }
],
duration: 10,
onClose: () => console.log('卡片已关闭')
}
)// 方式 3:自定义容器(例如把卡片推到自己的 DOM 容器里,而不是 body 浮层)
import { pushCard32 } from 'msg-cards'
pushCard32(
{ title: '机房监控全景图' },
{ container: '#dashboard-cards', insertMode: 'prepend' }
)命令式 API 参考
所有 pushCardNN(...) 都接受 Props + PushOptions,返回 PushResult:
// 类型定义
import type {
PushResult, PushOptions,
Push28Props, Push29Props /* ... */
} from 'msg-cards'
interface PushOptions {
container?: Element | string // 自定义容器,默认创建独立浮层
insertMode?: 'append' | 'prepend' // 插入方式
zIndex?: number // 浮层 z-index,默认 9999
/** 是否显示蒙层,默认为 true */
overlay?: boolean
/** 是否居中,默认为 true */
centered?: boolean
/** 居中时垂直位置,默认为 'center' */
position?: 'top' | 'center' | 'bottom'
/** 点击蒙层是否关闭,默认为 true */
overlayClosable?: boolean
/** 蒙层透明度,0-1,默认为 0.6 */
overlayOpacity?: number
/** 是否开启警报闪烁动效,默认为 true */
pulse?: boolean
}
interface PushResult {
close: () => void // 手动销毁卡片
vnode: VNode // 底层 VNode 引用(高级用法)
el: HTMLElement // 实际挂载的 DOM 容器
}在事件流中的典型用法
// src/composables/usePushNotification.ts
import { ref } from 'vue'
import { pushCard28, pushCard34 } from 'msg-cards'
const list = ref<{ close: () => void }[]>([])
export function notifyError(title: string, items: Array<{ label: string; value: string; level?: string }>) {
const card = pushCard28({
title,
items,
duration: 10,
// 顶部弹出蒙层
position: 'top',
overlayOpacity: 0.5
})
list.value.push(card)
}
export function notifyBigNumber(label: string, value: number) {
// 无蒙层,直接嵌入页面流中
pushCard34({
label,
value,
overlay: false,
centered: false
})
}
export function closeAll() {
list.value.forEach(c => c.close())
list.value = []
}TSX / render 函数中的用法
// src/components/Dashboard.tsx 中的 render 函数用法
import { defineComponent } from 'vue'
import { MsgCard28 } from 'msg-cards'
export default defineComponent({
setup() {
return () => (
<MsgCard28
title="异常告警"
duration={8}
items={[
{ label: '数据中心01', value: '温度正常', level: 'success' }
]}
onClose={() => console.log('closed')}
/>
)
}
})**提示:TSX 用法本质上仍是模板声明式用法;
pushCard*()是真正的“命令式推送”。前者用于 `.ts/.tsx 文件中主动触发卡片推送。
五、各组件 Props 速览
MsgCard28 · 异常告警列表
| Prop | 类型 | 默认值 | 说明 |
|---|---|---|---|
title |
string |
'异常告警' |
标题 |
items |
AlertItem[] |
[] |
告警条目列表 |
duration |
number |
0 |
自动关闭秒数 |
overlay |
boolean |
true |
是否显示蒙层 |
centered |
boolean |
true |
是否居中 |
position |
'top' | 'center' | 'bottom' |
'center' |
垂直位置 |
overlayClosable |
boolean |
true |
点击蒙层关闭 |
overlayOpacity |
number |
0.6 |
蒙层透明度 |
pulse |
boolean |
true |
是否开启警报闪烁动效 |
interface AlertItem {
label: string
value: string | number
level?: 'info' | 'success' | 'warning' | 'danger'
}MsgCard29 · 数据中心异常告警(含场景图)
| Prop | 类型 | 默认值 | 说明 |
|---|---|---|---|
title |
string |
'数据中心异常告警' |
标题 |
subtitle |
string |
'数据中心C01机房' |
场景图下方文字 |
time |
string |
'' |
右侧显示的时间戳 |
params |
RoomParam[] |
[] |
参数列表 |
sceneImage |
string |
'' |
自定义场景图 URL,未传时使用内置 SVG |
duration |
number |
0 |
自动关闭秒数 |
overlay |
boolean |
true |
是否显示蒙层 |
centered |
boolean |
true |
是否居中 |
position |
'top' | 'center' | 'bottom' |
'center' |
垂直位置 |
overlayClosable |
boolean |
true |
点击蒙层关闭 |
overlayOpacity |
number |
0.6 |
蒙层透明度 |
pulse |
boolean |
true |
是否开启警报闪烁动效 |
interface RoomParam {
label: string
value: string | number
unit?: string
}MsgCard30 · 数据仓对比
| Prop | 类型 | 默认值 | 说明 |
|---|---|---|---|
title |
string |
'三号仓' |
标题 |
icon |
string |
'🏠' |
图标字符 |
rows |
WarehouseRow[] |
[] |
数据行 |
duration |
number |
0 |
自动关闭秒数 |
overlay |
boolean |
true |
是否显示蒙层 |
centered |
boolean |
true |
是否居中 |
position |
'top' | 'center' | 'bottom' |
'center' |
垂直位置 |
overlayClosable |
boolean |
true |
点击蒙层关闭 |
overlayOpacity |
number |
0.6 |
蒙层透明度 |
pulse |
boolean |
true |
是否开启警报闪烁动效 |
interface WarehouseRow {
label: string
today: number | string
yesterday: number | string
trend?: 'up' | 'down' | 'flat'
trendValue?: string | number
}MsgCard31 · 机房参数环形图
| Prop | 类型 | 默认值 | 说明 |
|---|---|---|---|
tagLabel |
string |
'告警' |
顶部角标文字 |
title |
string |
'数据中心01机房参数展示' |
标题 |
items |
MetricItem[] |
[] |
环形指标项 |
duration |
number |
0 |
自动关闭秒数 |
overlay |
boolean |
true |
是否显示蒙层 |
centered |
boolean |
true |
是否居中 |
position |
'top' | 'center' | 'bottom' |
'center' |
垂直位置 |
overlayClosable |
boolean |
true |
点击蒙层关闭 |
overlayOpacity |
number |
0.6 |
蒙层透明度 |
pulse |
boolean |
true |
是否开启警报闪烁动效 |
interface MetricItem {
label: string
value: number | string
ratio?: number // 0 - 1,决定环形进度
}MsgCard32 · 机房监控全景图
| Prop | 类型 | 默认值 | 说明 |
|---|---|---|---|
title |
string |
'机房监控全景图' |
标题 |
items |
MonitorItem[] |
[] |
机房场景列表 |
duration |
number |
0 |
自动关闭秒数 |
overlay |
boolean |
true |
是否显示蒙层 |
centered |
boolean |
true |
是否居中 |
position |
'top' | 'center' | 'bottom' |
'center' |
垂直位置 |
overlayClosable |
boolean |
true |
点击蒙层关闭 |
overlayOpacity |
number |
0.6 |
蒙层透明度 |
pulse |
boolean |
true |
是否开启警报闪烁动效 |
interface MonitorItem {
title: string
subtitle?: string
image?: string // 不传时使用内置 SVG 场景图
}MsgCard33 · 数据中心网格
| Prop | 类型 | 默认值 | 说明 |
|---|---|---|---|
title |
string |
'数据中心01机房' |
标题 |
rows |
Cell[][] |
[] |
二维数组,按行 × 列排列 |
duration |
number |
0 |
自动关闭秒数 |
overlay |
boolean |
true |
是否显示蒙层 |
centered |
boolean |
true |
是否居中 |
position |
'top' | 'center' | 'bottom' |
'center' |
垂直位置 |
overlayClosable |
boolean |
true |
点击蒙层关闭 |
overlayOpacity |
number |
0.6 |
蒙层透明度 |
pulse |
boolean |
true |
是否开启警报闪烁动效 |
interface Cell {
label: string
value: string | number
}MsgCard34 · 告警大数值
| Prop | 类型 | 默认值 | 说明 |
|---|---|---|---|
icon |
string |
'!' |
左侧圆形图标内容 |
label |
string |
'告警数据' |
标题 |
value |
string | number |
236.452 |
大数值 |
duration |
number |
0 |
自动关闭秒数 |
overlay |
boolean |
true |
是否显示蒙层 |
centered |
boolean |
true |
是否居中 |
position |
'top' | 'center' | 'bottom' |
'center' |
垂直位置 |
overlayClosable |
boolean |
true |
点击蒙层关闭 |
overlayOpacity |
number |
0.6 |
蒙层透明度 |
pulse |
boolean |
true |
是否开启警报闪烁动效 |
MsgCard35 · 地理位置标签
| Prop | 类型 | 默认值 | 说明 |
|---|---|---|---|
label |
string |
'北京' |
旗帜中央文字 |
duration |
number |
0 |
自动关闭秒数 |
overlay |
boolean |
true |
是否显示蒙层 |
centered |
boolean |
true |
是否居中 |
position |
'top' | 'center' | 'bottom' |
'center' |
垂直位置 |
overlayClosable |
boolean |
true |
点击蒙层关闭 |
overlayOpacity |
number |
0.6 |
蒙层透明度 |
pulse |
boolean |
true |
是否开启警报闪烁动效 |
所有类型定义一键引入
import type {
AlertLevel,
AlertItem,
RoomParam,
WarehouseRow,
MonitorItem
} from 'msg-cards'六、从本仓库构建发布(作为依赖包提供者的流程)
1. 克隆与安装
git clone <仓库地址>
cd msg-cards
npm install2. 本地预览全部卡片
npm run dev
# 打开 http://localhost:5173访问后可在浏览器中看到 8 种卡片的完整效果,以及带倒计时 / 手动关闭的交互演示。
3. 构建库产物(ES + UMD + 类型声明)
npm run build # 等价于 npm run build:lib构建完成后 dist/ 目录:
dist/
├── msg-cards.es.js # ESM 产物(现代打包工具使用)
├── msg-cards.umd.js # UMD 产物(<script> 标签 / require 使用)
├── style.css # 统一主题样式(必须引入一次)
└── types/
├── index.d.ts
├── components/MsgCard28.vue.d.ts
├── …
└── types/index.d.ts # AlertItem / RoomParam 等类型
构建配置文件:vite.lib.config.ts
4. 本地测试(link 到其他项目)
# 在 msg-cards 目录
npm run build
npm link # 将 msg-cards 链接到全局 node_modules
# 在你的项目目录
npm link msg-cards # 将本地构建包以软链方式引入5. 发布到 npm / 私有仓库
npm run build # 先构建
npm login # 登录到对应仓库
npm publish # 仅会发布 dist/(由 package.json files 字段控制)若发布到公司私有仓库(例如 Verdaccio / GitLab Registry),可在
.npmrc中配置registry或通过--registry参数指定。
6. 仅做类型检查(不构建)
npm run type-check # 等同于 vue-tsc --noEmit七、UMD 浏览器直接引入(无需构建工具)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<title>msg-cards UMD Demo</title>
<link rel="stylesheet" href="./dist/style.css" />
</head>
<body>
<div id="app">
<msg-card28 :title="'异常告警'" :items="items" :duration="10" @close="() => console.log('closed')" />
<msg-card34 :label="'告警数据'" :value="128" />
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
<script src="./dist/msg-cards.umd.js"></script>
<script>
const { createApp, ref } = Vue
const { MsgCard28, MsgCard34 } = window.MsgCards
createApp({
components: { MsgCard28, MsgCard34 },
setup() {
return {
items: ref([
{ label: '数据中心01', value: '温度正常', level: 'success' },
{ label: '数据中心02', value: '异常', level: 'danger' }
])
}
}
}).mount('#app')
</script>
</body>
</html>八、主题色自定义
主题色(深红 #ff2a44)定义在 CSS 变量中,可在项目全局覆盖:
/* src/styles/msg-cards-override.css */
:root {
--mc-primary: #00c2ff; /* 主色改为青色 */
--mc-primary-light: #3ddcff;
--mc-primary-dark: #0077a8;
--mc-primary-glow: rgba(0, 194, 255, 0.45);
--mc-panel-border: rgba(0, 194, 255, 0.55);
}在入口文件中紧随 msg-cards/dist/style.css 之后引入即可:
import 'msg-cards/dist/style.css'
import './styles/msg-cards-override.css'九、目录结构
msg-cards/
├── src/
│ ├── components/ # 8 个卡片组件(均支持 duration/close)
│ │ ├── MsgCard28.vue ~ MsgCard35.vue
│ │
│ ├── styles/theme.css # 主题色 + 基础样式
│ ├── types/index.ts # AlertItem / RoomParam / WarehouseRow / MonitorItem
│ ├── push.ts # 命令式 API(pushCard28/pushCard29/...)
│ ├── index.ts # 插件入口,具名导出 + Vue Plugin 导出
│ └── shims-vue.d.ts
│
├── demo/ # 本地开发示例(App.vue / main.ts)
├── index.html # Vite 开发入口
├── vite.config.ts # 开发 / Demo 构建配置
├── vite.lib.config.ts # 库模式构建配置(生产发布用)
├── tsconfig.json # 开发用 tsconfig(包含 demo)
├── tsconfig.lib.json # 库模式专用 tsconfig(仅 src)
└── package.json
十、常见问题
Q1. 引入后卡片没有显示样式 / 颜色 / 切角?
确认已在全局入口执行一次
import 'msg-cards/dist/style.css'。若用按需引入(未调用use(MsgCards)),样式仍需手动引入。
Q2. 卡片显得太宽 / 太窄,不贴合我的大屏?
卡片组件均采用内容自适应宽度(内部
width: 420px ~ 520px等仅为默认),可通过外层容器设置width/transform: scale()或使用 CSS Grid 排列多个卡片。
Q3. TypeScript 报错找不到 .vue 类型?
确保宿主项目
tsconfig.json的compilerOptions.types包含"vite/client"(或已有shims-vue.d.ts)。从包中引入时,类型定义已输出到msg-cards/dist/types/。
Q4. 想覆盖某张卡片的内部颜色、阴影等细节?
由于每个组件的
<style scoped>使用了--mc-*变量,直接在宿主项目覆盖同名 CSS 变量即可全局生效;也可对特定组件外层:deep()覆盖。
Q5. npm run build 报 Search string not found: supportedTSExtensions?
旧的
vue-tsc 1.8.x与 TypeScript 5.5+ 不兼容。本仓库已锁定typescript ~5.4.5+vue-tsc ^2.0.0,重新npm install即可。
Q6. 如何只启用手动关闭,禁用倒计时自动关闭?
不传入
duration或传:duration="0"即可。此时卡片右上角仍显示×按钮,点击后触发@close。
Q7. 倒计时结束或点击关闭后,如何让同一卡片重新显示?
当前关闭会从 DOM 移除。需要通过父组件用
v-if重新挂载:<template> <MsgCard28 v-if="show" :duration="10" @close="show = false" :items="items" /> <button @click="show = true">重新推送</button> </template> <script setup lang="ts"> import { ref } from 'vue' const show = ref(true) </script>
十一、版本与 License
- 版本:
1.0.0(代码中通过import { version } from 'msg-cards'可读取) - License:MIT