通知栏NoticeBar
在页面顶部或内容区之间横向滚动展示一条通告(如「系统维护通知」)
反馈 规格 16 · 通知栏 NoticeBar 6 端实现 触摸优先
<!-- ① 令牌:PC 令牌 + 移动端 --kole-m-* 合成单文件,引一次 -->
<link rel="stylesheet" href="kole-ui/mobile/tokens.css">
<!-- ② 本组件样式(全量则用 kole-ui/mobile/components/index.css) -->
<link rel="stylesheet" href="kole-ui/mobile/components/mobile-noticebar.css">
<!-- ③ 结构照抄下方任一演示块(类名与 6 端实现一致) -->
演示
每个演示都是真实渲染:预览帧加载 frameworks-mobile/NoticeBar.html?demo=<id>(只显示该演示块),代码是该演示块在演示页里的原文,可复制。全部演示同屏可看 演示页 ↗。
01 组件类型
品牌浅底 + 同族深字;容器带 role=status,读屏会朗读一次。
查看代码(演示页原文 · 7 行)
<section class="demo-block" data-demo="basic">
<p class="demo-label">基础通告(tone=default:品牌浅底,container 带 role=status 朗读一次)</p>
<div class="kole-m-noticebar kole-m-noticebar--default" role="status" data-assert="noticebar-basic">
<span class="kole-m-noticebar__icon" aria-hidden="true">▸</span>
<span class="kole-m-noticebar__text">系统将于今晚 23:00 进行例行维护,预计 30 分钟。</span>
</div>
</section>关闭按钮是原生 button、24×24 热区,aria-label 带上通告内容以便区分。
查看代码(演示页原文 · 9 行)
<section class="demo-block" data-demo="closable">
<p class="demo-label">可关闭(closable=true:关闭按钮是原生 button,热区 24×24,点后打标记)</p>
<div class="kole-m-noticebar kole-m-noticebar--warning" id="noticebar-closable" role="status" data-assert="noticebar-closable">
<span class="kole-m-noticebar__icon" aria-hidden="true">!</span>
<span class="kole-m-noticebar__text">当前有 3 笔订单即将超时,请尽快处理。</span>
<button class="kole-m-noticebar__close" type="button" aria-label="关闭通告:订单超时提醒"
data-behavior="click-sets-attr:#noticebar-closable|data-closed|true">✕</button>
</div>
</section>文案超宽时横向循环滚动;系统开启「减少动态效果」时停止滚动并改为换行。
查看代码(演示页原文 · 12 行)
<section class="demo-block" data-demo="scrollable">
<p class="demo-label">跑马灯(scrollable=true:文字超宽时横向滚动;reduced-motion 下停止并换行)</p>
<div class="kole-m-noticebar kole-m-noticebar--scrollable" role="status" data-assert="noticebar-scrollable">
<span class="kole-m-noticebar__icon" aria-hidden="true">▸</span>
<span class="kole-m-noticebar__text">
<span class="kole-m-noticebar__track">
<span class="kole-m-noticebar__seg">平台升级公告:新增批量导入与导出能力,历史数据无需迁移;如遇问题请联系客服。</span>
<span class="kole-m-noticebar__seg kole-m-noticebar__seg--dup" aria-hidden="true">平台升级公告:新增批量导入与导出能力,历史数据无需迁移;如遇问题请联系客服。</span>
</span>
</span>
</div>
</section>02 组件状态
成功与失败语气用同族浅底,颜色之外还有图标区分,不只靠色相。
查看代码(演示页原文 · 11 行)
<section class="demo-block" data-demo="tone">
<p class="demo-label">四种语气(tone=success / danger:浅底 + 同族深字,亮暗两态都达标)</p>
<div class="kole-m-noticebar kole-m-noticebar--success" role="status" data-assert="noticebar-tone">
<span class="kole-m-noticebar__icon" aria-hidden="true">✓</span>
<span class="kole-m-noticebar__text">本月账单已结清,感谢使用。</span>
</div>
<div class="kole-m-noticebar kole-m-noticebar--danger" role="status">
<span class="kole-m-noticebar__icon" aria-hidden="true">!</span>
<span class="kole-m-noticebar__text">账号存在异地登录,建议立即修改密码。</span>
</div>
</section>API
props / events / slots 为 6 端实现的公共接口(说明文字取自规格对应小节)。字段名与各端源码逐名核对:node tools/verify-mobile-docs.mjs
Props
| 名称 | 类型 | 默认值 | 说明 | 必传 |
|---|---|---|---|---|
tone | 'default' | 'success' | 'warning' | 'danger' | 'default' | 变体 tone:四种语气(浅底 + 同族深字)(规格 §16.3) | N |
scrollable | boolean | false | 变体 scrollable:文字超宽时是否跑马灯(规格 §16.3) | N |
closable | boolean | false | 变体 closable:是否显示关闭按钮(规格 §16.3) | N |
text | string | '' | 通告文字(规格 §16.2 text) | N |
「必传」按严格定义:实现里**没有默认值**时才为 Y(本门禁逐条核对 props 与各端源码的默认值,防止契约与实现脱节)。
事件
| 名称 | 参数 | 说明 |
|---|---|---|
close | — | 点击关闭按钮时触发;是否移除这条通告由宿主决定(规格 §16.5) |
插槽
| 名称 | 说明 |
|---|---|
default | 通告内容(与 text 二选一;text 优先) |
CSS 变量
组件级变量(在组件样式表里定义)。业务侧可在自己的作用域内覆盖,不必改组件源码。
| 名称 | 默认值 | 说明 |
|---|---|---|
--kole-m-noticebar-icon-size | 16px | 组件内部默认值,可在业务侧覆盖 |
何时使用
- 在页面顶部或内容区之间横向滚动展示一条通告(如「系统维护通知」)
- 关闭按钮热区不小于 24×24(用负外边距扩展)
- 跑马灯在 prefers-reduced-motion: reduce 下停止滚动并改为换行显示(无障碍硬要求)
- 关闭动作只触发一次事件,是否移除由宿主决定
- 容器 role="status"(读屏会朗读一次通告)
- 跑马灯不得用 aria-live(滚动内容反复朗读会干扰)
交互与触控
- 关闭按钮热区不小于 24×24(用负外边距扩展)
- 跑马灯在 prefers-reduced-motion: reduce 下停止滚动并改为换行显示(无障碍硬要求)
- 关闭动作只触发一次事件,是否移除由宿主决定
无障碍
- 容器 role="status"(读屏会朗读一次通告)
- 关闭按钮为原生 button 并带 aria-label
- 跑马灯不得用 aria-live(滚动内容反复朗读会干扰)
相似组件
从「该用哪一个」的角度区分;PC 端的对应实现见 PC 文档站。
| 组件 | 何时用它而不是本组件 |
|---|---|
| 轻提示Toast | 一次性结果反馈用轻提示;需要常驻在页面里的通告才用通知栏 |
| 标签Tag | 很短的状态词用标签;整句通告用通知栏 |
| 分割线Divider | 通知栏与内容区之间靠浅底与留白分隔,不必再插分割线 |
规格未定 / 禁止发明
| 类别 | 条目 |
|---|---|
| 禁止发明 | 多条通告的排队 / 轮播 |
| 禁止发明 | 滚动速度的可配置项 |
| 规格未定 | 通告文字的最大长度 |
| 规格未定 | 是否支持富文本 |
结构(anatomy)
| 字段 | 说明 |
|---|---|
noticebar | 根容器 |
noticebar__icon | 左侧喇叭图标 |
noticebar__text | 通告文字(可滚动) |
noticebar__close | 可选关闭按钮 |
变体维度与类名映射
类名映射由构建脚本从契约 variantClasses 生成,并被 verify:mobile-docs 逐条对照组件 CSS 校验(类/变量必须真实存在)。
| 维度 | 取值 | 对应类名 / 变量 |
|---|---|---|
tone | default / success / warning / danger | default .kole-m-noticebar--default success .kole-m-noticebar--success warning .kole-m-noticebar--warning danger .kole-m-noticebar--danger |
scrollable | false / true | false (由数据驱动,无专属类) true .kole-m-noticebar--scrollable |
closable | false / true | false (由数据驱动,无专属类) true .kole-m-noticebar__close |
代表变体
| 变体 | 标签 |
|---|---|
tone=default · scrollable=false · closable=false | 基础通告 |
tone=warning · scrollable=false · closable=true | 可关闭提醒 |
tone=default · scrollable=true · closable=false | 跑马灯长通告 |
tone=success · scrollable=false · closable=false | 成功语气 |
用到的令牌
构建时从本组件样式表扫描得出。蓝色为移动端自有令牌,绿色为继承的 PC 令牌(改一处两端生效)。
6 端源码
同一组件的六份实现(生产环境的类名与结构一致,差异只在技术栈写法与单位)。点开查看,右侧可复制。
frameworks-mobile/NoticeBar.css · 纯样式(CSS) · 102 行
/* Kole UI Mobile · NoticeBar 样式 — 对齐移动端规格 §16
通知栏:浅底 + 同族字色;跑马灯在 prefers-reduced-motion: reduce 下停止滚动并换行显示。 */
.kole-m-noticebar {
--kole-m-noticebar-icon-size: 16px;
display: flex;
align-items: center;
gap: var(--kole-space-8);
box-sizing: border-box;
min-height: var(--kole-m-touch-target);
padding: var(--kole-space-8) var(--kole-m-gutter);
background: var(--kole-color-brand-bg);
color: var(--kole-color-brand);
font-family: var(--kole-font-family);
font-size: var(--kole-m-font-size-label);
line-height: 1.4;
overflow: hidden;
}
/* 变体 tone:四种语气(浅底 + 同族深字) */
.kole-m-noticebar--default { background: var(--kole-color-brand-bg); color: var(--kole-color-brand); }
.kole-m-noticebar--success { background: var(--kole-color-tag-green-bg); color: var(--kole-color-success); }
.kole-m-noticebar--warning { background: var(--kole-color-table-header-bg); color: var(--kole-color-warning); }
.kole-m-noticebar--danger { background: var(--kole-color-table-header-bg); color: var(--kole-color-error); }
.kole-m-noticebar__icon {
flex: 0 0 auto;
font-size: var(--kole-m-noticebar-icon-size);
line-height: 1;
}
.kole-m-noticebar__text {
flex: 1 1 auto;
min-width: 0;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
/* 变体 scrollable=true:文字超宽时跑马灯(内容用两段拼接实现无缝循环) */
.kole-m-noticebar--scrollable .kole-m-noticebar__text {
text-overflow: clip;
}
.kole-m-noticebar--scrollable .kole-m-noticebar__track {
display: inline-flex;
gap: var(--kole-space-48);
padding-inline-end: var(--kole-space-48);
white-space: nowrap;
animation: kole-m-noticebar-scroll 12s linear infinite;
}
@keyframes kole-m-noticebar-scroll {
from { transform: translateX(0); }
to { transform: translateX(-50%); }
}
/* 无障碍硬要求:减少动态偏好下停止滚动并允许换行(规格 §16.5) */
@media (prefers-reduced-motion: reduce) {
.kole-m-noticebar--scrollable .kole-m-noticebar__text {
white-space: normal;
}
.kole-m-noticebar--scrollable .kole-m-noticebar__track {
display: block;
animation: none;
padding-inline-end: 0;
}
/* 滚动形态下第二段是循环占位,静止时不该出现 */
.kole-m-noticebar--scrollable .kole-m-noticebar__track > .kole-m-noticebar__seg--dup {
display: none;
}
}
/* 关闭按钮:原生 button,24×24 热区(负外边距吸收,不撑高栏体) */
.kole-m-noticebar__close {
flex: 0 0 auto;
display: inline-flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
width: 24px;
height: 24px;
margin-inline-end: calc(-1 * var(--kole-space-8));
padding: 0;
border: 0;
border-radius: 50%;
background: none;
color: inherit;
font-family: inherit;
font-size: var(--kole-m-font-size-caption);
line-height: 1;
cursor: pointer;
touch-action: manipulation;
}
.kole-m-noticebar__close:focus-visible {
outline: 2px solid var(--kole-color-focus-ring);
outline-offset: -2px;
}
.kole-m-noticebar__close:active { background: var(--kole-color-table-header-bg); }
frameworks-mobile/NoticeBar.html · H5 原生(无框架) · 95 行
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
<title>Kole UI Mobile · NoticeBar(H5)</title>
<link rel="stylesheet" href="../.design_library/kole-ui-mobile/colors_and_type.css">
<link rel="stylesheet" href="NoticeBar.css">
<style>
body { margin: 0; background: var(--kole-color-page-bg); font-family: var(--kole-font-family); color: var(--kole-color-text-body); }
.demo { max-width: 375px; margin: 0 auto; padding: var(--kole-m-gutter) 0; }
.demo-label { margin: 0; padding: var(--kole-space-12) var(--kole-m-gutter) var(--kole-space-8);
font-size: var(--kole-m-font-size-label); color: var(--kole-color-text-secondary); }
.demo-block[hidden] { display: none; }
</style>
</head>
<body>
<div class="demo">
<section class="demo-block" data-demo="basic">
<p class="demo-label">基础通告(tone=default:品牌浅底,container 带 role=status 朗读一次)</p>
<div class="kole-m-noticebar kole-m-noticebar--default" role="status" data-assert="noticebar-basic">
<span class="kole-m-noticebar__icon" aria-hidden="true">▸</span>
<span class="kole-m-noticebar__text">系统将于今晚 23:00 进行例行维护,预计 30 分钟。</span>
</div>
</section>
<section class="demo-block" data-demo="closable">
<p class="demo-label">可关闭(closable=true:关闭按钮是原生 button,热区 24×24,点后打标记)</p>
<div class="kole-m-noticebar kole-m-noticebar--warning" id="noticebar-closable" role="status" data-assert="noticebar-closable">
<span class="kole-m-noticebar__icon" aria-hidden="true">!</span>
<span class="kole-m-noticebar__text">当前有 3 笔订单即将超时,请尽快处理。</span>
<button class="kole-m-noticebar__close" type="button" aria-label="关闭通告:订单超时提醒"
data-behavior="click-sets-attr:#noticebar-closable|data-closed|true">✕</button>
</div>
</section>
<section class="demo-block" data-demo="scrollable">
<p class="demo-label">跑马灯(scrollable=true:文字超宽时横向滚动;reduced-motion 下停止并换行)</p>
<div class="kole-m-noticebar kole-m-noticebar--scrollable" role="status" data-assert="noticebar-scrollable">
<span class="kole-m-noticebar__icon" aria-hidden="true">▸</span>
<span class="kole-m-noticebar__text">
<span class="kole-m-noticebar__track">
<span class="kole-m-noticebar__seg">平台升级公告:新增批量导入与导出能力,历史数据无需迁移;如遇问题请联系客服。</span>
<span class="kole-m-noticebar__seg kole-m-noticebar__seg--dup" aria-hidden="true">平台升级公告:新增批量导入与导出能力,历史数据无需迁移;如遇问题请联系客服。</span>
</span>
</span>
</div>
</section>
<section class="demo-block" data-demo="tone">
<p class="demo-label">四种语气(tone=success / danger:浅底 + 同族深字,亮暗两态都达标)</p>
<div class="kole-m-noticebar kole-m-noticebar--success" role="status" data-assert="noticebar-tone">
<span class="kole-m-noticebar__icon" aria-hidden="true">✓</span>
<span class="kole-m-noticebar__text">本月账单已结清,感谢使用。</span>
</div>
<div class="kole-m-noticebar kole-m-noticebar--danger" role="status">
<span class="kole-m-noticebar__icon" aria-hidden="true">!</span>
<span class="kole-m-noticebar__text">账号存在异地登录,建议立即修改密码。</span>
</div>
</section>
</div>
<script>
/* 演示页交互:关闭按钮只打标记(真实业务里是否移除这条通告由宿主决定)。 */
(function () {
document.querySelectorAll('.kole-m-noticebar__close').forEach(function (btn) {
btn.addEventListener('click', function () {
var bar = btn.closest('.kole-m-noticebar');
if (bar) bar.setAttribute('data-closed', 'true');
});
});
})();
</script>
<script>
/* ?demo=<id> → 只显示该演示块(文档站按块预览用;无参数时全部显示,测试与回归走无参数路径) */
(function () {
var id = new URLSearchParams(location.search).get('demo');
if (!id) return;
var blocks = Array.prototype.slice.call(document.querySelectorAll('.demo-block'));
var hit = false;
blocks.forEach(function (b) {
var on = b.getAttribute('data-demo') === id;
if (on) hit = true;
b.hidden = !on;
});
if (!hit) { blocks.forEach(function (b) { b.hidden = false; }); return; }
document.body.classList.add('demo-single');
blocks.forEach(function (b) {
var label = b.querySelector('.demo-label');
if (label && !b.hidden) label.hidden = true;
});
})();
</script>
</body>
</html>
frameworks-mobile/NoticeBar.jsx · React · 53 行
import React from 'react';
import './NoticeBar.css';
/* 通知栏(移动端)— 规格 §16;容器 role=status(读屏朗读一次);
跑马灯在 prefers-reduced-motion 下由 CSS 停止滚动并换行(无障碍硬要求)。 */
export default function NoticeBar({
tone = 'default',
scrollable = false,
closable = false,
text = '',
onClose,
children = null,
}) {
const content = text || children;
const cls =
'kole-m-noticebar' +
` kole-m-noticebar--${tone}` +
(scrollable ? ' kole-m-noticebar--scrollable' : '');
return (
<div className={cls} role="status">
<span className="kole-m-noticebar__icon" aria-hidden="true">
▸
</span>
<span className="kole-m-noticebar__text">
{scrollable ? (
/* 无缝循环:两段相同文案,第二段是循环占位(静止时被 CSS 隐藏) */
<span className="kole-m-noticebar__track">
<span className="kole-m-noticebar__seg">{content}</span>
<span className="kole-m-noticebar__seg kole-m-noticebar__seg--dup" aria-hidden="true">
{content}
</span>
</span>
) : (
content
)}
</span>
{closable ? (
<button
className="kole-m-noticebar__close"
type="button"
aria-label={`关闭通告:${typeof content === 'string' ? content : ''}`}
onClick={() => {
if (onClose) onClose();
}}
>
✕
</button>
) : null}
</div>
);
}
frameworks-mobile/NoticeBar.vue2.vue · Vue 2 · 60 行
<template>
<div class="kole-m-noticebar" :class="barClass" role="status">
<span class="kole-m-noticebar__icon" aria-hidden="true">▸</span>
<span class="kole-m-noticebar__text">
<span v-if="scrollable" class="kole-m-noticebar__track">
<span class="kole-m-noticebar__seg">{{ content }}</span>
<span class="kole-m-noticebar__seg kole-m-noticebar__seg--dup" aria-hidden="true">{{ content }}</span>
</span>
<template v-else>{{ content }}</template>
</span>
<button
v-if="closable"
class="kole-m-noticebar__close"
type="button"
:aria-label="closeLabel"
@click="onCloseClick"
>✕</button>
</div>
</template>
<script>
export default {
name: 'KoleMNoticeBar',
props: {
tone: { type: String, default: 'default' },
scrollable: { type: Boolean, default: false },
closable: { type: Boolean, default: false },
text: { type: String, default: '' }
},
computed: {
content: function () {
if (this.text) return this.text;
var nodes = (this.$slots && this.$slots.default) || [];
return nodes
.map(function (n) {
return n.children && typeof n.children === 'string' ? n.children : '';
})
.join('');
},
barClass: function () {
return [
'kole-m-noticebar--' + this.tone,
this.scrollable ? 'kole-m-noticebar--scrollable' : ''
].filter(Boolean);
},
/* 关闭按钮的读屏名称带上通告内容,否则「✕」无法区分是哪一条(规格 §16.6) */
closeLabel: function () {
return '关闭通告:' + this.content;
}
},
methods: {
onCloseClick: function () {
this.$emit('close');
}
}
};
</script>
<style src="./NoticeBar.css"></style>
frameworks-mobile/NoticeBar.vue3.vue · Vue 3 · 53 行
<template>
<div class="kole-m-noticebar" :class="barClass" role="status">
<span class="kole-m-noticebar__icon" aria-hidden="true">▸</span>
<span class="kole-m-noticebar__text">
<span v-if="scrollable" class="kole-m-noticebar__track">
<span class="kole-m-noticebar__seg">{{ content }}</span>
<span class="kole-m-noticebar__seg kole-m-noticebar__seg--dup" aria-hidden="true">{{ content }}</span>
</span>
<template v-else>{{ content }}</template>
</span>
<button
v-if="closable"
class="kole-m-noticebar__close"
type="button"
:aria-label="closeLabel"
@click="onCloseClick"
>✕</button>
</div>
</template>
<script setup>
import { computed, useSlots } from 'vue';
const props = defineProps({
tone: { type: String, default: 'default' },
scrollable: { type: Boolean, default: false },
closable: { type: Boolean, default: false },
text: { type: String, default: '' }
});
const emit = defineEmits(['close']);
const slots = useSlots();
const content = computed(() => {
if (props.text) return props.text;
const nodes = slots.default ? slots.default() : [];
return nodes.map((n) => (typeof n.children === 'string' ? n.children : '')).join('');
});
const barClass = computed(() => [
`kole-m-noticebar--${props.tone}`,
props.scrollable ? 'kole-m-noticebar--scrollable' : ''
].filter(Boolean));
/* 关闭按钮的读屏名称带上通告内容,否则「✕」无法区分是哪一条(规格 §16.6) */
const closeLabel = computed(() => '关闭通告:' + content.value);
function onCloseClick() {
emit('close');
}
</script>
<style src="./NoticeBar.css"></style>
frameworks-mobile/NoticeBar.uniapp.vue · uni-app(跨端:小程序 / App / H5) · 115 行
<template>
<view class="kole-m-noticebar" :class="barClass" :role="'status'">
<text class="kole-m-noticebar__icon">▸</text>
<view class="kole-m-noticebar__text">
<view v-if="scrollable" class="kole-m-noticebar__track">
<text class="kole-m-noticebar__seg">{{ content }}</text>
<text class="kole-m-noticebar__seg kole-m-noticebar__seg--dup">{{ content }}</text>
</view>
<text v-else>{{ content }}</text>
</view>
<view
v-if="closable"
class="kole-m-noticebar__close"
role="button"
:aria-label="closeLabel"
@tap="onCloseTap"
><text>✕</text></view>
</view>
</template>
<script setup>
/* uni-app 端 · 通知栏(移动端)— 规格 §16
跨端差异:用 view / text;关闭按钮用 view + role="button" + aria-label,点击用 @tap;
尺寸用 rpx(2rpx ≈ 1px);跑马灯的 reduced-motion 降级由样式里的媒体查询承担。 */
import { computed, useSlots } from 'vue';
const props = defineProps({
tone: { type: String, default: 'default' },
scrollable: { type: Boolean, default: false },
closable: { type: Boolean, default: false },
text: { type: String, default: '' }
});
const emit = defineEmits(['close']);
const slots = useSlots();
const content = computed(() => {
if (props.text) return props.text;
const nodes = slots.default ? slots.default() : [];
return nodes.map((n) => (typeof n.children === 'string' ? n.children : '')).join('');
});
const barClass = computed(() => [
`kole-m-noticebar--${props.tone}`,
props.scrollable ? 'kole-m-noticebar--scrollable' : ''
].filter(Boolean));
/* 关闭按钮的读屏名称带上通告内容,否则「✕」无法区分是哪一条(规格 §16.6) */
const closeLabel = computed(() => '关闭通告:' + content.value);
function onCloseTap() {
emit('close');
}
</script>
<style>
.kole-m-noticebar {
--kole-m-noticebar-icon-size: 32rpx;
--kole-m-touch-target: 88rpx;
--kole-m-font-size-label: 28rpx;
--kole-m-font-size-caption: 22rpx;
--kole-m-gutter: 32rpx;
display: flex;
align-items: center;
box-sizing: border-box;
min-height: var(--kole-m-touch-target);
padding: 16rpx var(--kole-m-gutter);
background-color: var(--kole-color-brand-bg);
color: var(--kole-color-brand);
font-size: var(--kole-m-font-size-label);
overflow: hidden;
}
.kole-m-noticebar--default { background-color: var(--kole-color-brand-bg); color: var(--kole-color-brand); }
.kole-m-noticebar--success { background-color: var(--kole-color-tag-green-bg); color: var(--kole-color-success); }
.kole-m-noticebar--warning { background-color: var(--kole-color-table-header-bg); color: var(--kole-color-warning); }
.kole-m-noticebar--danger { background-color: var(--kole-color-table-header-bg); color: var(--kole-color-error); }
.kole-m-noticebar__icon {
flex-shrink: 0;
margin-right: 16rpx;
font-size: var(--kole-m-noticebar-icon-size);
}
.kole-m-noticebar__text {
flex: 1;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.kole-m-noticebar--scrollable .kole-m-noticebar__track {
display: flex;
white-space: nowrap;
}
.kole-m-noticebar__seg {
flex-shrink: 0;
padding-right: 96rpx;
}
.kole-m-noticebar__close {
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
width: 48rpx;
height: 48rpx;
margin-right: -16rpx;
border-radius: 50%;
color: inherit;
font-size: var(--kole-m-font-size-caption);
}
</style>
测试与回归
断言在真实的 375×640 设备帧里跑(引擎与 PC 侧共用 tests/_runtime.js,触控行为动词来自移动端 tests/mobile/_behaviors.js)。
断言 15 条 · 全部通过 报告 2026-09-20 16:50:33
node site/dev-server.js &
REG_BASE=http://127.0.0.1:3311 node tools/run-mobile-regression.mjs # 全量 5 个组件
npm run verify:mobile-docs # 本页内容完整性 + API 与源码一致性
设计契约
components/mobile-noticebar.json(点击展开原始 JSON)
{
"schemaVersion": 1,
"sourceKind": "authored-spec",
"provenance": "authored-in-repo",
"specFile": "spec/移动端规格.md",
"confidence": "high",
"specSection": "16 · 通知栏 NoticeBar",
"slug": "mobile-noticebar",
"name": "通知栏 NoticeBar",
"semanticTypeCandidates": [
"notice",
"banner",
"marquee"
],
"variantDimensions": [
{
"name": "tone",
"values": [
"default",
"success",
"warning",
"danger"
]
},
{
"name": "scrollable",
"values": [
"false",
"true"
]
},
{
"name": "closable",
"values": [
"false",
"true"
]
}
],
"representativeVariants": [
{
"tone": "default",
"scrollable": "false",
"closable": "false",
"label": "基础通告"
},
{
"tone": "warning",
"scrollable": "false",
"closable": "true",
"label": "可关闭提醒"
},
{
"tone": "default",
"scrollable": "true",
"closable": "false",
"label": "跑马灯长通告"
},
{
"tone": "success",
"scrollable": "false",
"closable": "false",
"label": "成功语气"
}
],
"anatomy": {
"noticebar": "根容器",
"noticebar__icon": "左侧喇叭图标",
"noticebar__text": "通告文字(可滚动)",
"noticebar__close": "可选关闭按钮"
},
"structurePatterns": {
"tone": "default / success / warning / danger",
"scrollable": "false / true(文字超宽时是否跑马灯)",
"closable": "false / true"
},
"usageHints": [
"在页面顶部或内容区之间横向滚动展示一条通告(如「系统维护通知」)",
"关闭按钮热区不小于 24×24(用负外边距扩展)",
"跑马灯在 prefers-reduced-motion: reduce 下停止滚动并改为换行显示(无障碍硬要求)",
"关闭动作只触发一次事件,是否移除由宿主决定",
"容器 role=\"status\"(读屏会朗读一次通告)",
"跑马灯不得用 aria-live(滚动内容反复朗读会干扰)"
],
"doNotInvent": [
"多条通告的排队 / 轮播",
"滚动速度的可配置项"
],
"unknowns": [
"通告文字的最大长度",
"是否支持富文本"
],
"interaction": [
"关闭按钮热区不小于 24×24(用负外边距扩展)",
"跑马灯在 prefers-reduced-motion: reduce 下停止滚动并改为换行显示(无障碍硬要求)",
"关闭动作只触发一次事件,是否移除由宿主决定"
],
"accessibility": [
"容器 role=\"status\"(读屏会朗读一次通告)",
"关闭按钮为原生 button 并带 aria-label",
"跑马灯不得用 aria-live(滚动内容反复朗读会干扰)"
],
"api": {
"source": "implementation",
"note": "props / events / slots 为 6 端实现的公共接口(说明文字取自规格对应小节)。字段名与各端源码逐名核对:node tools/verify-mobile-docs.mjs",
"requiredNote": "「必传」按严格定义:实现里**没有默认值**时才为 Y(本门禁逐条核对 props 与各端源码的默认值,防止契约与实现脱节)。",
"props": [
{
"name": "tone",
"type": "'default' | 'success' | 'warning' | 'danger'",
"default": "'default'",
"desc": "变体 tone:四种语气(浅底 + 同族深字)(规格 §16.3)",
"required": false
},
{
"name": "scrollable",
"type": "boolean",
"default": "false",
"desc": "变体 scrollable:文字超宽时是否跑马灯(规格 §16.3)",
"required": false
},
{
"name": "closable",
"type": "boolean",
"default": "false",
"desc": "变体 closable:是否显示关闭按钮(规格 §16.3)",
"required": false
},
{
"name": "text",
"type": "string",
"default": "''",
"desc": "通告文字(规格 §16.2 text)",
"required": false
}
],
"events": [
{
"name": "close",
"params": "—",
"desc": "点击关闭按钮时触发;是否移除这条通告由宿主决定(规格 §16.5)"
}
],
"slots": [
{
"name": "default",
"desc": "通告内容(与 text 二选一;text 优先)"
}
]
},
"variantClasses": {
"tone": {
"default": [
".kole-m-noticebar--default"
],
"success": [
".kole-m-noticebar--success"
],
"warning": [
".kole-m-noticebar--warning"
],
"danger": [
".kole-m-noticebar--danger"
]
},
"scrollable": {
"false": [],
"true": [
".kole-m-noticebar--scrollable"
]
},
"closable": {
"false": [],
"true": [
".kole-m-noticebar__close"
]
}
},
"demos": [
{
"id": "basic",
"group": "01 组件类型",
"title": "基础通告",
"desc": "品牌浅底 + 同族深字;容器带 role=status,读屏会朗读一次。",
"variant": "tone=default"
},
{
"id": "closable",
"group": "01 组件类型",
"title": "可关闭",
"desc": "关闭按钮是原生 button、24×24 热区,aria-label 带上通告内容以便区分。",
"variant": "closable=true"
},
{
"id": "scrollable",
"group": "01 组件类型",
"title": "跑马灯",
"desc": "文案超宽时横向循环滚动;系统开启「减少动态效果」时停止滚动并改为换行。",
"variant": "scrollable=true"
},
{
"id": "tone",
"group": "02 组件状态",
"title": "语义语气",
"desc": "成功与失败语气用同族浅底,颜色之外还有图标区分,不只靠色相。",
"variant": "tone=success|danger"
}
],
"related": [
{
"slug": "mobile-toast",
"why": "一次性结果反馈用轻提示;需要常驻在页面里的通告才用通知栏"
},
{
"slug": "mobile-tag",
"why": "很短的状态词用标签;整句通告用通知栏"
},
{
"slug": "mobile-divider",
"why": "通知栏与内容区之间靠浅底与留白分隔,不必再插分割线"
}
]
}