标签Tag
用简短的文字标注状态、分类或属性;可关闭的标签用于已选项
数据展示 规格 10 · 标签 Tag 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-tag.css">
<!-- ③ 结构照抄下方任一演示块(类名与 6 端实现一致) -->
演示
每个演示都是真实渲染:预览帧加载 frameworks-mobile/Tag.html?demo=<id>(只显示该演示块),代码是该演示块在演示页里的原文,可复制。全部演示同屏可看 演示页 ↗。
01 组件类型
默认语气的标签,用于普通分类标注;纯展示标签不加交互角色。
查看代码(演示页原文 · 11 行)
<section class="demo-block" data-demo="basic">
<p class="demo-label">基础用法(tone=default:默认语气,用于普通分类标注)</p>
<div class="demo-box">
<span class="kole-m-tag kole-m-tag--default" data-assert="tag-basic">
<span class="kole-m-tag__label">全部订单</span>
</span>
<span class="kole-m-tag kole-m-tag--default">
<span class="kole-m-tag__label">待发货</span>
</span>
</div>
</section>primary / success / warning / danger 的底色与字色同族,浅底深字在亮暗两态都达标。
查看代码(演示页原文 · 17 行)
<section class="demo-block" data-demo="tone">
<p class="demo-label">五种语气(tone=primary / success / warning / danger:底色与字色同族)</p>
<div class="demo-box">
<span class="kole-m-tag kole-m-tag--primary" data-assert="tag-tone">
<span class="kole-m-tag__label">进行中</span>
</span>
<span class="kole-m-tag kole-m-tag--success">
<span class="kole-m-tag__label">已完成</span>
</span>
<span class="kole-m-tag kole-m-tag--warning">
<span class="kole-m-tag__label">待付款</span>
</span>
<span class="kole-m-tag kole-m-tag--danger">
<span class="kole-m-tag__label">已取消</span>
</span>
</div>
</section>关闭按钮是原生 button(热区 24×24)并带 aria-label,读屏能区分是哪一枚标签。
查看代码(演示页原文 · 15 行)
<section class="demo-block" data-demo="closable">
<p class="demo-label">可关闭(closable=true:关闭按钮是原生 button,热区 24×24,点后打标记)</p>
<div class="demo-box">
<span class="kole-m-tag kole-m-tag--primary" id="tag-closable" data-assert="tag-closable">
<span class="kole-m-tag__label">已勾选</span>
<button class="kole-m-tag__close" type="button" aria-label="移除标签:已勾选"
data-behavior="click-sets-attr:#tag-closable|data-closed|true">✕</button>
</span>
<span class="kole-m-tag kole-m-tag--default" id="tag-closable-2">
<span class="kole-m-tag__label">已发货</span>
<button class="kole-m-tag__close" type="button" aria-label="移除标签:已发货"
data-behavior="click-sets-attr:#tag-closable-2|data-closed|true">✕</button>
</span>
</div>
</section>02 组件状态
size=small 更矮更紧,适合表格行内或列表右侧这类空间受限的位置。
查看代码(演示页原文 · 14 行)
<section class="demo-block" data-demo="small">
<p class="demo-label">小尺寸(size=small:更矮更紧,用于表格行内或列表右侧)</p>
<div class="demo-box">
<span class="kole-m-tag kole-m-tag--small kole-m-tag--success" data-assert="tag-small">
<span class="kole-m-tag__label">正常</span>
</span>
<span class="kole-m-tag kole-m-tag--small kole-m-tag--warning">
<span class="kole-m-tag__label">超时</span>
</span>
<span class="kole-m-tag kole-m-tag--small kole-m-tag--default">
<span class="kole-m-tag__label">草稿</span>
</span>
</div>
</section>置灰且关闭按钮不响应,用于无权限项;禁用态文字用 disabled 色(WCAG 对禁用控件豁免)。
查看代码(演示页原文 · 12 行)
<section class="demo-block" data-demo="disabled">
<p class="demo-label">禁用(状态 disabled:置灰且关闭按钮不响应,多用于无权限项)</p>
<div class="demo-box">
<span class="kole-m-tag kole-m-tag--default is-disabled" data-assert="tag-disabled" aria-disabled="true">
<span class="kole-m-tag__label">不可编辑</span>
<button class="kole-m-tag__close" type="button" aria-label="移除标签:不可编辑" disabled>✕</button>
</span>
<span class="kole-m-tag kole-m-tag--primary is-disabled" aria-disabled="true">
<span class="kole-m-tag__label">已归档</span>
</span>
</div>
</section>API
props / events / slots 为 6 端实现的公共接口(说明文字取自规格对应小节)。字段名与各端源码逐名核对:node tools/verify-mobile-docs.mjs
Props
| 名称 | 类型 | 默认值 | 说明 | 必传 |
|---|---|---|---|---|
tone | 'default' | 'primary' | 'success' | 'warning' | 'danger' | 'default' | 变体 tone:五种语气,底色与字色同族(规格 §10.3) | N |
size | 'default' | 'small' | 'default' | 变体 size:small 更矮更紧,用于表格行内或列表右侧(规格 §10.3) | N |
closable | boolean | false | 变体 closable:显示关闭按钮(规格 §10.3) | N |
disabled | boolean | false | 状态 disabled:置灰且不可关闭(规格 §10.4) | N |
「必传」按严格定义:实现里**没有默认值**时才为 Y(本门禁逐条核对 props 与各端源码的默认值,防止契约与实现脱节)。
事件
| 名称 | 参数 | 说明 |
|---|---|---|
close | — | 点击关闭按钮时触发;是否真的移除标签由宿主决定(规格 §10.5) |
插槽
| 名称 | 说明 |
|---|---|
default | 标签文字(规格 §10.2 label) |
CSS 变量
组件级变量(在组件样式表里定义)。业务侧可在自己的作用域内覆盖,不必改组件源码。
| 名称 | 默认值 | 说明 |
|---|---|---|
--kole-m-tag-height | 24px | 标签高度(小尺寸 20px) |
--kole-m-tag-hit-slack | 6px | 关闭按钮向外的额外热区 |
--kole-m-tag-height | 20px | 组件内部默认值,可在业务侧覆盖 |
何时使用
- 用简短的文字标注状态、分类或属性;可关闭的标签用于已选项
- 关闭按钮热区不小于 24×24(小尺寸标签内用负外边距扩展热区)
- 关闭动作只触发一次事件,是否真的移除由宿主决定
- 关闭按钮为原生 button 并带 aria-label(如「移除标签:已发货」)
- 纯展示标签不加交互角色
交互与触控
- 关闭按钮热区不小于 24×24(小尺寸标签内用负外边距扩展热区)
- 关闭动作只触发一次事件,是否真的移除由宿主决定
无障碍
- 关闭按钮为原生 button 并带 aria-label(如「移除标签:已发货」)
- 纯展示标签不加交互角色
相似组件
从「该用哪一个」的角度区分;PC 端的对应实现见 PC 文档站。
| 组件 | 何时用它而不是本组件 |
|---|---|
| 徽标Badge | 徽标只承载计数与红点,标签承载文字语义;需要计数时用徽标而不是把数字写进标签 |
| 单元格Cell | 列表行右侧的状态标记用标签;整行可点时用单元格的 value,不必再叠标签 |
| 分割线Divider | 同一组标签之间的分隔靠间距,不要用分割线把标签切开 |
规格未定 / 禁止发明
| 类别 | 条目 |
|---|---|
| 禁止发明 | 标签的动态增删动画 |
| 禁止发明 | 超长标签的换行规则 |
| 规格未定 | 同一行最多放几个标签 |
| 规格未定 | 关闭后是否保留占位 |
结构(anatomy)
| 字段 | 说明 |
|---|---|
tag | 根元素,圆角胶囊 |
label | 标签文字 |
close | 可选关闭按钮 |
变体维度与类名映射
类名映射由构建脚本从契约 variantClasses 生成,并被 verify:mobile-docs 逐条对照组件 CSS 校验(类/变量必须真实存在)。
| 维度 | 取值 | 对应类名 / 变量 |
|---|---|---|
tone | default / primary / success / warning / danger | default .kole-m-tag--default primary .kole-m-tag--primary success .kole-m-tag--success warning .kole-m-tag--warning danger .kole-m-tag--danger |
size | default / small | default (由数据驱动,无专属类) small .kole-m-tag--small |
closable | false / true | false (由数据驱动,无专属类) true .kole-m-tag__close |
代表变体
| 变体 | 标签 |
|---|---|
tone=default · size=default · closable=false | 基础标签 |
tone=success · size=default · closable=false | 成功语气 |
tone=primary · size=default · closable=true | 可关闭标签 |
tone=warning · size=small · closable=false | 小尺寸标签 |
用到的令牌
构建时从本组件样式表扫描得出。蓝色为移动端自有令牌,绿色为继承的 PC 令牌(改一处两端生效)。
6 端源码
同一组件的六份实现(生产环境的类名与结构一致,差异只在技术栈写法与单位)。点开查看,右侧可复制。
frameworks-mobile/Tag.css · 纯样式(CSS) · 76 行
/* Kole UI Mobile · Tag 样式 — 对齐移动端规格 §10
标签:圆角胶囊,浅底 + 同族深色文字(对比度亮色 5.35:1 起、暗色 ≥4.5:1);
closable 的关闭按钮是原生 button,热区 24×24(不足处用负外边距扩展)。 */
.kole-m-tag {
--kole-m-tag-height: 24px; /* 标签高度(小尺寸 20px) */
--kole-m-tag-hit-slack: 6px; /* 关闭按钮向外的额外热区 */
box-sizing: border-box;
display: inline-flex;
align-items: center;
gap: var(--kole-space-4);
max-width: 100%;
height: var(--kole-m-tag-height);
padding: 0 var(--kole-space-8);
border-radius: calc(var(--kole-m-tag-height) / 2);
background: var(--kole-color-brand-bg);
color: var(--kole-color-brand);
font-family: var(--kole-font-family);
font-size: var(--kole-m-font-size-caption);
line-height: 1;
white-space: nowrap;
}
.kole-m-tag__label {
overflow: hidden;
text-overflow: ellipsis;
}
/* 变体 size=small:更矮更紧,用于表格行内或列表右侧 */
.kole-m-tag--small {
--kole-m-tag-height: 20px;
padding: 0 var(--kole-space-4);
}
/* 变体 tone:五种语气,底色与字色同族(浅底 + 深字,对比度已实测) */
.kole-m-tag--primary { background: var(--kole-color-brand-bg); color: var(--kole-color-brand); }
.kole-m-tag--success { background: var(--kole-color-tag-green-bg); color: var(--kole-color-success); }
.kole-m-tag--warning { background: var(--kole-color-table-header-bg); color: var(--kole-color-warning); }
.kole-m-tag--danger { background: var(--kole-color-table-header-bg); color: var(--kole-color-error); }
.kole-m-tag--default { background: var(--kole-color-disabled-bg); color: var(--kole-color-text-secondary); }
/* 状态 disabled:置灰且不可关闭 */
.kole-m-tag.is-disabled {
background: var(--kole-color-disabled-bg);
color: var(--kole-color-text-disabled);
pointer-events: none;
}
/* 关闭按钮:原生 button,24×24 热区(视觉尺寸小,靠 padding 撑开) */
.kole-m-tag__close {
display: inline-flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
width: 24px;
height: 24px;
margin-inline: calc(-1 * var(--kole-m-tag-hit-slack)) calc(-1 * var(--kole-space-4));
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-tag__close:focus-visible {
outline: 2px solid var(--kole-color-focus-ring);
outline-offset: -2px;
}
.kole-m-tag__close:active { background: var(--kole-color-table-header-bg); }
frameworks-mobile/Tag.html · H5 原生(无框架) · 129 行
<!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 · Tag(H5)</title>
<link rel="stylesheet" href="../.design_library/kole-ui-mobile/colors_and_type.css">
<link rel="stylesheet" href="Tag.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-box { display: flex; flex-wrap: wrap; align-items: center; gap: var(--kole-space-8);
padding: var(--kole-space-16) var(--kole-m-gutter); background: var(--kole-color-card-bg);
border-block: 1px solid var(--kole-color-border); }
.demo-block[hidden] { display: none; }
</style>
</head>
<body>
<div class="demo">
<section class="demo-block" data-demo="basic">
<p class="demo-label">基础用法(tone=default:默认语气,用于普通分类标注)</p>
<div class="demo-box">
<span class="kole-m-tag kole-m-tag--default" data-assert="tag-basic">
<span class="kole-m-tag__label">全部订单</span>
</span>
<span class="kole-m-tag kole-m-tag--default">
<span class="kole-m-tag__label">待发货</span>
</span>
</div>
</section>
<section class="demo-block" data-demo="tone">
<p class="demo-label">五种语气(tone=primary / success / warning / danger:底色与字色同族)</p>
<div class="demo-box">
<span class="kole-m-tag kole-m-tag--primary" data-assert="tag-tone">
<span class="kole-m-tag__label">进行中</span>
</span>
<span class="kole-m-tag kole-m-tag--success">
<span class="kole-m-tag__label">已完成</span>
</span>
<span class="kole-m-tag kole-m-tag--warning">
<span class="kole-m-tag__label">待付款</span>
</span>
<span class="kole-m-tag kole-m-tag--danger">
<span class="kole-m-tag__label">已取消</span>
</span>
</div>
</section>
<section class="demo-block" data-demo="closable">
<p class="demo-label">可关闭(closable=true:关闭按钮是原生 button,热区 24×24,点后打标记)</p>
<div class="demo-box">
<span class="kole-m-tag kole-m-tag--primary" id="tag-closable" data-assert="tag-closable">
<span class="kole-m-tag__label">已勾选</span>
<button class="kole-m-tag__close" type="button" aria-label="移除标签:已勾选"
data-behavior="click-sets-attr:#tag-closable|data-closed|true">✕</button>
</span>
<span class="kole-m-tag kole-m-tag--default" id="tag-closable-2">
<span class="kole-m-tag__label">已发货</span>
<button class="kole-m-tag__close" type="button" aria-label="移除标签:已发货"
data-behavior="click-sets-attr:#tag-closable-2|data-closed|true">✕</button>
</span>
</div>
</section>
<section class="demo-block" data-demo="small">
<p class="demo-label">小尺寸(size=small:更矮更紧,用于表格行内或列表右侧)</p>
<div class="demo-box">
<span class="kole-m-tag kole-m-tag--small kole-m-tag--success" data-assert="tag-small">
<span class="kole-m-tag__label">正常</span>
</span>
<span class="kole-m-tag kole-m-tag--small kole-m-tag--warning">
<span class="kole-m-tag__label">超时</span>
</span>
<span class="kole-m-tag kole-m-tag--small kole-m-tag--default">
<span class="kole-m-tag__label">草稿</span>
</span>
</div>
</section>
<section class="demo-block" data-demo="disabled">
<p class="demo-label">禁用(状态 disabled:置灰且关闭按钮不响应,多用于无权限项)</p>
<div class="demo-box">
<span class="kole-m-tag kole-m-tag--default is-disabled" data-assert="tag-disabled" aria-disabled="true">
<span class="kole-m-tag__label">不可编辑</span>
<button class="kole-m-tag__close" type="button" aria-label="移除标签:不可编辑" disabled>✕</button>
</span>
<span class="kole-m-tag kole-m-tag--primary is-disabled" aria-disabled="true">
<span class="kole-m-tag__label">已归档</span>
</span>
</div>
</section>
</div>
<script>
/* 演示页交互:关闭按钮只打标记(真实业务里是否移除该项由宿主决定)。 */
(function () {
document.querySelectorAll('.kole-m-tag__close').forEach(function (btn) {
btn.addEventListener('click', function () {
var tag = btn.closest('.kole-m-tag');
if (tag) tag.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/Tag.jsx · React · 43 行
import React from 'react';
import './Tag.css';
/* 标签(移动端)— 规格 §10;closable 的关闭按钮是原生 button(带 aria-label),
关闭动作只回调,是否真的移除标签由宿主决定。 */
export default function Tag({
tone = 'default',
size = 'default',
closable = false,
disabled = false,
onClose,
children = null,
}) {
const cls =
'kole-m-tag' +
` kole-m-tag--${tone}` +
(size === 'small' ? ' kole-m-tag--small' : '') +
(disabled ? ' is-disabled' : '');
/* 关闭按钮的读屏名称要带上标签文字,否则一串「✕」无法区分(规格 §10.6) */
const label = typeof children === 'string' ? children : '';
return (
<span className={cls} aria-disabled={disabled ? 'true' : undefined}>
<span className="kole-m-tag__label">{children}</span>
{closable ? (
<button
className="kole-m-tag__close"
type="button"
disabled={disabled}
aria-label={`移除标签:${label}`}
onClick={() => {
if (disabled) return;
if (onClose) onClose();
}}
>
✕
</button>
) : null}
</span>
);
}
frameworks-mobile/Tag.vue2.vue · Vue 2 · 53 行
<template>
<span class="kole-m-tag" :class="tagClass" :aria-disabled="disabled ? 'true' : null">
<span class="kole-m-tag__label"><slot></slot></span>
<button
v-if="closable"
class="kole-m-tag__close"
type="button"
:disabled="disabled"
:aria-label="closeLabel"
@click="onCloseClick"
>✕</button>
</span>
</template>
<script>
export default {
name: 'KoleMTag',
props: {
tone: { type: String, default: 'default' },
size: { type: String, default: 'default' },
closable: { type: Boolean, default: false },
disabled: { type: Boolean, default: false }
},
computed: {
tagClass: function () {
return [
'kole-m-tag--' + this.tone,
this.size === 'small' ? 'kole-m-tag--small' : '',
this.disabled ? 'is-disabled' : ''
].filter(Boolean);
},
/* 关闭按钮的读屏名称带上标签文字,否则一串「✕」无法区分(规格 §10.6) */
closeLabel: function () {
var nodes = (this.$slots && this.$slots.default) || [];
var text = nodes
.map(function (n) {
return n.children && typeof n.children === 'string' ? n.children : '';
})
.join('');
return '移除标签:' + text;
}
},
methods: {
onCloseClick: function () {
if (this.disabled) return;
this.$emit('close');
}
}
};
</script>
<style src="./Tag.css"></style>
frameworks-mobile/Tag.vue3.vue · Vue 3 · 47 行
<template>
<span class="kole-m-tag" :class="tagClass" :aria-disabled="disabled ? 'true' : null">
<span class="kole-m-tag__label"><slot></slot></span>
<button
v-if="closable"
class="kole-m-tag__close"
type="button"
:disabled="disabled"
:aria-label="closeLabel"
@click="onCloseClick"
>✕</button>
</span>
</template>
<script setup>
import { computed, useSlots } from 'vue';
const props = defineProps({
tone: { type: String, default: 'default' },
size: { type: String, default: 'default' },
closable: { type: Boolean, default: false },
disabled: { type: Boolean, default: false }
});
const emit = defineEmits(['close']);
const slots = useSlots();
const tagClass = computed(() => [
`kole-m-tag--${props.tone}`,
props.size === 'small' ? 'kole-m-tag--small' : '',
props.disabled ? 'is-disabled' : ''
].filter(Boolean));
/* 关闭按钮的读屏名称带上标签文字,否则一串「✕」无法区分(规格 §10.6) */
const closeLabel = computed(() => {
const nodes = slots.default ? slots.default() : [];
const text = nodes.map((n) => (typeof n.children === 'string' ? n.children : '')).join('');
return '移除标签:' + text;
});
function onCloseClick() {
if (props.disabled) return;
emit('close');
}
</script>
<style src="./Tag.css"></style>
frameworks-mobile/Tag.uniapp.vue · uni-app(跨端:小程序 / App / H5) · 103 行
<template>
<view class="kole-m-tag" :class="tagClass" :aria-disabled="disabled ? 'true' : 'false'">
<text class="kole-m-tag__label"><slot></slot></text>
<view
v-if="closable"
class="kole-m-tag__close"
:role="disabled ? '' : 'button'"
:aria-label="closeLabel"
@tap="onCloseTap"
><text>✕</text></view>
</view>
</template>
<script setup>
/* uni-app 端 · 标签(移动端)— 规格 §10
跨端差异:用 view / text;关闭按钮用 view + role="button" + aria-label(小程序无 <button>
的行内语义,role 在 H5 产物里生效),点击用 @tap;尺寸用 rpx(48rpx = 24px @375pt)。 */
import { computed, useSlots } from 'vue';
const props = defineProps({
tone: { type: String, default: 'default' },
size: { type: String, default: 'default' },
closable: { type: Boolean, default: false },
disabled: { type: Boolean, default: false }
});
const emit = defineEmits(['close']);
const slots = useSlots();
const tagClass = computed(() => [
`kole-m-tag--${props.tone}`,
props.size === 'small' ? 'kole-m-tag--small' : '',
props.disabled ? 'is-disabled' : ''
].filter(Boolean));
/* 关闭按钮的读屏名称带上标签文字,否则一串「✕」无法区分(规格 §10.6) */
const closeLabel = computed(() => {
const nodes = slots.default ? slots.default() : [];
const text = nodes.map((n) => (typeof n.children === 'string' ? n.children : '')).join('');
return '移除标签:' + text;
});
function onCloseTap() {
if (props.disabled) return;
emit('close');
}
</script>
<style>
.kole-m-tag {
--kole-m-tag-height: 48rpx;
--kole-m-tag-hit-slack: 12rpx;
--kole-m-font-size-caption: 22rpx;
box-sizing: border-box;
display: inline-flex;
align-items: center;
max-width: 100%;
height: var(--kole-m-tag-height);
padding: 0 16rpx;
border-radius: 24rpx;
background-color: var(--kole-color-brand-bg);
color: var(--kole-color-brand);
font-size: var(--kole-m-font-size-caption);
line-height: 1;
}
.kole-m-tag__label {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.kole-m-tag--small {
--kole-m-tag-height: 40rpx;
padding: 0 8rpx;
}
.kole-m-tag--primary { background-color: var(--kole-color-brand-bg); color: var(--kole-color-brand); }
.kole-m-tag--success { background-color: var(--kole-color-tag-green-bg); color: var(--kole-color-success); }
.kole-m-tag--warning { background-color: var(--kole-color-table-header-bg); color: var(--kole-color-warning); }
.kole-m-tag--danger { background-color: var(--kole-color-table-header-bg); color: var(--kole-color-error); }
.kole-m-tag--default { background-color: var(--kole-color-disabled-bg); color: var(--kole-color-text-secondary); }
.kole-m-tag.is-disabled {
background-color: var(--kole-color-disabled-bg);
color: var(--kole-color-text-disabled);
}
.kole-m-tag__close {
box-sizing: border-box;
display: inline-flex;
align-items: center;
justify-content: center;
width: 48rpx;
height: 48rpx;
margin-right: -8rpx;
margin-left: -4rpx;
border-radius: 50%;
color: inherit;
font-size: var(--kole-m-font-size-caption);
line-height: 1;
}
</style>
测试与回归
断言在真实的 375×640 设备帧里跑(引擎与 PC 侧共用 tests/_runtime.js,触控行为动词来自移动端 tests/mobile/_behaviors.js)。
断言 17 条 · 全部通过 报告 2026-09-22 23:01:05
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-tag.json(点击展开原始 JSON)
{
"schemaVersion": 1,
"sourceKind": "authored-spec",
"provenance": "authored-in-repo",
"specFile": "spec/移动端规格.md",
"confidence": "high",
"specSection": "10 · 标签 Tag",
"slug": "mobile-tag",
"name": "标签 Tag",
"semanticTypeCandidates": [
"tag",
"chip",
"label"
],
"variantDimensions": [
{
"name": "tone",
"values": [
"default",
"primary",
"success",
"warning",
"danger"
]
},
{
"name": "size",
"values": [
"default",
"small"
]
},
{
"name": "closable",
"values": [
"false",
"true"
]
}
],
"representativeVariants": [
{
"tone": "default",
"size": "default",
"closable": "false",
"label": "基础标签"
},
{
"tone": "success",
"size": "default",
"closable": "false",
"label": "成功语气"
},
{
"tone": "primary",
"size": "default",
"closable": "true",
"label": "可关闭标签"
},
{
"tone": "warning",
"size": "small",
"closable": "false",
"label": "小尺寸标签"
}
],
"anatomy": {
"tag": "根元素,圆角胶囊",
"label": "标签文字",
"close": "可选关闭按钮"
},
"structurePatterns": {
"tone": "default / primary / success / warning / danger",
"size": "default / small",
"closable": "false / true"
},
"usageHints": [
"用简短的文字标注状态、分类或属性;可关闭的标签用于已选项",
"关闭按钮热区不小于 24×24(小尺寸标签内用负外边距扩展热区)",
"关闭动作只触发一次事件,是否真的移除由宿主决定",
"关闭按钮为原生 button 并带 aria-label(如「移除标签:已发货」)",
"纯展示标签不加交互角色"
],
"doNotInvent": [
"标签的动态增删动画",
"超长标签的换行规则"
],
"unknowns": [
"同一行最多放几个标签",
"关闭后是否保留占位"
],
"interaction": [
"关闭按钮热区不小于 24×24(小尺寸标签内用负外边距扩展热区)",
"关闭动作只触发一次事件,是否真的移除由宿主决定"
],
"accessibility": [
"关闭按钮为原生 button 并带 aria-label(如「移除标签:已发货」)",
"纯展示标签不加交互角色"
],
"api": {
"source": "implementation",
"note": "props / events / slots 为 6 端实现的公共接口(说明文字取自规格对应小节)。字段名与各端源码逐名核对:node tools/verify-mobile-docs.mjs",
"requiredNote": "「必传」按严格定义:实现里**没有默认值**时才为 Y(本门禁逐条核对 props 与各端源码的默认值,防止契约与实现脱节)。",
"props": [
{
"name": "tone",
"type": "'default' | 'primary' | 'success' | 'warning' | 'danger'",
"default": "'default'",
"desc": "变体 tone:五种语气,底色与字色同族(规格 §10.3)",
"required": false
},
{
"name": "size",
"type": "'default' | 'small'",
"default": "'default'",
"desc": "变体 size:small 更矮更紧,用于表格行内或列表右侧(规格 §10.3)",
"required": false
},
{
"name": "closable",
"type": "boolean",
"default": "false",
"desc": "变体 closable:显示关闭按钮(规格 §10.3)",
"required": false
},
{
"name": "disabled",
"type": "boolean",
"default": "false",
"desc": "状态 disabled:置灰且不可关闭(规格 §10.4)",
"required": false
}
],
"events": [
{
"name": "close",
"params": "—",
"desc": "点击关闭按钮时触发;是否真的移除标签由宿主决定(规格 §10.5)"
}
],
"slots": [
{
"name": "default",
"desc": "标签文字(规格 §10.2 label)"
}
]
},
"variantClasses": {
"tone": {
"default": [
".kole-m-tag--default"
],
"primary": [
".kole-m-tag--primary"
],
"success": [
".kole-m-tag--success"
],
"warning": [
".kole-m-tag--warning"
],
"danger": [
".kole-m-tag--danger"
]
},
"size": {
"default": [],
"small": [
".kole-m-tag--small"
]
},
"closable": {
"false": [],
"true": [
".kole-m-tag__close"
]
}
},
"demos": [
{
"id": "basic",
"group": "01 组件类型",
"title": "基础用法",
"desc": "默认语气的标签,用于普通分类标注;纯展示标签不加交互角色。",
"variant": "tone=default"
},
{
"id": "tone",
"group": "01 组件类型",
"title": "五种语气",
"desc": "primary / success / warning / danger 的底色与字色同族,浅底深字在亮暗两态都达标。",
"variant": "tone=primary|success|warning|danger"
},
{
"id": "closable",
"group": "01 组件类型",
"title": "可关闭",
"desc": "关闭按钮是原生 button(热区 24×24)并带 aria-label,读屏能区分是哪一枚标签。",
"variant": "closable=true"
},
{
"id": "small",
"group": "02 组件状态",
"title": "小尺寸",
"desc": "size=small 更矮更紧,适合表格行内或列表右侧这类空间受限的位置。",
"variant": "size=small"
},
{
"id": "disabled",
"group": "02 组件状态",
"title": "禁用",
"desc": "置灰且关闭按钮不响应,用于无权限项;禁用态文字用 disabled 色(WCAG 对禁用控件豁免)。",
"variant": "状态 disabled"
}
],
"related": [
{
"slug": "mobile-badge",
"why": "徽标只承载计数与红点,标签承载文字语义;需要计数时用徽标而不是把数字写进标签"
},
{
"slug": "cell",
"why": "列表行右侧的状态标记用标签;整行可点时用单元格的 value,不必再叠标签"
},
{
"slug": "mobile-divider",
"why": "同一组标签之间的分隔靠间距,不要用分割线把标签切开"
}
]
}