背景
在对接AI对话中大多数都是返回纯文本,但是联网搜索会有返回图片的情况,我也是偶然间才发现的,在AI的一顿输出中屏幕里的图片一闪一闪的,像是扔了个闪光弹。所以得想个法子处理一下。
分析原因
不断的回流和重绘
因为在AI对话中,
SSE返回数据了,前端就得拿到content去+=,由于AI返回的都是markdown格式的字符串,前端还得用第三方库把markdown解析成html去渲染,所以每次content变动都会重新解析成html,然后就是重新渲染了
布局跳动
因为AI返回的
markdown字符串中图片是没有尺寸大小,如果自己没有去定义样式规定大小布局,浏览器在重新渲染时就得去计算,可能本地的其它样式也互相影响
频繁请求
还是在不断的重新渲染中遇到图片就请求,在浏览器的
网络面板中可以观察到,连续重复的对同一图片请求
解决方案
一开始想到的肯定是问AI怎么办啦。当然我也问了,AI给了一些方案,但是试过了效果还是不好,但是解决了布局跳动,没解决图片闪烁的问题。
先简单说一下AI给的方案
- 给图片加上行内样式,规定宽高可以解决布局跳动的问题。【这个可以的】
- 上
Map和预加载,把图片预加载和缓存起来。【没有什么效果】 - 给图片加透明度
opacity:0,等loaded后再把opacity:1。【没有什么效果,不过我试了visibility:hidden/show这种还彳亍,就是页面留白,会让人不知道是什么】
走过的一些弯路
- 监听
content变化,再用正则替换img加上样式。再几次尝试后发现console没有打印,意识到content里是markdown格式的字符串,用正则去匹配html字符串是一丶用没有。 - 就是听信AI,上样式
opacity和监听onload过渡。不过起码发现了visibility:show/hidden这东西好使。
最终方案
- 自定义
marked的图片解析器,在解析图片时包上一层div,但是记得把href,title这些设置为data-方便后续处理,里面放一个本地的svg占位图,不是真实的网络图片。 - 监听对话是否完成,完成对话时,找到富文本里刚才包裹的所有
div,这时候就可以清空div,再把真实的img挂载进去就大功告成了。但是我做了小优化,我利用vue中的h和render函数,把第三方组件的图片组件挂载到div了,可以实现预览。
自定义图片渲染器
对话完成后处理富文本里的图片
部分HTML结构
效果
回复中占位效果
对话完成后的效果