需先解析文本将@、#、URL转为带data-type/data-value的标签,再v-html渲染,最后父容器事件委托监听;微信小程序须用rich-text nodes数组替代。

uni-app里怎么用v-html安全渲染带链接的富文本
直接用v-html会丢掉点击事件,也拦不住XSS——微博那种「@张三」「#话题#」「http://xxx」自动变可点击链接的需求,光靠v-html做不到。
得先解析原始文本,把匹配到的链接、@、#替换成带data-type和data-value的标签,再用v-html渲染,最后在父容器上委托监听click事件。
- 别用正则全局替换后直接塞
v-html——没加target="_blank"或rel="noopener"容易被利用 - 匹配
http(s)://时注意末尾标点(如句号、逗号),否则「详见:https://a.com。」会把句号包进href - 微信小程序不支持
v-html,必须走rich-text组件,但rich-text不支持自定义data-*属性,得改用nodes数组方式构造节点
正则怎么写才不漏不炸:@、#、URL三类匹配要点
三类目标要分开处理,顺序不能错:先匹配URL(最复杂),再@用户名,最后#话题#。否则「@https://a.com」会被误判成@号。
- URL推荐用:
/(https?://[^s"{}|\^`[]]+)/g——比S+更稳,避开HTML敏感字符 - @用户名:
/@([a-zA-Z0-9_u4e00-u9fa5]{1,15})/g,限制中文+英文+数字+下划线,长度别超15,防恶意长字符串 - #话题#:
/#([^# u2028u2029]+?)#/g,非贪婪匹配,排除换行和Unicode分隔符
示例替换逻辑(仅核心):
text.replace(urlReg, '<a href="%241" data-type="url" data-value="$1">$1</a>')
点击事件怎么绑定才跨端有效
不能给每个单独绑——动态生成的DOM,且小程序里v-html根本不会触发事件。
- 统一在富文本容器上用
tap(小程序)或click(H5)监听,然后用e.target.dataset.type判断类型 - H5需加
preventDefault()避免跳转干扰;小程序里rich-text的nodes方式要用bindtap,且data-*属性必须写成data-type格式,不能驼峰 - 注意iOS WebView中
click有300ms延迟,建议用touchstart代替,但得自己做防重复触发
小程序rich-text下怎么让链接可点又不跳转
rich-text不执行JS,也不认data-*,只能靠nodes数组里的attrs传参,再在bindtap里取e.detail.tapIndex反查节点。
- 解析完文本后,不要拼HTML字符串,改用
nodes: [{ name: 'a', attrs: { 'data-type': 'at', 'data-value': '张三' }, children: [...] }] - 点击时通过
e.detail.nodes[e.detail.tapIndex]拿到对应节点,读attrs['data-type']和attrs['data-value'] - 别忘了给
a节点加style="color: #007AFF; text-decoration: underline;",否则默认是黑字无下划线,用户看不出是链接
真正麻烦的是三端行为不一致:H5能直接window.open,App需uni.openWebview,小程序得uni.navigateTo或uni.previewMedia——路由逻辑得按uni.getSystemInfoSync().platform拆开写。










