แนวทางในการเพิ่มความเร็ว การแสดงลิสรายการหรือโหลดรูปภาพจำนวนมากๆ

เขียนเมื่อ 6 ปีก่อน โดย Ninenik Narkdee
html5 jquery lazyload

คำสั่ง การ กำหนด รูปแบบ ตัวอย่าง เทคนิค ลูกเล่น การประยุกต์ การใช้งาน เกี่ยวกับ html5 jquery lazyload

ดูแล้ว 7,506 ครั้ง


เนื้อหานี้จะเป็นแนวทางอย่างง่าย ในการประยุกต์ใช้งาน jquery และ html สำหรับใช้ในการเพิ่มความเร็ว
และลดการทำงานของ server รองรับกรณีมีผู้ใช้จำนวนมาก เมื่อมีการโหลดหน้ารายการที่มีรูปภาพจำนวน
มาก หรือหน้ารายการที่แสดงรูปภาพขนาดปกติจำนวนมากๆ 
    เราจะลองจากรูปแบบการใช้งานอย่างง่าย สมมติหน้านั้นๆ มีการแสดงรายการรูปภาพจำนวนมาก ดังนี้
 
ไฟล์ demo.php
 
<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> 
    <title>Document</title> 
    <link rel="stylesheet" href="https://unpkg.com/bootstrap@4.1.0/dist/css/bootstrap.min.css" >
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.7/css/all.css">   
    <style type="text/css">
    body{
        font-family: system-ui,-apple-system,BlinkMacSystemFont,Helvetica Neue,Helvetica,sans-serif;
        font-size: 14px;
    }
    </style>
</head>
<body>
 
<div class="container">
    <?php for($i=1;$i<=50;$i++){?>    
        <div>
        <img src="https://c2.staticflickr.com/2/1770/42470454165_d6fb92de25_o.jpg?time=<?=time()+$i?>" />
        </div>
	<?php } ?>        
</div>   
   
<script src="https://unpkg.com/jquery@3.3.1/dist/jquery.min.js"></script>
<script type="text/javascript">
$(function(){

     
});
</script>
</body>
</html>
 
จากโค้ดตัวอย่าง จะเห็นว่า เราใช้การวนลูปด้วย for เพื่อจำลองรายการรูปภาพจำนวนมาก โดยรูปภาพใน tag <img> เราได้เพิ่มส่วนของ
 
?time=<?=time()+$i?>
ต่อท้ายเข้าไป เพื่อจำลองให้แต่ละรูปคือรูปใหม่ ที่ต่างกัน แต่เวลาใช้จริงไม่ต้องกำหนดส่วนนี้ ดังนั้น เมื่อมีการโหลดหน้านี้ขึ้นมา รูปจำนวนทั้งหมด 50 รูปจะทำการโหลดมาพร้อมๆ กัน ซึ่ง ถ้ามีผู้ใช้จำนวนมากๆ ก็จะทำให้ server ของเราทำงานหนัก เพราะมีจำนวนการ request จำนวนมากเข้ามา
 


 
 


 
 
รูปแรกเป็นรายการรูปที่แสดงจำนวนมากต่อกันยาวลงไปเรื่อยๆ จำนวนทั้งหมด 50 รายการ รูปที่สอง จะเห็นว่ามีจำนวน request ที่เป็นรูปภาพ
จำนวนทั้งหมด 50 รายการ จากรายการทั้งหมด 55 รายการ และเมื่อมีผู้ใช้จำนวนมากๆ จำนวนการ request ก็จเพิ่มขึ้นเข้าไปอีก
 
แนวทางของเราก็คือ เราจะให้แสดงรูปเฉพาะที่จะสามารถมองเห็นได้ ในหน้าจอนั้นๆ ก่อน และเมื่อเลือน scrollbar ก็จะค่อยๆ ไปดึงรูปเพิ่มเติม
ซึ่งวิธีการแบบนี้ จะทำให้รูป จะโหลดมาเฉพาะส่วนที่เราต้องการแสดง ไม่ดึงทั้งหมด 50 รายการ เพราะบางครั้ง ผู้ใช้อาจจะแค่เปิดผ่านมาหน้านี้
ไม่ได้ต้องการดูรายการทั้งหมดก็ได้ 
 
