当前位置:网站首页>Lazy loading of pictures
Lazy loading of pictures
2022-07-25 16:01:00 【Gai Yuexi's boyfriend outside the circle (kuaixi)】
Catalog
Judge whether the picture is in the visible area
Scroll event callback function
Only record pictures that have not been loaded
demand
There is no life at work , So write a lazy pit record . Demand is the most common image lazy loading , Use an array to store the addresses of all pictures , Wait until the picture appears in the visible area before setting it src attribute , Only in this way can the picture be loaded .
Thought analysis
Judge whether the picture is in the visible area
This is the most critical place , Only by correctly judging the visual area in the picture can the picture be loaded correctly .img It's a picture. ,parent Is its container , My specific judgment formula is as follows :
img.offsetHeight + img.offsetTop > parent.scrollTop && img.offsetTop < parent.scrollTop + parent.clientHeight
The formula is divided into two parts . The first part is to judge whether the picture can enter the visible area , The second part is to judge whether the picture leaves the visible area . Its logic can be illustrated , No more details .
Picture settings
For a picture , We didn't want to load it at first , So use background Set the background picture as a placeholder . also , We also need to save its address on it , For easy loading . Consider the existence of elements dataset in , such as img.dataset.src. such , For each picture , The following settings should be made :
<img data-src="https://acg.toubiec.cn/random.php?1" class="lazy">This is using native HTML Written , If the vue And other frameworks can directly traverse the array address to generate img. We still need to give img The tag specifies the class name , I write as lazy. And then to lazy Class to set a unified style :
.lazy {
width: 400px;
height: 400px;
background-image: url("https://cn.vuejs.org/images/logo.svg");
background-repeat: no-repeat;
background-size: contain;
margin-bottom: 50px;
}Here, the background is used to realize the occupation ,background-image Is the default picture . If the picture is set later src, You can cover the background .
Parent element Settings
I simply use a class named container Of div Picture of the package :
<div class="container">
<img data-src="https://acg.toubiec.cn/random.php?1" class="lazy">
<img data-src="https://acg.toubiec.cn/random.php?2" class="lazy">
<img data-src="https://acg.toubiec.cn/random.php?3" class="lazy">
<img data-src="https://acg.toubiec.cn/random.php?4" class="lazy">
<img data-src="https://acg.toubiec.cn/random.php?5" class="lazy">
<img data-src="https://acg.toubiec.cn/random.php?6" class="lazy">
</div>And then to container Class setting style :
.container {
background-color: floralwhite;
width: 60vw;
height: 100%;
overflow-y: auto;
margin: 0 auto;
display: flex;
flex-direction: column;
align-items: center;
}such , All pictures are arranged horizontally in the middle .
Scroll event callback function
To achieve lazy loading , You must listen for scrolling events , Determine which pictures are in the visible area in the monitoring function , Then load it . Just now we have realized the logic of judging whether the picture is in the visible area , Now the callback function that encapsulates the scrolling event :
// Judge whether the picture is in the visible area
// parent: Parent element img: Picture elements
function ifInview(parent, img) {
return img.offsetHeight + img.offsetTop > parent.scrollTop && img.offsetTop < parent.scrollTop + parent.clientHeight
}
// Callback function for scrolling Events
function load() {
console.log('load')
let parent = document.getElementsByClassName('container')[0];
let img_list = document.getElementsByClassName('lazy');
for (let i = 0; i < arr.length; i++) {
let img = img_list[i];
if (ifInview(parent, img)) {
img.src = img.dataset.src;
}
}
}Then bind the parent element scroll Event monitoring :
let container = document.getElementsByClassName('container')[0]
container.addEventListener('scroll', load);Be accomplished .
problem
After writing these codes, I found , Scrolling does not trigger scroll Callback function for event . Why is that ?
Check code , Find the problem : stay container in , Set its height to 100%.container The height of is inherited from body,body Inherited from html.html It contains 6 A picture , So it has 6 The height of the picture , therefore container It has 6 The height of the picture . therefore , about container Speaking of , It doesn't overflow at all , So it's overflow-y:auto It doesn't work at all !!!
The solution is , to container Set a fixed height , I set as 100vh.
After setting, it is found that it still cannot be triggered . Read again , Find out I'm right container Used flex Layout , This causes the height of the child element to be limited to the parent element , Cannot exceed the height of the parent element , Naturally, it cannot trigger scroll event . therefore , Have to give up flex Layout . I will img Set to block element , Then center them , The effect is the same .
The changed code :
.container {
background-color: floralwhite;
width: 60vw;
height: 100vh;
overflow-y: scroll;
margin: 0 auto;
}
.lazy {
width: 400px;
height: 400px;
display: block;
background-image: url("https://cn.vuejs.org/images/logo.svg");
background-repeat: no-repeat;
background-size: contain;
background-position: center;
margin: 20px auto;
}Try it again , It was successful .
Optimize
After the realization of basic functions , It can be optimized .
Only record pictures that have not been loaded
First of all, consider a point , Each scroll event calls load function . however , If all the pictures have been loaded by now , There is no need to call it . therefore , You need to record pictures that have not been loaded yet , The next call only needs to traverse them . So , I save the obtained sub element list load Outside the function , And then every time load When the function is called , Remove the loaded image . To achieve removal , I use Array.from Convert a pseudo array of child elements into an array , So you can call splice The method .
The improved code is as follows :
// Get the parent element and all child elements
let parent = document.getElementsByClassName('container')[0];
// Convert to array
let img_list = Array.from(document.getElementsByClassName('lazy'));
// Callback function for scrolling Events
function load() {
if (!img_list.length) {
return;
}
for (let i = 0; i < img_list.length; i++) {
let img = img_list[i];
if (ifInview(parent, img)) {
img.src = img.dataset.src;
img_list.splice(i, 1)
}
}
}such , Load one picture at a time , It will be removed from the list of child elements . When img_list The length of is 0 when , Will go straight back to .
throttle
Now there's another question , Every time you scroll , Will trigger load function , all too often . therefore , Anti shake or throttling can be adopted , Reduce the number of calls . Here I use throttling . The specific idea is , Encapsulate a method to implement the throttling function , Yes load Carry out throttling packaging , And then put scroll Set the callback function of the event to this throttling function .
The implementation is as follows :
// Throttling function
function throttle(func, delay) {
let last = Date.now();
return function () {
let now = Date.now();
if (now - last < delay) {
return;
}
last = now;
func.apply(window);
}
}
// Get the callback function after throttling
let throttle_load = throttle(load, 500);
let container = document.getElementsByClassName('container')[0]
// Set throttling callback to scroll Callback function for event
container.addEventListener('scroll', throttle_load);Set every 500 Millisecond trigger once , Achieve throttling effect .
Realization effect
I used it here 20 A picture , The effect is more obvious .
Lazy load Demo
summary
When lazy loading is completed , We need to pay attention to these points :
1、 The height of the parent element of the picture cannot be set to 100%
2、 The height of all child elements must exceed that of the parent element , Trigger overflow
3、 The judgment of whether the picture is in the visible area should be accurate
4、 Optimization means such as throttling
Code
Attach simple code . Because I wrote it in my spare time , So it's simpler , There's no complicated logic , I hope the criticism can correct .
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset='UTF-8'>
<meta http-equiv=" X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
.container {
background-color: floralwhite;
width: 60vw;
height: 100vh;
overflow-y: scroll;
margin: 0 auto;
}
.lazy {
width: 400px;
height: 400px;
display: block;
background-image: url("https://cn.vuejs.org/images/logo.svg");
background-repeat: no-repeat;
background-size: contain;
background-position: center;
margin: 20px auto;
}
</style>
</head>
<body>
<div class="container">
<img data-src="https://acg.toubiec.cn/random.php?1" class="lazy">
<img data-src="https://acg.toubiec.cn/random.php?2" class="lazy">
<img data-src="https://acg.toubiec.cn/random.php?3" class="lazy">
<img data-src="https://acg.toubiec.cn/random.php?4" class="lazy">
<img data-src="https://acg.toubiec.cn/random.php?5" class="lazy">
<img data-src="https://acg.toubiec.cn/random.php?6" class="lazy">
<img data-src="https://acg.toubiec.cn/random.php?7" class="lazy">
<img data-src="https://acg.toubiec.cn/random.php?8" class="lazy">
<img data-src="https://acg.toubiec.cn/random.php?9" class="lazy">
<img data-src="https://acg.toubiec.cn/random.php?10" class="lazy">
<img data-src="https://acg.toubiec.cn/random.php?11" class="lazy">
<img data-src="https://acg.toubiec.cn/random.php?12" class="lazy">
<img data-src="https://acg.toubiec.cn/random.php?13" class="lazy">
<img data-src="https://acg.toubiec.cn/random.php?14" class="lazy">
<img data-src="https://acg.toubiec.cn/random.php?15" class="lazy">
<img data-src="https://acg.toubiec.cn/random.php?16" class="lazy">
<img data-src="https://acg.toubiec.cn/random.php?17" class="lazy">
<img data-src="https://acg.toubiec.cn/random.php?18" class="lazy">
<img data-src="https://acg.toubiec.cn/random.php?19" class="lazy">
<img data-src="https://acg.toubiec.cn/random.php?20" class="lazy">
</div>
<script>
// Image address array
let arr = [
"https://acg.toubiec.cn/random.php?1",
"https://acg.toubiec.cn/random.php?2",
"https://acg.toubiec.cn/random.php?3",
"https://acg.toubiec.cn/random.php?4",
"https://acg.toubiec.cn/random.php?5",
"https://acg.toubiec.cn/random.php?6",
"https://acg.toubiec.cn/random.php?7",
"https://acg.toubiec.cn/random.php?8",
"https://acg.toubiec.cn/random.php?9",
"https://acg.toubiec.cn/random.php?10",
"https://acg.toubiec.cn/random.php?11",
"https://acg.toubiec.cn/random.php?12",
"https://acg.toubiec.cn/random.php?13",
"https://acg.toubiec.cn/random.php?14",
"https://acg.toubiec.cn/random.php?15",
"https://acg.toubiec.cn/random.php?16",
"https://acg.toubiec.cn/random.php?17",
"https://acg.toubiec.cn/random.php?18",
"https://acg.toubiec.cn/random.php?19",
"https://acg.toubiec.cn/random.php?20",
];
// Default placeholder picture address
let default_src = "https://cn.vuejs.org/images/logo.svg"
// Judge whether the picture is in the visible area
// parent: Parent element img: Picture elements
function ifInview(parent, img) {
return img.offsetHeight + img.offsetTop > parent.scrollTop && img.offsetTop < parent.scrollTop + parent.clientHeight
}
// Get the parent element and all child elements
let parent = document.getElementsByClassName('container')[0];
// Convert to array
let img_list = Array.from(document.getElementsByClassName('lazy'));
// Callback function for scrolling Events
function load() {
if (!img_list.length) {
return;
}
console.log('load')
for (let i = 0; i < img_list.length; i++) {
let img = img_list[i];
if (ifInview(parent, img)) {
img.src = img.dataset.src;
img_list.splice(i, 1)
}
}
}
// Throttling function
function throttle(func, delay) {
let last = Date.now();
return function () {
let now = Date.now();
if (now - last < delay) {
return;
}
last = now;
func.apply(window);
}
}
// Get the callback function after throttling
let throttle_load = throttle(load, 500);
let container = document.getElementsByClassName('container')[0]
// Set throttling callback to scroll Callback function for event
container.addEventListener('scroll', throttle_load);
</script>
</body>
</html>边栏推荐
- Leetcode - 641 design cycle double ended queue (Design)*
- MySQL乐观锁
- 十字链表的存储结构
- How to solve cross domain problems
- Is there only one lib under JDBC in Seata?
- Data system partition design - Request Routing
- Solve the vender-base.66c6fc1c0b393478adf7.js:6 typeerror: cannot read property 'validate' of undefined problem
- SVD singular value decomposition derivation and application and signal recovery
- Redis分布式锁,没它真不行
- How to realize page inclusion
猜你喜欢

