Daily learning summary, to build a wheel to measure the effect of learning
Introduction to the
Image lazy loading is a web page optimization technique within the scope. As a network resource, images occupy network resources just like ordinary static resources when they are requested. Loading all images on the entire page at one time greatly increases the loading time of the first screen of the page. In order to solve this problem, by cooperating with the front and back ends, the image is loaded only when it appears in the current window of the browser. The technology to reduce the number of requests for the first screen image is called “image lazy loading”.
The effect
Three solutions are introduced
1. Browser native loading
The loading property allows the browser to delay loading off-screen images and iframes until the user scrolls the page near them. Loading supports three values:
lazy
: lazy loading.eager
: Load immediately.auto
: It is up to the browser to decide whether to lazily load.
One line of code
<! -- Loading in visual range --><img src="./demo.png" loading="lazy" alt="demo" /><! Load the image immediately --><img src="./demo.png" loading="eager" alt=".."/><! The browser decides whether to lazily load images.<img src="./demo.png" loading="auto" alt=".."/><! -- iframe --><iframe src="player.html" loading="lazy"></iframe>
Copy the code
Note: You need to set the width and height of the image
img {
width: 300px;
height: 300px;
}
Copy the code
Knock key: compatibility, basically in addition to Chrome, are not compatible ðŸ˜
2. getBoundingClientRect + data-src
Core code: determine the visual range of conditions: the rect. Top < document. DocumentElement. ClientHeight
const rect = imageElement.getBoundingClientRect() // Load the image when it appears in the window
if(rect.top < document.documentElement.clientHeight) { }
Copy the code
Rect. bottom is different from right and heingt in rect.right and position
- The SRC of the IMG tag is set to the thumbnail or not set to SRC, and then customize a property. Value is the address of the actual image or the original image, and defines a class name to indicate that the image needs to be lazily loaded (such as lazy-image in the following example). Data-src is set visually to img.src:
<img data-src="demo1.png" class="lazy-image"/>
/ / CSS
.lazy-image {
background: url('.. /loading.gif') no-repeat center;
}
Copy the code
2. After the page is loaded, we need to get the set of elements of all images that need lazy loading and determine whether they are in the visible area. If so, set the SRC attribute value of the element to the address of the real image.
/ / getBoundingClientRect scheme
initImageShow() {
// A collection of images that need lazy loading
let len = this.lazyImages.length
for (let i = 0; i < len; i++) {
const lazyImage = this.lazyImages[i]
const rect = lazyImage.getBoundingClientRect()
// Load the image when the image appears in the window
if (rect.top < document.documentElement.clientHeight) {
// Real address
lazyImage.src = lazyImage.dataset.src
// Remove the display
this.lazyImages.splice(i, 1)
len--
i--
// Remove the scroll event listener if all loads are complete
if (this.lazyImages.length === 0) {
document.removeEventListener('scroll'.this._throttleFn)
}
}
}
}
Copy the code
3. Windows IntersectionObserver API
Alternatively, IntersectionObserver can be used to determine whether the IntersectionObserver is within the visible area
/ / IntersectionObserver scheme
initObserverShow() {
const lazyObserver = new IntersectionObserver((entries, observer) = > {
entries.forEach((entry, index) = > {
// If the element is visible
if (entry.isIntersecting) {
const lazyImage = entry.target
// Set the real image address of img to data-src
lazyImage.src = lazyImage.dataset.src
lazyObserver.unobserve(lazyImage)
}
})
})
// Listen on each lazeImage
this.lazyImages.forEach(function(lazyImage) {
lazyObserver.observe(lazyImage)
})
}
Copy the code
Looking at browser compatibility, there’s basically nothing wrong with not considering IE
Wheel making application
LazyLoad Class
export default class LazyImage {
constructor(selector) {
// nodeList class array
this.lazyImages = Array.from(document.querySelectorAll(selector))
this.init()
}
init() {
// IntersectionObserver determines whether the image appears in the visible area
if(! ('IntersectionObserver' in window)) {
this.initObserverShow()
} else {
this.initImageShow()
// Add a throttling function
this._throttleFn = this.throttle(this.initImageShow)
document.addEventListener('scroll'.this._throttleFn)
}
}
/ / getBoundingClientRect scheme
initImageShow() {
let len = this.lazyImages.length
for (let i = 0; i < len; i++) {
const lazyImage = this.lazyImages[i]
const rect = lazyImage.getBoundingClientRect()
// Load the image when the image appears in the window
if (rect.top < document.documentElement.clientHeight) {
// Real address
lazyImage.src = lazyImage.dataset.src
// Remove the display
this.lazyImages.splice(i, 1)
len--
i--
// Remove the scroll event listener if all loads are complete
if (this.lazyImages.length === 0) {
document.removeEventListener('scroll'.this._throttleFn)
}
}
}
}
/ / IntersectionObserver scheme
initObserverShow() {
const lazyObserver = new IntersectionObserver((entries, observer) = > {
entries.forEach((entry, index) = > {
// If the element is visible
if (entry.isIntersecting) {
const lazyImage = entry.target
// Set the real image address of img to data-src
lazyImage.src = lazyImage.dataset.src
lazyObserver.unobserve(lazyImage)
}
})
})
// Listen on each lazeImage
this.lazyImages.forEach(function(lazyImage) {
lazyObserver.observe(lazyImage)
})
}
/ * * * *@param {function} func
* @param {*Number} delay
* @param {*Number} immediate
*/
throttle(func, delay = 15, immediate = 30) {
let timeout = null
let context = this
return function() {
let args = arguments
timeout && clearTimeout(timeout)
// Whether to execute immediately
if (immediate) {
// If yes, the timeout command is executed after delay seconds
letcallNow = ! timeout timeout =setTimeout(function(){
timeout = null
}, delay)
callNow && func.apply(context, args)
} else {
timeout = setTimeout(function() {
func.apply(context, args)
}, delay)
}
}
}
}
Copy the code
use
<img class="lazy-image" :data-src="item" alt="..." />
new LazyImage('.lazy-image')
Copy the code
. Lazy-image Enables background loading
V – lazy Vue instructions
lazyImage.js
// Introduce the default image
import loadingImg from '@/assets/loading.gif'
let timer = null
// Create a listener
const observer = new IntersectionObserver((entries) = > {
"// entries are a collection of all monitored objects
entries.forEach(entry= > {
// Emitted when the monitored element reaches the threshold and no image is loaded.
console.log('entry.target', entry.target.isLoaded)
if (entry.isIntersecting || entry.intersectionRatio > 0) {
if(! entry.target.isLoaded) {const lazyImage = entry.target
// Set the real image address of img to data-src
lazyImage.src = lazyImage.dataSrc
observer.unobserve(lazyImage)
}
}
})
})
export default {
// insert bind
// Common: DOM insertions are called, bind precedes inserted
// Different points:
// Bind has a null parent
// Inserted The parent node exists.
// Bind is called before the DOM tree is drawn, and INSERTED is called after the DOM tree is drawn
// Insert The element is inserted into the page, and you can get the DOM element's position directly
inserted(el, binding, vnode) {
clearTimeout(timer)
// Display the default image during initialization
el.src = loadingImg
// Bind the image address to the DOM
el.dataSrc = binding.value
observer.observe(el)
// Stop listening when the component is uninstalled
const vm = vnode.context
timer = setTimeout(() = > {
vm.$on('hook:beforeDestroy'.() = > {
observer.disconnect()
})
}, 20)},// Image update triggered
update(el, binding) {
el.isLoaded = false
el.dataSrc = binding.value
}
}
Copy the code
use
Vue.directive('imgLazy', lazyImage)
<img class="lazy-image" v-imgLazy="item" alt="..." />
Copy the code
Refer to the link
-
Developer.mozilla.org/zh-CN/docs/…
-
www.ruanyifeng.com/blog/2016/1…