不能直接用Canvas渲染搜索历史词云,因其在iOS WKWebView易错位、Android低版本WebView渲染偏移、H5与小程序字体缩放不一致、不响应屏幕旋转及动态字号,且不支持无障碍访问;应采用纯CSS+flex布局+预设字号类与颜色数组实现。

搜索历史词云为什么不能直接用 Canvas 渲染
Canvas 在 uni-app 里真机表现极不稳定:iOS WKWebView 下容易错位,Android 低版本 WebView 渲染偏移,H5 和小程序之间字体缩放不一致,且无法响应屏幕旋转或动态字号调整。更关键的是,Canvas 不支持无障碍访问,对视力障碍用户不友好。
词云本质是「视觉权重表达」,不是图形绘制任务。用纯 CSS + v-for + 预设 class 就够了,性能高、兼容稳、可维护强。
- 外层容器加
display: flex; flex-wrap: wrap; justify-content: center; - 每个词用
<view class="tag-item" :class="sizeClassMap[rank]" :style="{ color }">{{ word }}</view> -
sizeClassMap是提前算好的映射表,比如{ 0: 'size-l', 1: 'size-m', 2: 'size-s' },避免模板里调Math.random() - 颜色也预存在数组里:
this.colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4'],按索引取,不现场生成
吸附式搜索框和词云共存时的层级与滚动冲突怎么解
当搜索框吸顶(position: sticky 或 fixed)后,如果词云区域在它下方,且用了 scroll-view,会出现两个问题:一是词云被吸顶框遮挡,二是 scroll-view 的 @scroll 事件无法触发吸附逻辑。
正确做法是让整个页面滚动由 page 控制,词云区域不单独滚动;吸顶只作用于搜索框本身,而非整个导航栏。
- 搜索框加
position: sticky; top: var(--status-bar-height); z-index: 999;,不要用fixed(否则 iOS 键盘弹起时错位) - 词云区域放在搜索框正下方,用普通
<view></view>,不包scroll-view - 若词云项超过 15 条,改用横向
scroll-view scroll-x,避免纵向撑开导致吸顶失效 - 确保
pages.json中该页面的"disableScroll": false,允许原生页面滚动
点击历史词后 input 不更新、光标不聚焦的三连坑
这不是词云的问题,而是 uni-app 受控组件 + 平台差异叠加导致的静默失败。常见现象:点“iPhone”后 input 显示空白、键盘不弹、搜索没触发。
-
v-model绑定变量名必须和赋值语句完全一致,比如v-model="searchText"就不能写成this.searchValue = word - 安卓真机需手动聚焦:
this.$nextTick(() => this.$refs.inputRef?.focus()),且input要有ref="inputRef" - iOS 上如果用了防抖搜索(
setTimeout),点击历史词后必须clearTimeout(this.timer),否则旧定时器可能覆盖新输入 - 别在
@click里直接调uni.navigateTo跳转搜索页——要先赋值、聚焦、再跳转,否则新页面的v-model拿不到初始值
本地存储历史词时 iOS 静默失败的规避方案
iOS 的 uni.setStorageSync 在写入含控制字符(如 `\u2028`、`\u2029`)、超长字符串或非法 JSON 时会静默失败,不报错也不存入,但 Android 正常。这是最隐蔽的兼容性陷阱。
- 写入前先做安全过滤:
keyword.replace(/[\u2028\u2029\u0000-\u0008\u000b\u000c\u000e-\u001f]/g, '') - 用
try/catch包裹写入逻辑,失败时 fallback 到内存缓存(仅本次会话有效) - 验证是否写入成功:写完立刻
uni.getStorageSync('searchHistory')读一次,比对长度或首项是否匹配 - 别依赖
uni.getStorageInfoSync判断 key 是否存在——它返回的是总容量信息,不是 key 存在性探针


















