刚刚花了一点点时间解决了一个 Vue 项目的图片 lazyload 问题,简单记录下解决过程。
先介绍一下这个项目,它是几个月前由两个人做的一个前后端 Web 项目,我当时负责的是后端+部署,并在之后接手了前端维护工作。这个项目是一个面向 Desktop 和 Mobile 的响应式设计的站点,是一个 Card Collection 类的设计,每个 Card 都有图片和文字。
当时前端的制作没有考虑太多的性能方面的问题, 内容是一页形式的,所有 Card 数据一次性加载出来,在 Desktop 上面是以滚动 Section 的形式展示出来,而在 Mobile 上面则是以 Tab 的形式+ CSS Display 的形式来显示出来。无论哪种形式,这里有一个明显的问题:所有的图片都是一次性加载的,而不是 lazy load,随着数据量的增大,首页载入越来越慢,也越来越消耗时间和流量。
解决这个问题的思路当然是把图片 lazy load 化,但是因为 Desktop 的 Mobile 的交互的不同,导致了实现 lazy load 过程中绕了点路。
我通过简单的搜索,找到了 vue-lazyload 这个组件。
前面提到了,Desktop 上是以滚动 Section 的形式去展示所有的 Card 的,于是在这种情况下,lazy load 是天然工作的,然而在 Mobile 模式下,是以点击切换 Tab 的形式去展示不同 Section 的 Card,于是 lazy load 不工作了。
当时我并没有发现不工作的原因,因为在 Mobile 上切换了 Tab 后,数据出来了,但是图片没有加载,直到上面部分自动切换的 Banner 切换到下一张图了,Card 部分的图片才加载起来。我观察了好久,发现图片加载的时机有长有短,后来发现似乎和 Banner 有关,后来一验证,果然是这样,Banner 的自动切换图片发出了 scroll 事件,而 vue-lazyload 是监听 scroll 事件才去检查是否有必要加载图片的,于是就加载了…
既然发现了这个问题,我就得想办法在 Mobile 上界面上也能触发一下 scroll 事件,但由于整体结构和 Desktop 不太一样,除非进行比较大的重构,否则无法变成一个切换 Tab 会变成发出 scroll 事件的设计。
我接着看了看 vue-lazyload 的文档,发现它还监听如 mousewheel 这样的事件,于是我就在处理 Tab 切换的事件上,手动发出一个 mousewheel 事件,去手动触发 lazy load,算是曲线救国了…
methods: {
handleNavItemClick: function (collectionId) {
this.activeTab = collectionId
// 手动触发 lazy load
let event = document.createEvent('MouseEvents')
event.initEvent('mousewheel', true, true)
this.$el.dispatchEvent(event)
}
}
尽管这是一个 Workaround,但是比较低成本地去解决了这个问题,也算是个解决方案吧。后续有时间再去改进~
一直以为 lazyload 是靠 viewport 实现的……