Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
feat: add a mutationObserver to reload when some valid attributes cha…
…nges (#192)

* feat: add a mutationObserver to reload when some valid attributes changes
  • Loading branch information
iam-frankqiu committed Sep 10, 2020
1 parent 3f9bb22 commit 146b6ba
Show file tree
Hide file tree
Showing 8 changed files with 149 additions and 21 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -4,3 +4,4 @@ node_modules
.DS_Store
thumbs.db
*.log*
coverage
4 changes: 3 additions & 1 deletion README.md
Expand Up @@ -12,8 +12,9 @@
- supports <img>, <picture>, iframes, videos, audios, responsive images, background images and multiple background images etc.
- even supports LQIP (Low Quality Image Placeholder)
- is completely free and open source.
- it will reload when the valid attributes change.

It is written with an aim to lazy load images, iframes, ads, videos or any other element using the recently added [Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) with tremendous performance benefits.
It is written with an aim to lazy load images, iframes, ads, videos or any other element using the recently added [Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) and [MutationObserver](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) with tremendous performance benefits.

## Featured in:
- [Web | Google Developers](https://developers.google.com/web/fundamentals/performance/lazy-loading-guidance/images-and-video/)
Expand Down Expand Up @@ -112,6 +113,7 @@ or with custom options:
const observer = lozad('.lozad', {
rootMargin: '10px 0px', // syntax similar to that of CSS Margin
threshold: 0.1 // ratio of element convergence
enableAutoReload: true // it will reload the new image when validating attributes changes
});
observer.observe();
```
Expand Down
12 changes: 10 additions & 2 deletions demo/index.html
Expand Up @@ -58,7 +58,7 @@ <h1><a href="https://github.com/ApoorvSaxena/lozad.js"><strong>Lozad.js</strong>
<h1>Lozad.js - Performant Lazy Loading Library</h1>
</article>
<article class="thumb">
<img class="lozad" data-placeholder-background="#583624" data-src="images/thumbs/01.jpg" data-index="1" />
<img class="lozad" id="mutativeImg1" data-placeholder-background="#583624" data-src="images/thumbs/01.jpg" data-index="1" />
<noscript><img src="images/thumbs/01.jpg" data-index="1" /></noscript>
<h2>Image 1</h2>
</article>
Expand All @@ -68,7 +68,7 @@ <h2>Image 1</h2>
<h2>Image 2</h2>
</article>
<article class="thumb">
<img class="lozad" data-placeholder-background="#352629" data-src="images/thumbs/03.jpg" data-index="3" />
<img class="lozad" id="mutativeImg2" data-placeholder-background="#352629" data-src="images/thumbs/03.jpg" data-index="3" />
<noscript><img src="images/thumbs/03.jpg" data-index="3" /></noscript>
<h2>Image 3</h2>
</article>
Expand Down Expand Up @@ -284,6 +284,7 @@ <h1>&lt;video> example</h1>
// Initialize library to lazy load images
var observer = lozad('.lozad', {
threshold: 0.1,
enableAutoReload: true,
load: function(el) {
el.src = el.getAttribute("data-src");
el.onload = function() {
Expand All @@ -298,6 +299,13 @@ <h1>&lt;video> example</h1>
threshold: 0.1
})

window.onload = function () {
setTimeout(function () {
document.querySelector('#mutativeImg1').dataset.src = 'images/thumbs/02.jpg'
document.querySelector('#mutativeImg2').dataset.src = 'images/thumbs/02.jpg'
toastr["success"]("Once data-src change, the element render again.")
}, 3000)
}
// Background observer
// with default `load` method
var backgroundObserver = lozad('.lozad-background', {
Expand Down
37 changes: 32 additions & 5 deletions dist/lozad.es.js
@@ -1,4 +1,4 @@
/*! lozad.js - v1.16.0 - 2020-09-06
/*! lozad.js - v1.16.0 - 2020-09-10
* https://github.com/ApoorvSaxena/lozad.js
* Copyright (c) 2020 Apoorv Saxena; Licensed MIT */

Expand All @@ -10,9 +10,19 @@
*/
const isIE = typeof document !== 'undefined' && document.documentMode;

/**
*
* @param {string} type
*
*/
const support = type => window && window[type];

const validAttribute = ['data-iesrc', 'data-alt', 'data-src', 'data-srcset', 'data-background-image', 'data-toggle-class'];

const defaultConfig = {
rootMargin: '0px',
threshold: 0,
enableAutoReload: false,
load(element) {
if (element.nodeName.toLowerCase() === 'picture') {
let img = element.querySelector('img');
Expand Down Expand Up @@ -114,6 +124,14 @@ const onIntersection = (load, loaded) => (entries, observer) => {
});
};

const onMutation = load => entries => {
entries.forEach(entry => {
if (isLoaded(entry.target) && entry.type === 'attributes' && validAttribute.indexOf(entry.attributeName) > -1) {
load(entry.target);
}
});
};

const getElements = (selector, root = document) => {
if (selector instanceof Element) {
return [selector]
Expand All @@ -127,17 +145,21 @@ const getElements = (selector, root = document) => {
};

function lozad (selector = '.lozad', options = {}) {
const {root, rootMargin, threshold, load, loaded} = Object.assign({}, defaultConfig, options);
const {root, rootMargin, threshold, enableAutoReload, load, loaded} = Object.assign({}, defaultConfig, options);
let observer;

if (typeof window !== 'undefined' && window.IntersectionObserver) {
let mutationObserver;
if (support('IntersectionObserver')) {
observer = new IntersectionObserver(onIntersection(load, loaded), {
root,
rootMargin,
threshold
});
}

if (support('MutationObserver') && enableAutoReload) {
mutationObserver = new MutationObserver(onMutation(load, loaded));
}

const elements = getElements(selector, root);
for (let i = 0; i < elements.length; i++) {
preLoad(elements[i]);
Expand All @@ -153,6 +175,10 @@ function lozad (selector = '.lozad', options = {}) {
}

if (observer) {
if (mutationObserver && enableAutoReload) {
mutationObserver.observe(elements[i], {subtree: true, attributes: true, attributeFilter: validAttribute});
}

observer.observe(elements[i]);
continue
}
Expand All @@ -171,7 +197,8 @@ function lozad (selector = '.lozad', options = {}) {
markAsLoaded(element);
loaded(element);
},
observer
observer,
mutationObserver
}
}

Expand Down
40 changes: 36 additions & 4 deletions dist/lozad.js
@@ -1,4 +1,4 @@
/*! lozad.js - v1.16.0 - 2020-09-06
/*! lozad.js - v1.16.0 - 2020-09-10
* https://github.com/ApoorvSaxena/lozad.js
* Copyright (c) 2020 Apoorv Saxena; Licensed MIT */

Expand All @@ -16,9 +16,21 @@
*/
var isIE = typeof document !== 'undefined' && document.documentMode;

/**
*
* @param {string} type
*
*/
var support = function support(type) {
return window && window[type];
};

var validAttribute = ['data-iesrc', 'data-alt', 'data-src', 'data-srcset', 'data-background-image', 'data-toggle-class'];

var defaultConfig = {
rootMargin: '0px',
threshold: 0,
enableAutoReload: false,
load: function load(element) {
if (element.nodeName.toLowerCase() === 'picture') {
var img = element.querySelector('img');
Expand Down Expand Up @@ -124,6 +136,16 @@
};
};

var onMutation = function onMutation(load) {
return function (entries) {
entries.forEach(function (entry) {
if (isLoaded(entry.target) && entry.type === 'attributes' && validAttribute.indexOf(entry.attributeName) > -1) {
load(entry.target);
}
});
};
};

var getElements = function getElements(selector) {
var root = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : document;

Expand All @@ -146,19 +168,24 @@
root = _Object$assign.root,
rootMargin = _Object$assign.rootMargin,
threshold = _Object$assign.threshold,
enableAutoReload = _Object$assign.enableAutoReload,
load = _Object$assign.load,
loaded = _Object$assign.loaded;

var observer = void 0;

if (typeof window !== 'undefined' && window.IntersectionObserver) {
var mutationObserver = void 0;
if (support('IntersectionObserver')) {
observer = new IntersectionObserver(onIntersection(load, loaded), {
root: root,
rootMargin: rootMargin,
threshold: threshold
});
}

if (support('MutationObserver') && enableAutoReload) {
mutationObserver = new MutationObserver(onMutation(load, loaded));
}

var elements = getElements(selector, root);
for (var i = 0; i < elements.length; i++) {
preLoad(elements[i]);
Expand All @@ -174,6 +201,10 @@
}

if (observer) {
if (mutationObserver && enableAutoReload) {
mutationObserver.observe(elements[_i], { subtree: true, attributes: true, attributeFilter: validAttribute });
}

observer.observe(elements[_i]);
continue;
}
Expand All @@ -193,7 +224,8 @@
loaded(element);
},

observer: observer
observer: observer,
mutationObserver: mutationObserver
};
}

Expand Down
11 changes: 8 additions & 3 deletions dist/lozad.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 31 additions & 4 deletions src/lozad.js
Expand Up @@ -5,9 +5,19 @@
*/
const isIE = typeof document !== 'undefined' && document.documentMode

/**
*
* @param {string} type
*
*/
const support = type => window && window[type]

const validAttribute = ['data-iesrc', 'data-alt', 'data-src', 'data-srcset', 'data-background-image', 'data-toggle-class']

const defaultConfig = {
rootMargin: '0px',
threshold: 0,
enableAutoReload: false,
load(element) {
if (element.nodeName.toLowerCase() === 'picture') {
let img = element.querySelector('img')
Expand Down Expand Up @@ -109,6 +119,14 @@ const onIntersection = (load, loaded) => (entries, observer) => {
})
}

const onMutation = load => entries => {
entries.forEach(entry => {
if (isLoaded(entry.target) && entry.type === 'attributes' && validAttribute.indexOf(entry.attributeName) > -1) {
load(entry.target)
}
})
}

const getElements = (selector, root = document) => {
if (selector instanceof Element) {
return [selector]
Expand All @@ -122,17 +140,21 @@ const getElements = (selector, root = document) => {
}

export default function (selector = '.lozad', options = {}) {
const {root, rootMargin, threshold, load, loaded} = Object.assign({}, defaultConfig, options)
const {root, rootMargin, threshold, enableAutoReload, load, loaded} = Object.assign({}, defaultConfig, options)
let observer

if (typeof window !== 'undefined' && window.IntersectionObserver) {
let mutationObserver
if (support('IntersectionObserver')) {
observer = new IntersectionObserver(onIntersection(load, loaded), {
root,
rootMargin,
threshold
})
}

if (support('MutationObserver') && enableAutoReload) {
mutationObserver = new MutationObserver(onMutation(load, loaded))
}

const elements = getElements(selector, root)
for (let i = 0; i < elements.length; i++) {
preLoad(elements[i])
Expand All @@ -148,6 +170,10 @@ export default function (selector = '.lozad', options = {}) {
}

if (observer) {
if (mutationObserver && enableAutoReload) {
mutationObserver.observe(elements[i], {subtree: true, attributes: true, attributeFilter: validAttribute})
}

observer.observe(elements[i])
continue
}
Expand All @@ -166,6 +192,7 @@ export default function (selector = '.lozad', options = {}) {
markAsLoaded(element)
loaded(element)
},
observer
observer,
mutationObserver
}
}

0 comments on commit 146b6ba

Please sign in to comment.