Typecho 懒加载
在 Caupona 分茶 那篇文章中有着大量较大图片,直接全部加载会导致网页加载缓慢影响阅读,所以尝试为 Typecho 加了一点新功能
原理
在页面载入时,所有图片的 URL 都存储在 img 标签的 data-src 属性中,而 scr 属性则显示占位图:
<img data-src="/images/xxx.png" src="/images/loading.svg">
当图片在可视范围内时,将 data-src 属性的值赋给 src 属性,完成加载:
<img data-src="/images/xxx.png" src="/images/xxx.png">
实现
我们首先要解决的问题是:判断图片是否位于可视区域内
offsetTop
:元素到 offsetParent
1 顶部的距离
offsetHeight
:元素的高度(包含内边距 padding 和边框 border)
scrollTop
:元素内容垂直滚动的像素数
window.innerHeight
:文档可视区域的高度
我们可知:
- 当
document.documentElement.scrollTop + window.innerHeight > document.querySelector("img").offsetTop
的时候图片位于可视区域内或位于可视区域以上 - 当
document.querySelector("img").offsetTop + document.querySelector("img").offsetHeight > document.documentElement.scrollTop
的时候图片位于可视区域内或可视区域以下
当以上两个表达式同时为真时,图片一定位于可视区域内
在解决了图片是否位于可视区域内问题之后,我们就可以开始写 js 了
// 定义函数 lazyLoad,参数 selector 为选择器
function lazyLoad(selector) {
// 获取可视区域高度
var windowHeight = window.innerHeight;
// 获取可视区域以上的高度
var scrollTop = document.documentElement.scrollTop;
// 获取所有需要懒加载的图片
var images = document.querySelectorAll(selector);
// 使用 forEach() 遍历所有需要懒加载的图片
images.forEach((img) => {
// 判断图片是否位于可视区域内
if (scrollTop + windowHeight > img.offsetTop && img.offsetTop + img.offsetHeight > scrollTop) {
// 图片在可视区域内则将 data-src 属性的值赋给 src 属性
img.src = img.getAttribute("data-src");
}
});
}
完成了 lazyLoad 函数后,我们可以使用 document.addEventListener(event, function, useCapture)
方法监听滚动事件:
document.addEventListener("scroll", lazyLoad.call(this, img#lazyLoad));
为了能让浏览者进入页面后可以直接看到可视区域内的图片,需要使用 window.onload
在页面加载完成后执行一次 lazyLoad 函数:
window.onload = function() {
lazyLoad("img");
document.addEventListener("scroll", lazyLoad.bind(this, "img"));
}
修改 Typecho
我们主要需要修改的是 ~/var/Utils/HyperDown.php
中 parseInline
函数
找到下面两部分:
return $self - > makeHolder(
"<img src=\"{$url}\" alt=\"{$escaped}\" title=\"{$escaped}\">"
);
$result = isset($self - > _definitions[$matches[2]]) ?
"<img src=\"{$self->_definitions[$matches[2]]}\" alt=\"{$escaped}\" title=\"{$escaped}\">"
: $escaped;
将 img 标签的 src 属性值修改成占位图并添加 data-src 属性:
return $self - > makeHolder(
"<img data-src=\"{$url}\" src=\"https://xxx.com/loading.svg\" alt=\"{$escaped}\" title=\"{$escaped}\">"
);
$result = isset($self - > _definitions[$matches[2]]) ?
"<img data-src=\"{$self->_definitions[$matches[2]]}\" src=\"https://xxx.com/loading.svg\" alt=\"{$escaped}\" title=\"{$escaped}\">"
: $escaped;
之后在你的外观的 footer.php
中的合适位置添加 js:
// 定义函数 lazyLoad,参数 selector 为选择器
function lazyLoad(selector) {
// 获取可视区域高度
var windowHeight = window.innerHeight;
// 获取可视区域以上的高度
var scrollTop = document.documentElement.scrollTop;
// 获取所有需要懒加载的图片
var images = document.querySelectorAll(selector);
// 使用 forEach() 遍历所有需要懒加载的图片
images.forEach((img) => {
// 判断图片是否位于可视区域内
if (scrollTop + windowHeight > img.offsetTop && img.offsetTop + img.offsetHeight > scrollTop) {
// 图片在可视区域内则将 data-src 属性的值赋给 src 属性
img.src = img.getAttribute("data-src");
}
});
}
window.onload = function() {
lazyLoad("img");
document.addEventListener("scroll", lazyLoad.bind(this, "img"));
}
还要记得修改外观其他图片的 img 标签
最后,在后台评论设置中的“允许使用的HTML标签和属性”追加一条:<img class data-src src alt title>
如果只需要正文和评论的图片懒加载可以在刚刚修改的 ~/var/Utils/HyperDown.php
里为 img 标签加上 class,修改 js 选择器选择指定的图片
注意
如果你使用了 Smilies 插件(https://github.com/jzwalk/Smilies)请注意修改此插件 showsmilies
函数代码,插件在允许评论区显示表情图片的操作会为 commentsHTMLTagAllowed
追加一个 <img> 标签,你在评论设置中放行的 HTML 标签会被覆盖
/**
* 解析表情图片
*
* @access public
* @param string $content 评论内容
* @return string
*/
public static function showsmilies($content,$widget,$lastResult)
{
$content = empty($lastResult) ? $content : $lastResult;
$options = Helper::options();
//允许图片标签
$options->commentsHTMLTagAllowed .= '<img src="" alt="" style=""/>';
$archive = $widget instanceof Widget_Archive;
if ($widget instanceof Widget_Abstract_Comments || $archive && $options->plugin('Smilies')->postmode) {
$arrays = self::parsesmilies($archive);
$content = str_replace($arrays['2'],$arrays['3'],$content);
}
return $content;
}
- 分类:技术
好厉害!
icon_zhaji.png很有用!