msg-cards-xh
v1.0.4
Published
基于 Vue 3 + TypeScript 的科技风消息卡片推送组件库(异常告警/机房监控/数据仓等 8 种卡片样式)
Downloads
213
Maintainers
Readme
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' }
)// 方式 4:命令式 Modal —— 通过回调处理 confirm / cancel
import { pushModal } from 'msg-cards'
pushModal({
type: 'warning',
variant: 'list',
title: '确认执行操作?',
message: '以下数据将被清除,请确认',
items: [
{ label: '影响设备', value: '128 台', level: 'danger' },
{ label: '预计耗时', value: '约 3 分钟' }
],
confirmText: '立即执行',
cancelText: '再想想',
// 回调方式
onConfirm: () => console.log('用户点击了确定'),
onCancel: () => console.log('用户点击了取消'),
onClose: () => console.log('弹窗关闭(任何原因)')
})// 方式 5:命令式 Modal —— 使用 Promise await(推荐用于串行流程)
import { pushModal } from 'msg-cards'
async function handleDelete() {
const { result } = pushModal({
type: 'error',
title: '危险操作',
message: '该操作不可恢复,是否继续?',
confirmText: '删除',
cancelText: '取消'
})
// 等待用户操作(点确定 / 点取消 / 点 × / ESC / 超时 / 手动 close)
const reason = await result
if (reason === 'confirm') {
await doDelete()
} else {
console.log('用户取消了操作,原因:', reason)
}
}通用回调 Props
所有 pushCardNN() 和 pushModal() 都接受以下事件回调(在 Props 中直接传入即可):
| 回调 | 触发时机 | 适用范围 |
| --- | --- | --- |
| onClose?: () => void | 卡片被关闭(任何原因) | 所有卡片 + Modal |
| onConfirm?: () => void | 用户点击"确定"按钮 | 仅 Modal |
| onCancel?: () => void | 用户点击"取消"按钮 | 仅 Modal |
同时使用回调和
await result不冲突——Promise 会在回调执行后 resolve,且保证只 resolve 一次(幂等)。
命令式 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
}
// 卡片关闭原因
type CloseReason = 'confirm' | 'cancel' | 'close'
// - 'confirm' 用户点击了"确定"按钮(Modal 专用)
// - 'cancel' 用户点击了"取消"按钮(Modal 专用)
// - 'close' 其他关闭方式:手动 × / 蒙层点击 / ESC / 倒计时结束 / 手动调用 close()
interface PushResult {
close: () => void // 手动销毁卡片
vnode: VNode // 底层 VNode 引用(高级用法)
el: HTMLElement // 实际挂载的 DOM 容器
result: Promise<CloseReason> // Promise 形式的关闭结果,可 await 等待用户操作
}在事件流中的典型用法
// 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