วิธีการ เริ่มต้น ให้เราเพิ่ม class ให้กับ รูปที่เราต้องการ ในที่นี้เราจะใช้ชื่อว่า async_img_load
 
<img class="async_img_load"  />
 
ถ้ารูปนั้นมี css class เดิมอยู่แล้ว ให้เราเพิ่ม class ที่เราต้องการต่อเข้าไปดังนี้
 
<img class="old_css class async_img_load"  />
 
จากนั้น ในส่วนของ src ที่อ้างอิงตำแหน่งของไฟล์รูป ให้เราเปลี่ยนเป็น data attribute แทน ชื่อว่า data-fsrc จะได้เป็น
 
<?php for($i=1;$i<=50;$i++){?>    
	<div>
	<img class="async_img_load" data-fsrc="https://c2.staticflickr.com/2/1770/42470454165_d6fb92de25_o.jpg?time=<?=time()+$i?>" />
	</div>
<?php } ?>        
   
 
เมื่อเราทดสอบโหลดหน้านี้อีกครั้ง จะพบว่าไม่มีการโหลดรูปภาพ มาแสดง request ของรูปภาพเท่ากับ 0
 


 
 
ต่อไปเป็นส่วนของ javascript เราใช้ jquery โดยในส่วนนี้ เราจะกำหนดจำนวนรายการรูปเริ่มต้นที่ต้องการแสดงเมื่อโหลดครั้งแรก และ
กำหนดให้แสดงเพิ่มอีกเมื่อเลื่อน scrollbar ลงมาด้านล่างสุดของจอภาพ คำอธิบายแสดงในโค้ด
 
var _init_img_load = 15; // กำหนดจำนวนเริ่มต้นที่ต้องการแสดง
$(".async_img_load").hide(); // ซ่อนทั้งหมดก่อน
$(".async_img_load:lt("+_init_img_load+")").show(); // แสดงเฉพาะจำนวนที่เรากำหนด
$(".async_img_load:lt("+_init_img_load+")").each(function(i,k){ // วนลูปในรูปที่เรากำหนด
    var img_fsrc = $(k).data("fsrc"); // ดึงค่า path ของไฟล์ของรูป
    $(k).attr("src",img_fsrc); // แสดงรูป
});

// ตรวจสอบ event การ scroll 
 $(window).scroll(function(){  
    // ถ้า scroll ลงมาล่างสุด
    if($(window).scrollTop() + $(window).height() == $(document).height()) {
          _init_img_load+=15; // ให้แสดงรูปภาพอีก 15 รูป
            $(".async_img_load:lt("+_init_img_load+")").show();// แสดงเฉพาะจำนวนที่เรากำหนด
            $(".async_img_load:lt("+_init_img_load+")").each(function(i,k){// วนลูปในรูปที่เรากำหนด
                var img_fsrc = $(k).data("fsrc"); // ดึงค่า path ของไฟล์ของรูป
                $(k).attr("src",img_fsrc); // แสดงรูป
            });	  
    }		 
 });     	
 
 
เรามาดูผลลัพธ์การ request ข้อมูลตามลำดับ ดังนี้
 

 
 

 
 

 
 


 
 
จะเห็นว่า เริ่มต้น จะมีการดึงรูปมาแสดงเท่ากับ 15 รูป หรือ 15 request และเมื่อเราเลื่อน scrolbar ลองมาเรื่อยๆ จำนวนรุปก็จะแสดงเพิ่มเข้ามา
ตามจำนวน request ที่ค่อยๆ เพิ่มขึ้น จนแสดงรูปทั้งหมด 50 รูป  ลักษณะการทำงานแบบนี้จะช่วยให้ลดการทำงานของ server ได้เป็นอย่างดี
รวมถึงทำให้ผู้ใช้สามารถโหลดหน้าเว็บได้เร็วขึ้น เพราะไม่ต้องไปทำการดึงรายการทั้งหมดมาแสดงตั้งแต่แรก นอกจากนั้น แนวทางนี้ สามารถ
นำไปประยุกต์ สำหรับการโหลดข้อมูลเพิ่มเติมคล้ายๆ กับการใช้งาน ajax ได้
 
