Skip to content

Instantly share code, notes, and snippets.

@TransparentLC
Last active August 4, 2020 13:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save TransparentLC/298463165b026217e7afd494c968d44e to your computer and use it in GitHub Desktop.
Save TransparentLC/298463165b026217e7afd494c968d44e to your computer and use it in GitHub Desktop.
部分参考 https://github.com/tuupola/lazyload 的图片懒加载插件,添加了自动选择 AVIF 和 WebP 格式的支持,本质上是在造轮子 2333
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src="https://cdn.jsdelivr.net/gh/w3c/IntersectionObserver/polyfill/intersection-observer.min.js"></script>
<script src="lazyload.js"></script>
<script>
var el = document.createElement('div');
el.style.cssText = 'display:block;max-width:480px;max-height:360px;height:360px';
for (var i = 0; i < 20; i++) {
var e = el.cloneNode();
var r = Math.random().toString(16).slice(2, 10);
e.setAttribute('data-src', 'https://picsum.photos/seed/' + r + '/600/600');
e.setAttribute('data-webp-src', 'https://picsum.photos/seed/' + r + '/600/600.webp');
document.body.appendChild(e);
}
var loading = URL.createObjectURL(new Blob([
'<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80" display="block" preserveAspectRatio="xMidYMid" viewBox="0 0 100 100" style="margin:auto;background:0% 0%"><circle cx="50" cy="50" r="30" fill="none" stroke="#ddd" stroke-dasharray="125 55" stroke-width="8"><animateTransform attributeName="transform" dur="1s" keyTimes="0;1" repeatCount="indefinite" type="rotate" values="0 50 50;360 50 50"/></circle></svg>'
], {type: 'image/svg+xml'}));
var lazyload = new LazyLoad(document.querySelectorAll('[data-src]'), {
loadingSrc: loading,
beforeObserve: function (e) {
if (e.tagName.toLowerCase() !== 'img') {
e.style.backgroundPosition = 'center';
e.style.backgroundRepeat = 'no-repeat';
}
},
afterObserve: function (e) {
console.log(e);
},
});
</script>
</body>
</html>
(function (root, factory) {
if (typeof exports === "object") {
module.exports = factory(root);
} else if (typeof define === "function" && define.amd) {
define([], factory);
} else {
root.LazyLoad = factory(root);
}
})(typeof global !== "undefined" ? global : this.window || this.global, function (root) {
/**
* @typedef {Object} LazyLoadConfig
* @property {Element} [root]
* @property {String} [rootMargin]
* @property {Number|Number[]} [threshold]
* @property {String} [loadingSrc]
* @property {function (Element)} [beforeObserve]
* @property {function (Element)} [afterObserve]
*/
/**
* @param {NodeList} image
* @param {LazyLoadConfig} config
*/
function LazyLoad(image, config) {
/** @type {IntersectionObserver} */
this.observer = null;
this.image = [].slice.call(image);
for (var k in this.defaults) if (!config.hasOwnProperty(k)) config[k] = this.defaults[k];
this.config = config;
this.init();
}
/**
* @param {Element} el
* @param {String} src
*/
var setSrc = function (el, src) {
if (el.tagName.toLowerCase() === 'img') {
el.src = src;
} else {
el.style.backgroundImage = 'url(' + src + ')';
}
};
var useWebp = undefined;
var useAvif = undefined;
LazyLoad.prototype = {
/** @type {LazyLoadConfig} */
defaults: {
root: null,
rootMargin: '0px',
threshold: 0,
loadingSrc: '',
beforeObserve: function () {},
afterObserve: function () {},
},
init: function () {
var that = this;
this.observer = new IntersectionObserver(function (entries) {
entries.forEach(function (entry) {
if (entry.isIntersecting) {
var el = entry.target;
that.load(el);
}
});
}, this.config);
this.image.forEach(function (/** @type {Element} */ el) {
setSrc(el, that.config.loadingSrc);
that.config.beforeObserve(el);
that.observer.observe(el);
});
},
/**
* @param {Element} el
*/
load: function (el) {
var that = this;
// Promise.all is a better choice...
if (useAvif === undefined) {
var imgAvif = new Image;
imgAvif.onload = imgAvif.onerror = function() {
useAvif = imgAvif.width > 0;
if (useWebp === undefined) {
var imgWebp = new Image;
imgWebp.onload = imgWebp.onerror = function() {
useWebp = imgWebp.width > 0;
that.load(el);
};
imgWebp.src = 'data:image/webp;base64,UklGRjIAAABXRUJQVlA4ICYAAACyAgCdASoCAAEALmk0mk0iIiIiIgBoSygABc6zbAAA/v56QAAAAA==';
return;
}
that.load(el);
};
imgAvif.src = 'data:image/avif;base64,AAAAHGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZgAAAPJtZXRhAAAAAAAAAChoZGxyAAAAAAAAAABwaWN0AAAAAAAAAAAAAAAAbGliYXZpZgAAAAAOcGl0bQAAAAAAAQAAAB5pbG9jAAAAAEQAAAEAAQAAAAEAAAEWAAAAFAAAAChpaW5mAAAAAAABAAAAGmluZmUCAAAAAAEAAGF2MDFDb2xvcgAAAABqaXBycAAAAEtpcGNvAAAAFGlzcGUAAAAAAAAAAQAAAAEAAAAQcGl4aQAAAAADCAgIAAAADGF2MUOBTQgAAAAAE2NvbHJuY2x4AAIAAgACgAAAABdpcG1hAAAAAAAAAAEAAQQBAoMEAAAAHG1kYXQSAAoFWAAOxIAyCRAAAAAP+I9ngg==';
return;
}
setSrc(el, (useAvif && el.getAttribute('data-avif-src')) || (useWebp && el.getAttribute('data-webp-src')) || el.getAttribute('data-src'));
this.observer.unobserve(el);
this.config.afterObserve(el);
},
destroy: function () {
if (!this.settings) return;
this.observer.disconnect();
this.config = null;
},
};
return LazyLoad;
});
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<p>Scroll down and the image will appear below.</p>
<p>The image will be the AV1/WebP/JPEG logo if your browser support that format. </p>
<div style="height:1280px"></div>
<hr>
<img
height="256"
data-src="https://bj.bcebos.com/im-cs/32316d5b7e4ff72a2e31ff364b631fcc.jpg"
data-webp-src="https://bj.bcebos.com/im-cs/14489017c6674588093174dea7a89e81.webp"
data-avif-src="https://bj.bcebos.com/im-cs/534cfa1d5d7bb418197cdf0cdc2f1332.avif"
>
<script src="https://cdn.jsdelivr.net/gh/w3c/IntersectionObserver/polyfill/intersection-observer.min.js"></script>
<script src="lazyload.js"></script>
<script>
var loading = URL.createObjectURL(new Blob([
'<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80" display="block" preserveAspectRatio="xMidYMid" viewBox="0 0 100 100" style="margin:auto;background:0% 0%"><circle cx="50" cy="50" r="30" fill="none" stroke="#ddd" stroke-dasharray="125 55" stroke-width="8"><animateTransform attributeName="transform" dur="1s" keyTimes="0;1" repeatCount="indefinite" type="rotate" values="0 50 50;360 50 50"/></circle></svg>'
], {type: 'image/svg+xml'}));
var lazyload = new LazyLoad(document.querySelectorAll('[data-src]'), {
loadingSrc: loading,
afterObserve: function (e) {
console.log(e);
},
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment