做过尝试 这个功能完成之前,本博客静态生成的html是无法使用懒加载的,因为懒加载组件是一个vue component。关于如何静态生成html,可以参考edit组件。我试过动态编译v-html,但是无法避免html字符串里有和vue冲突的东西。 改变思路 直到昨天,我都没有想好如何解决这个问题,一直留了个TODO在那。昨晚躺床上时灵光一现:无法编译整个html,那我只取出想要的部分,然后手动替换成vue实例呢?今早起来,打开电脑准备试试,这是这周最后一次在家里用电脑了 首先就是如何在js里手动实例化一个.vue单文件组件,找到了一个方法,尝试可行。 第二步,在v-html渲染后,手动替换图片为懒加载图片组件。只需在$nextTick加上: import LazyImg from "~/comps/lazy-img"; const LazyImgComp = Vue.extend(LazyImg); this.$refs.markdown.querySelectorAll('.image-container img').forEach(el => { new LazyImgComp({ propsData: { src: el.getAttribute('src'), alt: el.title, viewer: true, imgStyle: el.getAttribute('style'), title: el.title, } }).$mount(el); }) 对,没错,这一步就行了。但是有一个问题,项目之前懒加载监听的scroll事件,是从layout父级组件provide拿的。因为懒加载很多,若每一个都去addEventListener太不优雅;另外scroll还要被其他页面使用,例如文章详情的menu;另外scroll做了节流。所以我把它放到了顶级元素里(这里也是一个骚操作,有兴趣可以扒扒源码),这会导致一个问题:手动实例化的LazyImgComp,拿不到这个scroll inject!现在只有一种办法,把原本就不属于vue管的浏览器事件,脱离出去。 真正的问题 所以现在的问题就是,如何把scroll事件脱离出去,而且要让它为全站所使用。这个问题对我来说有点棘手,之前没这样做过。但是!又一个灵光一现,既然scroll是事件监听,那我为何不直接代理它,然后想怎么转发就怎么转发呢。于是就有了以下操作: 删掉之前的scroll烂代码。 新建一个scroll-event.js文件,如下:import {inBrowser} from "~/utils/utils"; import throttle from "lodash/throttle"; let scrollEvent = null; // 初始化window监听 export function initScrollTrigger () { if (inBrowser) { scrollEvent = new CustomEvent('scroll-event'); window.addEventListener('scroll', throttle(e => { window.dispatchEvent(scrollEvent); }, 200)); } } // 监听转发的事件 export function addScrollListener (callback) { if (scrollEvent) { window.addEventListener('scroll-event', callback); } } // 取消监听 export function rmScrollListener (callback) { if (scrollEvent) { window.removeEventListener('scroll-event', callback); } } initScrollTrigger只需要在layout顶级元素的mount里调用一次。然后addScrollListener作为节流过的scroll事件,就可以随便用了。实测可行。 冬天手冻僵了,人也懒,文章写得太简单,以后空闲想写了再完善吧。。。
适用于静态HTML的一种图片懒加载策略
做过尝试
这个功能完成之前,本博客静态生成的html是无法使用懒加载的,因为懒加载组件是一个vue component。关于如何静态生成html,可以参考edit组件。我试过动态编译
v-html
,但是无法避免html字符串里有和vue冲突的东西。改变思路
直到昨天,我都没有想好如何解决这个问题,一直留了个TODO在那。昨晚躺床上时灵光一现:无法编译整个html,那我只取出想要的部分,然后手动替换成vue实例呢?今早起来,打开电脑准备试试,这是这周最后一次在家里用电脑了
首先就是如何在js里手动实例化一个
.vue
单文件组件,找到了一个方法,尝试可行。第二步,在
v-html
渲染后,手动替换图片为懒加载图片组件。只需在$nextTick
加上:import LazyImg from "~/comps/lazy-img"; const LazyImgComp = Vue.extend(LazyImg); this.$refs.markdown.querySelectorAll('.image-container img').forEach(el => { new LazyImgComp({ propsData: { src: el.getAttribute('src'), alt: el.title, viewer: true, imgStyle: el.getAttribute('style'), title: el.title, } }).$mount(el); })
对,没错,这一步就行了。但是有一个问题,项目之前懒加载监听的scroll事件,是从layout父级组件provide拿的。因为懒加载很多,若每一个都去
addEventListener
太不优雅;另外scroll还要被其他页面使用,例如文章详情的menu;另外scroll做了节流。所以我把它放到了顶级元素里(这里也是一个骚操作,有兴趣可以扒扒源码),这会导致一个问题:手动实例化的LazyImgComp
,拿不到这个scrollinject
!现在只有一种办法,把原本就不属于vue管的浏览器事件,脱离出去。真正的问题
所以现在的问题就是,如何把scroll事件脱离出去,而且要让它为全站所使用。这个问题对我来说有点棘手,之前没这样做过。但是!又一个灵光一现,既然scroll是事件监听,那我为何不直接代理它,然后想怎么转发就怎么转发呢。于是就有了以下操作:
scroll-event.js
文件,如下:import {inBrowser} from "~/utils/utils"; import throttle from "lodash/throttle"; let scrollEvent = null; // 初始化window监听 export function initScrollTrigger () { if (inBrowser) { scrollEvent = new CustomEvent('scroll-event'); window.addEventListener('scroll', throttle(e => { window.dispatchEvent(scrollEvent); }, 200)); } } // 监听转发的事件 export function addScrollListener (callback) { if (scrollEvent) { window.addEventListener('scroll-event', callback); } } // 取消监听 export function rmScrollListener (callback) { if (scrollEvent) { window.removeEventListener('scroll-event', callback); } }
initScrollTrigger
只需要在layout顶级元素的mount里调用一次。然后addScrollListener
作为节流过的scroll事件,就可以随便用了。实测可行。冬天手冻僵了,人也懒,文章写得太简单,以后空闲想写了再完善吧。。。