真正可用的摘要截断方案是服务端返回摘要字段或前端用canvas精确测量后截断,因中英文、emoji、全角标点视觉宽度不一且系统渲染差异导致substring等固定字数截取不可控。

过滤器里不能直接用 substring 截固定字数
中英文、emoji、全角标点在不同设备上视觉宽度差异极大,content.substring(0, 80) 在 iOS 上可能显示 4 行,在安卓低端机上只占 1.5 行,省略号位置完全不可控。更糟的是,微信小程序里 emoji(如 ??)被解析为多个 Unicode 码点,.length 返回 2 或 4,但实际渲染宽度≈2个汉字——靠字符数截取等于放弃一致性。
真正能落地的过滤器写法:优先用服务端摘要,fallback 才走 canvas 测量
过滤器本质是纯同步函数,不能发请求、不能等 DOM 渲染、不能异步初始化 canvas。所以它只能做「兜底」,不能当主力截断逻辑。
- 接口返回了
item.summary或item.abstract,过滤器第一行就直接return value.summary || value.abstract - 没返回时,才调用本地 canvas 测量函数,且该函数必须提前定义好(不能在过滤器内 new canvas)
-
truncateByWidth函数需预设好 font 字体(如'14px system-ui')、最大宽度(如300),避免每次传参不一致 - 别在过滤器里调用
uni.createSelectorQuery——它异步,过滤器执行完 DOM 都还没挂载
truncateByWidth 必须在 onReady 后初始化 canvas 上下文
canvas 测量依赖真实字体度量,而 uni-app 的 uni.createCanvasContext 在组件未挂载时会返回空上下文,导致 measureText 报错或返回 0。
- 在
onReady或onLoad后首次调用一次初始化函数,创建并缓存ctx - 过滤器内只复用已准备好的
ctx,不做重复创建 - font 值必须和目标文本 CSS 中的
font完全一致(包括字号、字体族、是否加粗),否则测量失真 - 测量循环中,用
ctx.measureText(char).width累加,不是ctx.measureText(text).width——后者测整串,无法定位截断点
容易被忽略的边界:iOS 真机下 text-overflow: ellipsis 在 <text> 里根本无效
很多开发者以为写了过滤器就万事大吉,结果发现 H5 正常、小程序里文字还是撑开。根本原因是:uni-app 编译到小程序平台时,<text> 组件被映射为原生 text 节点,它不支持 text-overflow、display: -webkit-box 等任何盒模型相关样式。
- 过滤器生成的带
'…'的字符串,必须塞进<view>,不能塞进<text> - 如果用了
<rich-text>,过滤器截断后的字符串会被当作 HTML 解析,'…'可能被当成文本节点吞掉,得额外转义 - 安卓模拟器看着正常,不代表真机能过——iOS WebKit 对
-webkit-line-clamp的校验极其严格,缺一个条件(比如没设max-height)就静默失效
<view> 承载,三者缺一不可。


















