所提供的程式碼範例是以 WordPress 系統為基礎來製作的,但這製作的觀念其實移轉到任何系統都可行的。
雖然已經有很多優質的外掛當中會有包含到這一個功能,但個人試用過幾個之後發現對我的網站都會有一點點的小問題,所以最後決定還是自己寫來達到我希望的效果。
在理想請況下,圖片延遲的功能應該在載入圖片後還在可視範圍內的圖片會被下載。
以歡樂夢想國這一篇文章為範例,理想是進入網頁後只有前兩張圖片會被使用者下載,也就是他們 LOGO 跟迎賓木偶兩張。但是在 Jetpack 的圖片延遲功能作用下,其實你還是會一次將所有的圖片下載。
這是因為當使用者進入網站後,在所有的圖片都未下載的情況下,整篇文章都在畫面的可視範圍之內,類似下圖那樣。
所以 Jetpack 的圖片延遲下載的功能,就會判定文章中的每一張圖片都是需要下載的,可是如果你連過去會發現只有前兩張圖片是看的到的(以螢幕解析度 1920 x 1080 為例 )。
所以最後本網站使用的就是我自己寫的來達成圖片延遲載入的功能。
而會寫成這篇文章,當然就是因為我不是用外掛的形式來達成,而是寫在佈景主題當中。
首先開啟佈景主題的 functions.php 檔案,在最後面加入
add_action('template_redirect', 'ry_diy_lazy_image');
function ry_diy_lazy_image() {
ob_start(function($buffer) {
$buffer = preg_replace_callback('#<img([^>]+?)(>(.*?)</\1>|[/]?>)#si', function($matches) {
$matches[1] = preg_replace('/ src=(["|\'])/i', ' data-src=$1', $matches[1]);
$matches[1] = preg_replace('/ srcset=(["|\'])/i', ' data-srcset=$1', $matches[1]);
if( strpos($matches[1], ' class=') === FALSE ) {
$matches[1] .= ' class="need-load-img"';
} else {
$matches[1] = preg_replace('/ class=(["|\'])/i', ' class=$1need-load-img ', $matches[1]);
}
return '<img' . $matches[1] . '><noscript>' . $matches[0] . '</noscript>';
}, $buffer);
return $buffer;
});
}
add_action('wp_enqueue_scripts', 'ry_diy_lazy_image_script');
function ry_diy_lazy_image_script() {
wp_enqueue_script('ry_diy_lazy_image', get_template_directory_uri(). '/js/lazy_image.js', array('jquery'), false, true);
}
接下來在你的佈景主題下新增 js 資料夾,然後在其中加入 lazy_image.js 檔案內容為
jQuery(document).ready(function($) {
$('img').on('showimg', function() {
var $this = $(this);
if( $this.attr('data-src') !== undefined ) {
$this.removeClass('need-load-img')
.attr('src', $this.data('src'))
.attr('srcset', $this.data('srcset'))
.removeAttr('data-src')
.removeAttr('data-srcset');
}
});
$(window).scroll(tryLoadImage).trigger('scroll');
function tryLoadImage() {
var imgList = {};
$('.need-load-img').each(function(){
var $this = $(this),
offsetTop = $this.offset().top;
if( offsetTop < (document.documentElement.scrollTop + document.documentElement.clientHeight) ) {
if( imgList[offsetTop] === undefined ) {
imgList[offsetTop] = [];
}
imgList[offsetTop].push($this);
}
});
var imgListKeys = Object.keys(imgList);
imgListKeys.sort();
for( var i = 0; i < 3; ++i) {
if( imgListKeys[i] !== undefined ) {
imgList[imgListKeys[i]].forEach(function($img) {
$img.trigger('showimg');
});
}
}
if( imgListKeys[i] !== undefined ) {
setTimeout(tryLoadImage, 300);
}
}
});
最後不負責任說明,以上程式碼為從我的佈景主題當中擷取並適度調整而來的,並未完整測試。
所以不保證在所有情況下都可以正常運作。