安知鱼主题 - 一图流渐进式加载教程
本文介绍如何在安知鱼主题下为 Hexo 博客实现图片渐进式加载效果。通过先加载低分辨率并模糊处理的小图,再在后台加载高清大图的方式,可以有效提升页面加载体验,避免加载大图时页面空白或卡顿。
渐进式加载原理:先加载体积小的小图(建议小于100k),对其应用高斯模糊效果,待大图加载完成后替换显示。
效果预览
1. 功能简介
使用渐进式加载技术,可以先展示模糊效果的小图,随后自动切换为高清大图。此方案适用于首页顶部图及一图流背景,提升了视觉体验和加载速度。
2. 操作步骤
本教程分为两部分:
- 首页顶部图渐进式加载
- 首页一图流渐进式加载
2.1 首页顶部图渐进式加载
2.1.1 JS 文件配置 (imgloaded.js
)
在 themes/anzhiyu/source/js/
目录下新建 imgloaded.js
文件,内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
|
class ProgressiveLoad { constructor(smallSrc, largeSrc) { this.smallSrc = smallSrc; this.largeSrc = largeSrc; this.initTpl(); } initTpl() { this.container = document.createElement('div'); this.smallStage = document.createElement('div'); this.largeStage = document.createElement('div'); this.smallImg = new Image(); this.largeImg = new Image(); this.container.className = 'pl-container'; this.smallStage.className = 'pl-img pl-blur'; this.largeStage.className = 'pl-img'; this.container.appendChild(this.smallStage); this.container.appendChild(this.largeStage); this.smallImg.onload = this._onSmallLoaded.bind(this); this.largeImg.onload = this._onLargeLoaded.bind(this); } progressiveLoad() { this.smallImg.src = this.smallSrc; this.largeImg.src = this.largeSrc; } _onLargeLoaded() { this.largeStage.classList.add('pl-visible'); this.largeStage.style.backgroundImage = `url('${this.largeSrc}')`; } _onSmallLoaded() { this.smallStage.classList.add('pl-visible'); this.smallStage.style.backgroundImage = `url('${this.smallSrc}')`; } }
const executeLoad = (config, target) => { const isMobile = window.matchMedia('(max-width: 767px)').matches; const loader = new ProgressiveLoad( isMobile ? config.mobileSmallSrc : config.smallSrc, isMobile ? config.mobileLargeSrc : config.largeSrc ); if (target.children[0]) { target.insertBefore(loader.container, target.children[0]); } loader.progressiveLoad(); };
const config = { smallSrc: '/img/web.jpg', largeSrc: '/img/web.jpg', mobileSmallSrc: '/img/web.jpg', mobileLargeSrc: '/img/web.jpg', enableRoutes: ['/'], };
function initProgressiveLoad(config) { const target = document.getElementById('page-header'); if (target && target.classList.contains('full_page')) { executeLoad(config, target); } }
document.addEventListener("DOMContentLoaded", function() { initProgressiveLoad(config); }); document.addEventListener("pjax:complete", function() { initProgressiveLoad(config); });
|
2.1.2 CSS 文件配置 (imgloaded.css
)
在 themes/anzhiyu/source/css/
目录下新建 imgloaded.css
文件,内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| .pl-container { width: 100%; height: 100%; position: relative; overflow: hidden; will-change: transform; animation: blur-to-clear 2s cubic-bezier(.62,.21,.25,1) 0s 1 normal backwards running, scale 1.5s cubic-bezier(.62,.21,.25,1) 0s 1 both; } .pl-img { width: 100%; height: 100%; position: absolute; background-position: center; background-size: cover; background-repeat: no-repeat; opacity: 0; transition: opacity 1s; }
@keyframes blur-to-clear { 0% { filter: blur(50px); opacity: 1; } 100% { filter: blur(0); opacity: 1; } }
@keyframes scale { 0% { transform: scale(1.5); opacity: 0; } 100% { transform: scale(1); opacity: 1; } }
.pl-visible { opacity: 1; } .pl-blur { filter: blur(50px); }
|
2.2 首页一图流渐进式加载
2.2.1 JS 文件配置 (imgloaded.js
)
如果要实现首页“一图流”背景加载,需修改或新建 imgloaded.js
文件,示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
| (function() { class ProgressiveLoad { constructor(smallSrc, largeSrc) { this.smallSrc = smallSrc; this.largeSrc = largeSrc; this.initTpl(); this.container.addEventListener('animationend', () => { this.smallStage.style.display = 'none'; }, {once: true}); } initTpl() { this.container = document.createElement('div'); this.smallStage = document.createElement('div'); this.largeStage = document.createElement('div'); this.smallImg = new Image(); this.largeImg = new Image(); this.container.className = 'pl-container'; this.smallStage.className = 'pl-img pl-blur'; this.largeStage.className = 'pl-img'; this.container.appendChild(this.smallStage); this.container.appendChild(this.largeStage); this.smallImg.onload = this._onSmallLoaded.bind(this); this.largeImg.onload = this._onLargeLoaded.bind(this); } progressiveLoad() { this.smallImg.src = this.smallSrc; this.largeImg.src = this.largeSrc; } _onLargeLoaded() { this.largeStage.classList.add('pl-visible'); this.largeStage.style.backgroundImage = `url('${this.largeSrc}')`; } _onSmallLoaded() { this.smallStage.classList.add('pl-visible'); this.smallStage.style.backgroundImage = `url('${this.smallSrc}')`; } }
const executeLoad = (config, target) => { const isMobile = window.matchMedia('(max-width: 767px)').matches; const loader = new ProgressiveLoad( isMobile ? config.mobileSmallSrc : config.smallSrc, isMobile ? config.mobileLargeSrc : config.largeSrc ); if (target.children[0]) { target.insertBefore(loader.container, target.children[0]); } loader.progressiveLoad(); };
const ldconfig = { light: { smallSrc: '/img/web.jpg', largeSrc: '/img/web.jpg', mobileSmallSrc: '/img/web.jpg', mobileLargeSrc: '/img/web.jpg', enableRoutes: ['/'], }, dark: { smallSrc: '/img/web.jpg', largeSrc: '/img/web.jpg', mobileSmallSrc: '/img/web.jpg', mobileLargeSrc: '/img/web.jpg', enableRoutes: ['/'], }, };
const getCurrentTheme = () => { return document.documentElement.getAttribute('data-theme'); }
const onThemeChange = () => { const currentTheme = getCurrentTheme(); const config = ldconfig[currentTheme]; initProgressiveLoad(config); document.addEventListener("DOMContentLoaded", function() { initProgressiveLoad(config); }); document.addEventListener("pjax:complete", function() { initProgressiveLoad(config); }); }
const initTheme = getCurrentTheme(); const initConfig = ldconfig[initTheme]; initProgressiveLoad(initConfig);
const observer = new MutationObserver(mutations => { mutations.forEach(mutation => { if (mutation.attributeName === "data-theme" && location.pathname === '/') { onThemeChange(); } }); }); observer.observe(document.documentElement, { attributes: true, attributeFilter: ["data-theme"] });
function initProgressiveLoad(config) { const container = document.querySelector('.pl-container'); if (container) { container.remove(); } const target = document.getElementById('page-header'); if (target && target.classList.contains('full_page')) { executeLoad(config, target); } } })();
|
2.2.2 CSS 文件配置 (imgloaded.css
)
在 themes/anzhiyu/source/css/
下新建或修改 imgloaded.css
文件,内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| .pl-container { width: 100%; height: 100%; z-index: -2; position: fixed; overflow: hidden; will-change: transform; animation: blur-to-clear 2s cubic-bezier(.62,.21,.25,1) 0s 1 normal backwards running, scale 1.5s cubic-bezier(.62,.21,.25,1) 0s 1 both; } .pl-img { width: 100%; height: 100%; position: absolute; background-position: center; background-size: cover; background-repeat: no-repeat; opacity: 0; transition: opacity 1s; }
@keyframes blur-to-clear { 0% { filter: blur(50px); opacity: 1; } 100% { filter: blur(0); opacity: 1; } }
@keyframes scale { 0% { transform: scale(1.5); opacity: 0; } 100% { transform: scale(1); opacity: 1; } }
.pl-visible { opacity: 1; }
.pl-blur { filter: blur(50px); }
|
3. 文件引入
在主题配置文件 _config.anzhiyu.yml
中的 inject
项目下,添加以下引用代码:
1 2 3 4 5
| inject: head: - <link rel="stylesheet" href="/css/imgloaded.css?1"> bottom: - <script async data-pjax src="/js/imgloaded.js?1"></script>
|
4. 配置图片
- 开启顶部图片功能:在主题配置文件中将
top_image
设置为 true
。
- 由于图片加载和渲染由 JS 完成,因此无需在配置文件中提供图片 URL,只需在 JS 中修改相应图片链接即可。
示例配置:
1 2
| index_img: "background: url() top / cover no-repeat"
|
5. 图片懒加载配置(可选)
如果同时需要使用图片懒加载功能,可在主题配置文件中添加如下配置:
1 2 3 4 5 6
| lazyload: enable: true field: post placeholder: blur: true progressive: true
|
6. 完成
按照以上步骤配置好后,执行 Hexo 的 clean
、generate
及 server
命令,即可查看渐进式加载效果。
如图片文件路径和链接设置正确,页面加载时会先显示经过模糊处理的小图,随后自动替换为高清大图。