最稳方案是用 checkbox-group + checkbox,v-model 绑定数组,每个 checkbox 的 value 必须为字符串或数字;横向滚动需配合 scroll-x、inline-block 和 white-space: nowrap;自定义切换需手动维护数组并注意初始化与同步;大数据量时应分页懒加载。

uni-app 里用 checkbox-group 实现标签选择器最稳
直接用 checkbox-group + checkbox 是 uni-app 官方推荐、兼容性最好、逻辑最清晰的方式。别自己封装 view 模拟勾选状态,容易漏掉焦点、键盘操作、无障碍支持,而且 checkbox 在各端(微信小程序、App、H5)的原生表现更一致。
常见错误是把 checkbox 的 value 写成对象或数组,导致绑定失败;或者没给每个 checkbox 设置唯一 value,结果多选时值互相覆盖。
-
checkbox-group的v-model绑定一个数组(如selectedTags),用于存已选标签的value - 每个
checkbox的value必须是字符串或数字(不能是对象),对应标签唯一标识(比如tag.id或tag.name) - 显示文案用
slot或普通文本节点,不要塞进value里
<checkbox-group v-model="selectedTags"><label v-for="tag in tagList" :key="tag.id" class="tag-item">
<checkbox :value="String(tag.id)"></checkbox><span>{{ tag.name }}</span>
</label>
</checkbox-group>
热门标签滚动区域适配 H5 和小程序差异
热门标签常需横向滚动,但 scroll-view 在 H5 和小程序中行为不一致:H5 下默认不触发滚动条,小程序需显式设 scroll-x 且要加 white-space: nowrap 才能横滚;App 端还可能因父容器宽度计算不准导致截断。
关键不是加多少样式,而是控制「容器宽度」和「子项内联布局」的配合。
- 外层
scroll-view设scroll-x="true",并加class="tag-scroll" - 内部
view(包裹所有标签)必须设display: inline-block或white-space: nowrap - 每个标签项(
label或view)设display: inline-block,且避免用flex布局干扰内联流 - H5 端若仍不滚动,检查是否被
overflow: hidden的祖先节点截断
点击标签切换选中态但不依赖 checkbox-group?慎用
有些场景想自定义高亮样式(比如加背景色、圆角边框),又不想暴露原生 checkbox 样式,于是监听 click 自己维护 selected 数组。这可行,但要注意三个坑:
- 没处理空数组初始化 ——
selectedTags = []必须在data或setup中明确定义,否则响应式失效 - 用
includes()判断再push/splice容易重复添加或删错索引;推荐用indexOf+splice或filter替代 - 未同步更新
checkbox的checked属性(如果还留着 checkbox 元素),会导致视图与数据不一致
示例安全写法:
toggleTag(id) {
const idx = this.selectedTags.indexOf(String(id))
if (idx > -1) {
this.selectedTags.splice(idx, 1)
} else {
this.selectedTags.push(String(id))
}
}
性能敏感:上千标签时别一次性全量渲染
热门标签列表如果动态拉取、数量达几百甚至上千,全量 v-for 渲染会卡顿,尤其在低端安卓机上。uni-app 没有内置虚拟滚动,得手动截断 + 懒加载。
- 首次只渲染前 20 个,加「查看更多」按钮,点击后追加 20 个(用
slice(0, showCount)控制) - 避免在
v-for中调用方法(如:class="getTagClass(tag)"),改用计算属性或预处理数据 - 标签文案过长时用
text-overflow: ellipsis,但 H5 需配合white-space: nowrap; overflow: hidden,小程序则要加ellipsis属性
真正麻烦的不是怎么写,而是「什么时候该分页」「哪些标签需要实时响应用户输入变化」——这些得结合业务埋点和真机测帧率来定,不能光看代码行数。











