蕾米洛伊
本帖最后由 蕾米洛伊 于 2020-12-25 00:30 编辑

关于 bbs 图片懒加载的一个特别小的小建议
在图片下载过程中,即使图片一部分已经可以显示,但由于论坛机制的缘故,只会显示一个 loading 转圈圈图直到图片完全下载完毕
同时这个 loading 占位图不会因为加载错误而消失

在图片很小的情况下,这个没啥毛病
但是当图片非常大,尤其是图床还有限速(比如路过图床)的时候,就会出现图片很久无法显示的情况。
尤其是在精美的皮肤贴、茶馆里的图片贴、插件/服务器贴里面的超长图,这些帖子核心内容在图片内的情况,迟迟无法显示就非常影响阅读
而且这种情况没办法让用户有一个心理预期,只有一个圈圈一直在转还不知道有多久可以加载完,体验非常不好 orz

以及 loading 占位图因为不会因为加载错误而消失。即使加载已经停止,它还是一直在转圈圈转圈圈,此时就容易对用户和发图的楼主产生困扰。

所以咱建议在图片进入到视口的时候,直接让浏览器渲染图片,而不是先显示loading,等待图片加载完全结束后再替换为图片
这样 在绝大多数浏览器内 至少可以下载到哪看到哪 orz
同时能够在加载错误时直接显示❌或者不显示,至少可以给用户 “加载已经停止” 了的感觉,以便更直观地体现错误。



貌似这个建议有点多余(逃
(当然图片加载速度问题应该先由发图者自己想办法解决)
PS. WX的懒加载和论坛的方案是一样的,在网络不好或者 gif 非常大情况下就非常抓狂。然而考虑到每天有2亿人教张小龙做WX我可能排不上号


homeftw
我觉得有必要,很影响阅读体验

SHEEP_REALMS
一般情况下只有站内图床会显示加载图标,站外图床会直接开始加载内容,这个机制有点迷,如果站外图床也出现加载图标了那多半是反盗链/非HTTPS资源/无法连接图床。

Listry
对啊,一些帖子的图很容易挂掉,影响阅读

Salt_lovely
本帖最后由 Salt_lovely 于 2020-12-25 16:10 编辑

测试了一下,Discuz懒加载的逻辑是(懒得讲了直接放代码):
  1.             if (!img.getAttribute('lazyloaded') && offsetTop > document.documentElement.clientHeight && (offsetTop - scrollTop < document.documentElement.clientHeight)) {
  2.                 var dom = document.createElement('div');
  3.                 var width = img.getAttribute('width') ? img.getAttribute('width') : 100;
  4.                 var height = img.getAttribute('height') ? img.getAttribute('height') : 100;
  5.                 dom.innerHTML = '<div style="width: ' + width + 'px; height: ' + height + 'px;background: url(' + IMGDIR + '/loading.gif) no-repeat center center;"></div>';
  6.                 img.parentNode.insertBefore(dom.childNodes[0], img); // 在img前添加占位的div元素
  7.                 img.onload = function() { // 当图片加载完毕
  8.                     if (!this.getAttribute('_load')) {
  9.                         this.setAttribute('_load', 1);
  10.                         this.style.width = this.style.height = ''; // 恢复图片大小
  11.                         this.parentNode.removeChild(this.previousSibling); // 移除占位的div元素
  12.                         if (this.getAttribute('lazyloadthumb')) {
  13.                             thumbImg(this);
  14.                         }
  15.                     }
  16.                 }
  17.                 ;
  18.                 img.style.width = img.style.height = '1px'; // 加载中的图片长宽为 1px
  19.                 img.setAttribute('src', img.getAttribute('file') ? img.getAttribute('file') : img.getAttribute('src')); // 将file属性的内容添加到src里面
  20.                 img.setAttribute('lazyloaded', true); // 标记为已开始加载
  21.             }
复制代码

页面滚动到图片位置 -> 将图片的file属性添加到src上(此时浏览器开始下载图片)
-> 添加一个DIV占位(也就是你所说的那个转啊转的) -> 图片宽高均为1px(即不可见)
-> 图片下载完毕 -> 图片恢复大小 -> 占位的DIV消失

整个逻辑中缺少了图片下载失败的处理,而且用的是 .onload 这种方法不方便改写,我可以试试用用户脚本的手段覆盖Discuz的懒加载

覆写思路:
在DOMContentLoaded的时候(即页面加载完毕,开始下载资源的时候)启用 ->
遍历页面上所有的img(下一步就是劫持) ->
添加“lazyloaded”属性(Discuz的加载逻辑中会忽略含有“lazyloaded”属性的图片) ->
添加IntersectionObserver,监听所有img ->
img出现在页面上时监听器触发,移除当前img的监听,加载img
* IntersectionObserver异步监听元素是否进入页面,所以不会卡顿。

第一页 上一页 下一页 最后一页