การกำหนดด้วยวิธีข้างต้น จะเห็นว่า รูปเมื่อเริ่มต้น จะไม่มี src หรือไฟล์รูปใดๆ แสดง บางครั้ง browser อาจจะขึ้นเป็นรูปกากบาท ดังนั้น เรา
สามารถปรับเพิ่มเติม ให้การแสดงดูเรียบร้อยขึ้น โดยการกำหนด src ให้กับค่าเริ่มต้นเป็นรูปพื้นหลังสีขาว ดังนี้ได้
 
<img class="async_img_load" data-fsrc="https://c2.staticflickr.com/2/1770/42470454165_d6fb92de25_o.jpg?time=<?=time()+$i?>" 
src="my_white_background.png" />
 
สำหรับการกำหนดจำนวนรายการที่จะแสดงเริ่มต้น และการกำหนดจำนวนรายการที่จะแสดงเพิ่มเติม เมื่อเข้าเงื่อนไขการ scroll จะขึ้นอยู่กับว่า
เนื้อหาในส่วนของรูปนั้น แสดงเต็มหน้าจอเมื่อยังไม่เลื่อน scroll แล้วหรือไม่ อย่างไรก็ตาม บางครั้ง เราก็อาจจะกำหนดให้แสดงแบบ มากกว่า
ปกติก็ได้ เพือให้การใช้งานสะดวก เพราะถ้า เรากำหนดค่าน้อยเกินไป บางครั้งผู้ใช้ อาจจะเลื่อนหลายครั้ง กว่ารายการจะแสดงหมด ทำให้ได้รับ
ประสบการณ์การใช้งานที่ไม่ดีพอ
 
ในเงื่อนไขการเลื่อน scroll นั้น โค้ดข้างต้น เรากำหนดว่า เมื่อผู้ใช้เลื่อนลงมาล่างสุดหรือชิดขอบล่าง แต่เราสามารถกำหนดให้ ผู้ใช้สามารถที่
จะเลื่อนมาถึงตำแหน่ง ใดๆ ก่อนถึงขอบล่างก็ได้ เช่น บางกรณีขอบด้านล่าง อาจจะเป็นส่วนเนื้อหาที่ไม่เกี่ยวกับรูป เราก็ควรจะให้ผู้ใช้เลื่อนถึง
ตำแหน่ง ที่ไม่ใช่ขอบล่าง โดยปรับส่วนของเงื่อนไขการ scroll เป็นดังนี้
 
// เมื่อเลื่อนลงมาก่อนถึงขอบล่าง 100 px 
if($(window).scrollTop() + $(window).height() > $(document).height() - 100) {
   // 
}	
 
การกำหนดจำนวนความห่างจากขอบล่าง โดยค่ายิ่งมาก ก็หมายความว่า ยิ่งห่างจากขอบล่าง อย่างในตัวอย่าง เรากำหนด 100 
ก็หมายถึง ก่อนถึงขอบล่าง 100px ให้แสดงรายการเพิ่ม เมื่อมีการเลื่อน scroll มาถึงจุดนี้  หรือสมมติว่าด้านล่างของเว็บไซต์เรา
มีส่วนของเนื้อหาเกี่ยวกับที่อยู่ เบอร์โทร หรืออื่นๆ ที่มาคั่นอยู่ด้านล่าง เราก็ต้อง บวกค่าเข้าไปในส่ว่นของการกำหนดความห่างจากขอบล่างด้วย
 
 
ตอ่ไป เราจะมาประยุกต์เพิ่ม กรณีรูปของเรามีส่วนของเนื้อหาอื่นมาคั่น หรือล้อมรอบด้วยข้อมูลอืนๆ ไม่ได้แสดงเฉพาะรูปอย่างเดียว ดังตัวอย่าง
โค้ดดังนี้
 
<div class="container">
    <?php for($i=1;$i<=50;$i++){?>    
        <div>
        <img class="async_img_load" data-fsrc="https://c2.staticflickr.com/2/1770/42470454165_d6fb92de25_o.jpg?time=<?=time()+$i?>" />
        <div class="bg-light">
        <?=$i?>
        เนื้อหาเพิ่มเติม<br>
        เนื้อหาเพิ่มเติม<br>
        เนื้อหาเพิ่มเติม<br>        
        </div>
        </div>
	<?php } ?>        