推荐系统-协同过滤在Spark中的实现

Storage structure of cross linked list

JWT diagram

I interviewed 8 companies and got 5 offers in a week. Share my experience

Leetcode - 225 implements stack with queue

十字链表的存储结构

Leetcode - 707 design linked list (Design)

ML - Speech - traditional speech model

Solve the vender-base.66c6fc1c0b393478adf7.js:6 typeerror: cannot read property 'validate' of undefined problem

Leetcode - 641 design cycle double ended queue (Design)*
随机推荐
leetcode:6127. 优质数对的数目【位运算找规律 + 两数之和大于等于k + 二分】
Save the image with gaussdb (for redis), and the recommended business can easily reduce the cost by 60%
Leetcode - 379 telephone directory management system (Design)
Product dynamics - Android 13 high-efficiency adaptation new upgrade
递归菜单查询(递归:自己查自己)
Google Blog: training general agents with multi game decision transformer
MySQL tutorial 66 data table query statement
记得那两句话
LeetCode - 641 设计循环双端队列(设计)*
How Google cloud disk is associated with Google colab
没错,请求DNS服务器还可以使用UDP协议
MySQL - Summary of common SQL statements
Redis分布式锁,没它真不行
The difference between mouseover and mouseenter
Leetcode - 622 design cycle queue (Design)
Data system partition design - partition rebalancing
泰雷兹推出解决方案,助力SAP客户控制云端数据
通用测试用例写作规范
电阻电路的等效变化(Ⅱ)
Record Locks(记录锁)