mem-lazyload
Version:
#### 项目介绍 图片懒加载html5原生组件
180 lines (174 loc) • 6.01 kB
JavaScript
/**
* 使用方法:
* let lazy = new LazyLoad(window);
* // 当页面lazyload图片dom新增时调用update方法刷新lazy数据
* lazy.update();
*/
((global, factory) => {
typeof module !== 'undefined' && typeof module.exports === 'object' ?
module.exports = factory() : (global.LazyLoad = factory());
})(window, function () {
// 自定义标签名
const CUSTOM_ELEMENT_NAME = 'lazy-image';
const ANIMATION_CLASS = 'lazy-image-load';
// 样式常量
const DISPLAY_DEFAULT = 'inline-block';
const DISPLAY_INLINE = 'inline';
const POSITION_DEFAULT = 'relative';
const POSITION_STATIC = 'static';
const IMAGE_CLASS = 'lazy-image-real-dom';
const INITIAL_IMAGE = 'http://qn.zhangyy.xyz/5c9206d469.jpeg';
// 自定义类
class LazyImage extends HTMLElement {
constructor() {
super();
}
// 初始化元素
init() {
if (!LazyImage.$id) {
LazyImage.$id = 0;
}
LazyImage.$id += 1;
this.$id = LazyImage.$id;
// 是否已经加载图片
this.loaded = false;
let styleSheets = window.getComputedStyle(this, null);
let display = styleSheets.display;
let position = styleSheets.position;
this.setStyle(this, {
display: display === DISPLAY_INLINE ? DISPLAY_DEFAULT : display,
position: position === POSITION_STATIC ? POSITION_DEFAULT : position,
});
this.activeClass = this.getAttribute('active-class') || ANIMATION_CLASS;
this.initSrc = this.getAttribute('init-src') || INITIAL_IMAGE;
// 插入图片dom
this.img = this.insertImage();
// 注册过的自定义组件在dom更新时会重新注册,但是插入的dmo不会被注销,所以只更换自定义dom的外壳,
// 插入的dom状态保持原样
if (this.loaded) {
this.loadEnd();
}
this.setStyle(this.img, {
position: 'absolute',
left: '0',
top: '0',
width: '100%',
height: '100%',
});
}
// 插入图片dom
insertImage() {
let oImg = this.querySelector(`.${IMAGE_CLASS}`);
if (!oImg) {
oImg = document.createElement('img');
oImg.src = this.initSrc;
oImg.className = IMAGE_CLASS;
this.insertBefore(oImg, this.firstChild);
} else if (this.getAttribute('src') === oImg.src) {
this.loaded = true;
}
return oImg;
}
// 给dom设置样式
setStyle(dom, styles) {
Object.keys(styles).forEach((prop) => {
dom.style[prop] = styles[prop];
});
}
// 加载图片
load() {
if (this.loaded) {
return;
}
this.img.src = this.getAttribute('src');
this.img.className += ` ${this.activeClass}`;
this.loaded = true;
this.addEventListener('webkitAnimationEnd', this.loadEnd, false)
}
loadEnd(e) {
this.img.className = this.img.className.replace(this.activeClass, '');
this.removeEventListener('webkitAnimationEnd', this.loadEnd);
}
// dom首次被插入文档DOM时调用
connectedCallback() {
this.init();
}
// dom移除时调用
disconnectedCallback() {
this.loadEnd();
}
}
// 注册自定义组件
customElements.define(CUSTOM_ELEMENT_NAME, LazyImage);
class LazyLoad {
constructor(container = window) {
// wrap为滑动容器的对象
// container为dom容器,做查询dom的容器
this.wrap = container;
if (container === window) {
container = document;
}
this.container = container;
this.lazyImages = [];
this.init();
}
init() {
this.insertStyle();
this.update();
this.registerScroll();
}
// 插入样式
insertStyle() {
let oStyle = document.createElement('style');
oStyle.innerHTML = `
.${ANIMATION_CLASS} {
animation: lazyImageLoad 1s;
}
lazyImageLoad {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
`;
document.head.appendChild(oStyle);
}
// 类数组转换
makeArray(arrayLike) {
return Array.prototype.slice.call(arrayLike);
}
// 更新需要懒加载的dom
update() {
setTimeout(() => {
this.lazyImages = this.makeArray(this.container.querySelectorAll('lazy-image'))
.filter((oItem) => {
return !oItem.loaded;
});
this.loadImage();
}, 0);
}
// 加载更多图片
loadImage() {
this.lazyImages = this.lazyImages.filter((oItem) => {
let rect = oItem.getBoundingClientRect();
let top = rect.top;
if (top < window.innerHeight) {
oItem.load();
return false;
}
return true;
});
}
// 注册scroll事件
registerScroll() {
this.wrap.addEventListener('scroll', (e) => {
if (this.lazyImages.length) {
this.loadImage();
}
});
}
}
return LazyLoad;
});