</div>   
 
เรามาดูผลลัพธ์ ก่อนปรับในส่วนของ javascript ให้เราเลือนไปที่รูปที่ 15
 


 
 
จะเห็นว่าส่วนของเนื้อหาข้อมูล ที่ไม่ใช่รูปของรายการที่ 16 ขึ้นไปแสดงอยู่ เพราะเราไม่ได้กำหนดการซ่อนรายการ ที่ครอบคลุมส่วนของเนื้อหา
เพิ่มเติมที่เพิ่มเข้ามา ในกรณีดังนี้ เราต้องประยุกต์ เพิ่มเติมดังนี้
 
ให้เรากำหนด css class คลุมส่วนของ element ที่รวมรูปและเนื้อหาไว้ด้วยกัน จะได้เป็นดังนี้
 
<div class="container">
    <?php for($i=1;$i<=50;$i++){?>    
        <div class="wrap_async_img_load">
        <img class="async_img_load" data-fsrc="https://c2.staticflickr.com/2/1770/42470454165_d6fb92de25_o.jpg?time=<?=time()+$i?>" />
        <div class="bg-light">
        <?=$i?>
        เนื้อหาเพิ่มเติม<br>
        เนื้อหาเพิ่มเติม<br>
        เนื้อหาเพิ่มเติม<br>        
        </div>
        </div>
	<?php } ?>        
</div>   
 
เรากำหนด css class ชื่อ "wrap_async_img_load" ที่รวมรูปและเนื้อหาเพิ่มเติมไว้ด้วยกัน
 
จากนั้นให้ปรับส่วนของ javascript เป็นดังนี้
 
 
var _init_img_load = 15; // กำหนดจำนวนเริ่มต้นที่ต้องการแสดง
$(".wrap_async_img_load").hide(); // ซ่อนทั้งหมดก่อน
$(".wrap_async_img_load:lt("+_init_img_load+")").show(); // แสดงเฉพาะจำนวนที่เรากำหนด
$(".wrap_async_img_load:lt("+_init_img_load+") img").each(function(i,k){ // วนลูปในรูปที่เรากำหนด
    var img_fsrc = $(k).data("fsrc"); // ดึงค่า path ของไฟล์ของรูป
    $(k).attr("src",img_fsrc); // แสดงรูป
});

// ตรวจสอบ event การ scroll 
 $(window).scroll(function(){  
    // ถ้า scroll ลงมาล่างสุด
    if($(window).scrollTop() + $(window).height() == $(document).height()) {
          _init_img_load+=15; // ให้แสดงรูปภาพอีก 15 รูป
            $(".wrap_async_img_load:lt("+_init_img_load+")").show();// แสดงเฉพาะจำนวนที่เรากำหนด
            $(".wrap_async_img_load:lt("+_init_img_load+") img").each(function(i,k){// วนลูปในรูปที่เรากำหนด
                var img_fsrc = $(k).data("fsrc"); // ดึงค่า path ของไฟล์ของรูป
                $(k).attr("src",img_fsrc); // แสดงรูป
            });	  
    }		 
 });   
 
 
โดยเราเปลี่ยนจาก "async_img_load" เป็น "wrap_async_img_load" และในส่วนของบรรทัด วนลูป เราเพิ่ม img เข้าไปเพื่ออ้างอิง
ว่าเป็นรูปที่อยู่ใน "wrap_async_img_load" อีกที 
 
