feat: add lazyload image

This commit is contained in:
XPoet 2021-01-07 15:15:39 +08:00
parent 86f2e3ccc9
commit 3abec3cb33
16 changed files with 166 additions and 48 deletions

View File

@ -176,6 +176,13 @@ rss:
enable: false enable: false
# ---------------------------------------------------------------------------------------
# lazyload image
# ---------------------------------------------------------------------------------------
lazyload:
enable: false
# --------------------------------------------------------------------------------------- # ---------------------------------------------------------------------------------------
# CDN # CDN
# --------------------------------------------------------------------------------------- # ---------------------------------------------------------------------------------------

View File

@ -14,6 +14,10 @@
<%- __js('js/code-copy.js') %> <%- __js('js/code-copy.js') %>
<% } %> <% } %>
<% if (theme.lazyload.enable) { %>
<%- __js('js/lazyload.js') %>
<% } %>
<div class="post-scripts<%= theme.pjax.enable === true ? ' pjax' : '' %>"> <div class="post-scripts<%= theme.pjax.enable === true ? ' pjax' : '' %>">
<% if (theme.toc.enable && is_post()) { %> <% if (theme.toc.enable && is_post()) { %>
<%- __js([ <%- __js([

View File

@ -0,0 +1,24 @@
'use strict'
hexo.extend.filter.register(
'after_post_render',
function (data) {
const theme = hexo.theme.config;
if (!theme.lazyload || !theme.lazyload.enable) return;
data.content = data.content.replace(
// Match 'img' tags width the src attribute.
/<img([^>]*)src="([^"]*)"([^>]*)>/gim,
function (match, attrBegin, src, attrEnd) {
// Exit if the src doesn't exists.
if (!src) return match;
return `<img ${attrBegin}
lazyload
src="/images/loading.svg"
data-src="${src}"
${attrEnd}
>`
}
)
},
1
);

View File

@ -14,7 +14,7 @@ hexo.extend.helper.register('export_config', function () {
let {config, theme} = this; let {config, theme} = this;
// ------------ export language to js ------------ // ------------------------ export language to js ------------------------
const languageDir = path.join(__dirname, '../../languages'); const languageDir = path.join(__dirname, '../../languages');
let file = fs.readdirSync(languageDir).find(v => v === `${config.language}.yml`); let file = fs.readdirSync(languageDir).find(v => v === `${config.language}.yml`);
file = languageDir + '/' + (file ? file : 'en.yml'); file = languageDir + '/' + (file ? file : 'en.yml');
@ -24,7 +24,7 @@ hexo.extend.helper.register('export_config', function () {
} catch (e) { } catch (e) {
console.log(e); console.log(e);
} }
// ----------------------------------------------- // -----------------------------------------------------------------------
let hexo_config = { let hexo_config = {
@ -43,6 +43,7 @@ hexo.extend.helper.register('export_config', function () {
code_copy: theme.code_copy, code_copy: theme.code_copy,
side_tools: theme.side_tools, side_tools: theme.side_tools,
pjax: theme.pjax, pjax: theme.pjax,
lazyload: theme.lazyload,
version: theme.version, version: theme.version,
} }

View File

@ -3,9 +3,9 @@
@require 'keep-theme.styl' @require 'keep-theme.styl'
// ============================ // ======================================================================
// html, body // html, body
// ============================ // ======================================================================
html, body { html, body {
margin: 0; margin: 0;
padding: 0; padding: 0;
@ -29,9 +29,9 @@ html, body {
} }
// ============================ // ======================================================================
// scrollbar // scrollbar
// ============================ // ======================================================================
* { * {
&::-webkit-scrollbar { &::-webkit-scrollbar {
width: 6px; width: 6px;
@ -48,18 +48,18 @@ html, body {
} }
// ============================ // ======================================================================
// selection // selection
// ============================ // ======================================================================
::selection { ::selection {
background: var(--selection-color); background: var(--selection-color);
color: #fff; color: #fff;
} }
// ============================ // ======================================================================
// ul, ol, li // ul, ol, li
// ============================ // ======================================================================
ul, ol, li { ul, ol, li {
padding: 0; padding: 0;
margin: 0; margin: 0;
@ -67,9 +67,9 @@ ul, ol, li {
} }
// ============================ // ======================================================================
// a // a
// ============================ // ======================================================================
a { a {
text-decoration: none; text-decoration: none;
color: var(--default-text-color); color: var(--default-text-color);
@ -82,9 +82,24 @@ a {
} }
// ============================ // ======================================================================
// img
// ======================================================================
img {
&[lazyload] {
padding: 20px;
cursor: not-allowed;
pointer-events: none;
margin: 20px auto !important;
background: var(--lazyload-background-color);
transition();
}
}
// ======================================================================
// button // button
// ============================ // ======================================================================
button { button {
padding: 0; padding: 0;
margin: 0; margin: 0;
@ -113,9 +128,9 @@ button {
} }
// ============================ // ======================================================================
// flex center // flex center
// ============================ // ======================================================================
.flex-center { .flex-center {
display: flex; display: flex;
justify-content: center; justify-content: center;
@ -123,9 +138,9 @@ button {
} }
// ============================ // ======================================================================
// clear float // clear float
// ============================ // ======================================================================
.clear { .clear {
clear: both; clear: both;
} }

View File

@ -172,6 +172,7 @@
cursor: zoom-in; cursor: zoom-in;
display: block; display: block;
box-shadow: 0 0 2px var(--shadow-color); box-shadow: 0 0 2px var(--shadow-color);
transition();
if (hexo-config('style.article_img_align') == 'center') { if (hexo-config('style.article_img_align') == 'center') {
margin: 10px auto 2px; margin: 10px auto 2px;

View File

@ -6,24 +6,25 @@
// ======================================================================================== // ========================================================================================
// layout // layout
// ======================================================================================== // ========================================================================================
$header-height = 76px; // $header-height = 76px; // header height
$header-shrink-height = $header-height * 0.72; // $header-shrink-height = $header-height * 0.72; // header shrink height
$scroll-progress-bar-height = 2px; // $scroll-progress-bar-height = 2px; // scroll progress bar height
$main-content-width = 80%; // PC $main-content-width = 80%; // main content width (tablet)
$main-content-width-tablet = 85%; // $main-content-width-tablet = 86%; // main content width (PC)
$main-content-width-mobile = 90%; // $main-content-width-mobile = 90%; // main content width (mobile)
$circle-button-width = 40px; // tools $circle-button-width = 38px; // post tool button width
$tools-button-width = 32px; // tools $component-spacing-value = 30px; // component-spacing-value (PC)
$component-interspace = 30px; // /PC
// main content max width
$temp-content-max-width = hexo-config('style.content_max_width'); $temp-content-max-width = hexo-config('style.content_max_width');
$content-max-width = $temp-content-max-width ? convert($temp-content-max-width) : 1000px; $content-max-width = $temp-content-max-width ? convert($temp-content-max-width) : 1000px;
// ======================================================================================== // ========================================================================================
// // media query
// ======================================================================================== // ========================================================================================
$media-max-width = 780px; // () $media-max-width = 780px; // media query max width (tablet)
$media-max-width-mobile = 500px; // $media-max-width-mobile = 500px; // media query max width (mobile)
keep-tablet() keep-tablet()
@media (max-width: $media-max-width) @media (max-width: $media-max-width)
@ -76,6 +77,7 @@ $link-color = darken($default-text-color, 10%);
$copyright-info-color = #CC0033; $copyright-info-color = #CC0033;
$avatar-background-color = #0066CC; $avatar-background-color = #0066CC;
$loading-progress-bar-color = #990000; $loading-progress-bar-color = #990000;
$lazyload-background-color = rgba(200, 200, 200, 0.5);
// ======================================================================================== // ========================================================================================
@ -99,6 +101,7 @@ $dark-link-color = lighten($dark-default-text-color, 10%);
$dark-copyright-info-color = darken($copyright-info-color, 20%); $dark-copyright-info-color = darken($copyright-info-color, 20%);
$dark-avatar-background-color = darken($avatar-background-color, 10%); $dark-avatar-background-color = darken($avatar-background-color, 10%);
$dark-loading-progress-bar-color = lighten($loading-progress-bar-color, 50%); $dark-loading-progress-bar-color = lighten($loading-progress-bar-color, 50%);
$dark-lazyload-background-color = rgba(50, 50, 50, 0.5);
// ======================================================================== // ========================================================================
@ -131,7 +134,8 @@ root-color(mode) {
--link-color: mode == 'light' ? $link-color : $dark-link-color; --link-color: mode == 'light' ? $link-color : $dark-link-color;
--copyright-info-color: mode == 'light' ? $copyright-info-color : $dark-copyright-info-color; --copyright-info-color: mode == 'light' ? $copyright-info-color : $dark-copyright-info-color;
--avatar-background-color: mode == 'light' ? $avatar-background-color : $dark-avatar-background-color; --avatar-background-color: mode == 'light' ? $avatar-background-color : $dark-avatar-background-color;
--loading-progress-bar-color: mode == 'light' ? $loading-progress-bar-color : $dark-loading-progress-bar-color; --loading-progress-bar-color : mode == 'light' ? $loading-progress-bar-color : $dark-loading-progress-bar-color;
--lazyload-background-color : mode == 'light' ? $lazyload-background-color : $dark-lazyload-background-color;
} }

View File

@ -6,7 +6,7 @@ $article-date-font-size = 1rem;
.archive-list-container { .archive-list-container {
.archive-item { .archive-item {
margin-bottom: $component-interspace; margin-bottom: $component-spacing-value;
&:last-child { &:last-child {
margin-bottom: 0; margin-bottom: 0;

View File

@ -12,7 +12,7 @@ if (hexo-config('comment.valine.enable') && hexo-config('comment.gitalk.enable')
.comments-container { .comments-container {
display: inline-block; display: inline-block;
margin-top: $component-interspace; margin-top: $component-spacing-value;
width: 100%; width: 100%;
#comment-anchor { #comment-anchor {

View File

@ -91,7 +91,7 @@ $article-title-font-size = 1.6rem;
.article-content { .article-content {
margin-top: $component-interspace; margin-top: $component-spacing-value;
padding-bottom: 10px; padding-bottom: 10px;
border-bottom: 1px solid var(--border-color); border-bottom: 1px solid var(--border-color);
word-wrap: break-word; word-wrap: break-word;
@ -99,13 +99,13 @@ $article-title-font-size = 1.6rem;
} }
.post-copyright-info { .post-copyright-info {
margin-top: $component-interspace; margin-top: $component-spacing-value;
width: 100%; width: 100%;
} }
.article-nav { .article-nav {
height: 40px; height: 40px;
margin-top: $component-interspace; margin-top: $component-spacing-value;
.article-prev, .article-next { .article-prev, .article-next {
max-width: $post-nav-max-width; max-width: $post-nav-max-width;

View File

@ -18,7 +18,7 @@ $category-name-font-size = 1.6rem;
font-weight: 600; font-weight: 600;
padding-bottom: 20px; padding-bottom: 20px;
margin-bottom: $component-interspace; margin-bottom: $component-spacing-value;
border-bottom: 1px solid var(--border-color); border-bottom: 1px solid var(--border-color);
} }
} }

View File

@ -78,14 +78,14 @@ $page-aside-width = $temp-width ? convert($temp-width) : 260px;
width: 100%; width: 100%;
display: flex; display: flex;
justify-content: center; justify-content: center;
padding: $component-interspace 0; padding: $component-spacing-value 0;
+keep-tablet() { +keep-tablet() {
padding: $component-interspace * 0.8 0; padding: $component-spacing-value * 0.8 0;
} }
+keep-mobile() { +keep-mobile() {
padding: $component-interspace * 0.6 0; padding: $component-spacing-value * 0.6 0;
} }
.main-content { .main-content {
@ -137,25 +137,25 @@ $page-aside-width = $temp-width ? convert($temp-width) : 260px;
.post-tools { .post-tools {
position: fixed; position: fixed;
top: $header-height + $component-interspace; top: $header-height + $component-spacing-value;
right: $component-interspace; right: $component-spacing-value;
transition(); transition();
.header-shrink & { .header-shrink & {
top: $header-shrink-height + $component-interspace; top: $header-shrink-height + $component-spacing-value;
+keep-tablet() { +keep-tablet() {
top: $header-shrink-height * 0.9 + $component-interspace; top: $header-shrink-height * 0.9 + $component-spacing-value;
} }
+keep-mobile() { +keep-mobile() {
top: $header-shrink-height * 0.8 + $component-interspace; top: $header-shrink-height * 0.8 + $component-spacing-value;
} }
} }
+keep-tablet() { +keep-tablet() {
top: $header-height * 0.9 + $component-interspace; top: $header-height * 0.9 + $component-spacing-value;
right: 10px; right: 10px;
transform: scale(0.82); transform: scale(0.82);
transform-origin: right top; transform-origin: right top;
@ -163,7 +163,7 @@ $page-aside-width = $temp-width ? convert($temp-width) : 260px;
+keep-mobile() { +keep-mobile() {
top: $header-height * 0.8 + $component-interspace; top: $header-height * 0.8 + $component-spacing-value;
right: 5px; right: 5px;
transform: scale(0.72); transform: scale(0.72);
} }

View File

@ -18,7 +18,7 @@ $tag-name-font-size = 1.6rem;
font-weight: 600; font-weight: 600;
padding-bottom: 20px; padding-bottom: 20px;
margin-bottom: $component-interspace; margin-bottom: $component-spacing-value;
border-bottom: 1px solid var(--border-color); border-bottom: 1px solid var(--border-color);
} }
} }

17
source/images/loading.svg Normal file
View File

@ -0,0 +1,17 @@
<!-- By Sam Herbert (@sherb), for everyone. More @ http://goo.gl/7AJzbL -->
<svg width="38" height="38" viewBox="0 0 38 38" xmlns="http://www.w3.org/2000/svg" stroke="#fff">
<g fill="none" fill-rule="evenodd">
<g transform="translate(1 1)" stroke-width="2">
<circle stroke-opacity=".5" cx="18" cy="18" r="18"/>
<path d="M36 18c0-9.94-8.06-18-18-18">
<animateTransform
attributeName="transform"
type="rotate"
from="0 18 18"
to="360 18 18"
dur="1s"
repeatCount="indefinite"/>
</path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 694 B

41
source/js/lazyload.js Normal file
View File

@ -0,0 +1,41 @@
KEEP.initLazyLoad = () => {
const imgs = document.querySelectorAll('img');
let now = Date.now();
let needLoad = true;
function lazyload(imgs) {
now = Date.now();
needLoad = Array.from(imgs).some(i => i.hasAttribute('lazyload'));
const h = window.innerHeight;
const s = document.documentElement.scrollTop || document.body.scrollTop;
imgs.forEach(img => {
if (img.hasAttribute('lazyload') && !img.hasAttribute('loading')) {
if ((h + s) > img.offsetTop) {
img.setAttribute('loading', true);
const loadImageTimeout = setTimeout(() => {
const temp = new Image();
const src = img.getAttribute('data-src');
temp.src = src;
temp.onload = () => {
img.src = src;
img.removeAttribute('lazyload');
img.removeAttribute('loading');
clearTimeout(loadImageTimeout);
}
}, 1000);
}
}
});
}
lazyload(imgs);
window.onscroll = () => {
if (Date.now() - now > 100 && needLoad) {
lazyload(imgs);
}
}
}

View File

@ -20,6 +20,10 @@ window.addEventListener('DOMContentLoaded', () => {
if (KEEP.theme_config.code_copy.enable === true) { if (KEEP.theme_config.code_copy.enable === true) {
KEEP.initCodeCopy(); KEEP.initCodeCopy();
} }
if (KEEP.theme_config.lazyload.enable === true) {
KEEP.initLazyLoad();
}
} }
KEEP.refresh(); KEEP.refresh();