$(".async_img_load:lt("+_init_img_load+")").each(function(i,k){
// เปลี่ยนเป็น
$(".wrap_async_img_load:lt("+_init_img_load+") img").each(function(i,k){

 
เท่านี้ ส่วนของเนื้อหาที่ 16 ก็จะแสดงพร้อมๆ กับรูป เมื่อเลื่อน scroll เข้าเงื่อนไข
 
ก่อนจบ ขอเพิ่มเติม อีกกรณี สมมติว่าเราแสดงรูปแบบใช้เป็น พื้นหลัง จะสามารถใช้วิธีนี้ได้ หรือไม่ คำตอบคือ ได้ แต่ต้องปรับเป็นดังนี้
 
<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> 
    <title>Document</title> 
    <link rel="stylesheet" href="https://unpkg.com/bootstrap@4.1.0/dist/css/bootstrap.min.css" >
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.7/css/all.css">   
    <style type="text/css">
    body{
        font-family: system-ui,-apple-system,BlinkMacSystemFont,Helvetica Neue,Helvetica,sans-serif;
        font-size: 14px;
    }
	.pic_preview{height:auto;padding-bottom:100%;background-size:cover;background-position:center;}
    </style>
</head>
<body>
 
<div class="container">
    <?php for($i=1;$i<=50;$i++){?>    
        <div class="wrap_async_img_load">
        <img class="async_img_load" data-fsrc="https://c2.staticflickr.com/2/1770/42470454165_d6fb92de25_o.jpg?time=<?=time()+$i?>"
        style="width:170px;height:120px;background-size:cover;background-position:center;" />
        <div class="bg-light">
        <?=$i?>
        เนื้อหาเพิ่มเติม<br>
        เนื้อหาเพิ่มเติม<br>
        เนื้อหาเพิ่มเติม<br>        
        </div>
        </div>
	<?php } ?>        
</div>   
   
<script src="https://unpkg.com/jquery@3.3.1/dist/jquery.min.js"></script>
<script type="text/javascript">
$(function(){
	
	var _init_img_load = 15; // กำหนดจำนวนเริ่มต้นที่ต้องการแสดง
	$(".wrap_async_img_load").hide(); // ซ่อนทั้งหมดก่อน
	$(".wrap_async_img_load:lt("+_init_img_load+")").show(); // แสดงเฉพาะจำนวนที่เรากำหนด
	$(".wrap_async_img_load:lt("+_init_img_load+") img").each(function(i,k){ // วนลูปในรูปที่เรากำหนด
		var img_fsrc = $(k).data("fsrc"); // ดึงค่า path ของไฟล์ของรูป
		$(k).css("background-image", "url("+img_fsrc+")"); // แสดงรูป
	});
	
	// ตรวจสอบ event การ scroll 
     $(window).scroll(function(){  
	 	// ถ้า scroll ลงมาล่างสุด
		if($(window).scrollTop() + $(window).height() == $(document).height()) {
			  _init_img_load+=15; // ให้แสดงรูปภาพอีก 15 รูป
				$(".wrap_async_img_load:lt("+_init_img_load+")").show();// แสดงเฉพาะจำนวนที่เรากำหนด
				$(".wrap_async_img_load:lt("+_init_img_load+") img").each(function(i,k){// วนลูปในรูปที่เรากำหนด
					var img_fsrc = $(k).data("fsrc"); // ดึงค่า path ของไฟล์ของรูป
					$(k).css("background-image", "url("+img_fsrc+")"); // แสดงรูป
				});	  
		}		 
     });     	
     
});
</script>
</body>
</html>
 
หวังว่าเนื้อหานี้จะเป็นแนวทาง นำไปประยุกต์ใช้งานเพิ่มเติมต่อไปได้ ดู DEMO ด้านล่าง
DEMO 1 กรณีรูปอย่างเดียว
DEMO 2 กรณีรูปพร้อมเนื้อหา
DEMO 3 กรณีรูปเป็นพื้นหลัง






กด Like หรือ Share เป็นกำลังใจ ให้มีบทความใหม่ๆ เรื่อยๆ น่ะครับ











URL สำหรับอ้างอิง





คำแนะนำ และการใช้งาน

สมาชิก กรุณา ล็อกอินเข้าระบบ เพื่อตั้งคำถามใหม่ หรือ ตอบคำถาม สมาชิกใหม่ สมัครสมาชิกได้ที่ สมัครสมาชิก


  • ถาม-ตอบ กรุณา ล็อกอินเข้าระบบ
  • เปลี่ยน


    ( หรือ เข้าใช้งานผ่าน Social Login )







เว็บไซต์ของเราให้บริการเนื้อหาบทความสำหรับนักพัฒนา โดยพึ่งพารายได้เล็กน้อยจากการแสดงโฆษณา โปรดสนับสนุนเว็บไซต์ของเราด้วยการปิดการใช้งานตัวปิดกั้นโฆษณา (Disable Ads Blocker) ขอบคุณครับ