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
# ---------------------------------------------------------------------------------------
# lazyload image
# ---------------------------------------------------------------------------------------
lazyload:
enable: false
# ---------------------------------------------------------------------------------------
# CDN
# ---------------------------------------------------------------------------------------

View File

@ -14,6 +14,10 @@
<%- __js('js/code-copy.js') %>
<% } %>
<% if (theme.lazyload.enable) { %>
<%- __js('js/lazyload.js') %>
<% } %>
<div class="post-scripts<%= theme.pjax.enable === true ? ' pjax' : '' %>">
<% if (theme.toc.enable && is_post()) { %>
<%- __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;
// ------------ export language to js ------------
// ------------------------ export language to js ------------------------
const languageDir = path.join(__dirname, '../../languages');
let file = fs.readdirSync(languageDir).find(v => v === `${config.language}.yml`);
file = languageDir + '/' + (file ? file : 'en.yml');
@ -24,7 +24,7 @@ hexo.extend.helper.register('export_config', function () {
} catch (e) {
console.log(e);
}
// -----------------------------------------------
// -----------------------------------------------------------------------
let hexo_config = {
@ -43,6 +43,7 @@ hexo.extend.helper.register('export_config', function () {
code_copy: theme.code_copy,
side_tools: theme.side_tools,
pjax: theme.pjax,
lazyload: theme.lazyload,
version: theme.version,
}

View File

@ -3,9 +3,9 @@
@require 'keep-theme.styl'
// ============================
// ======================================================================
// html, body
// ============================
// ======================================================================
html, body {
margin: 0;
padding: 0;
@ -29,9 +29,9 @@ html, body {
}
// ============================
// ======================================================================
// scrollbar
// ============================
// ======================================================================
* {
&::-webkit-scrollbar {
width: 6px;
@ -48,18 +48,18 @@ html, body {
}
// ============================
// ======================================================================
// selection
// ============================
// ======================================================================
::selection {
background: var(--selection-color);
color: #fff;
}
// ============================
// ======================================================================
// ul, ol, li
// ============================
// ======================================================================
ul, ol, li {
padding: 0;
margin: 0;
@ -67,9 +67,9 @@ ul, ol, li {
}
// ============================
// ======================================================================
// a
// ============================
// ======================================================================
a {
text-decoration: none;
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 {
padding: 0;
margin: 0;
@ -113,9 +128,9 @@ button {
}
// ============================
// ======================================================================
// flex center
// ============================
// ======================================================================
.flex-center {
display: flex;
justify-content: center;
@ -123,9 +138,9 @@ button {
}
// ============================
// ======================================================================
// clear float
// ============================
// ======================================================================
.clear {
clear: both;
}

View File

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

View File

@ -6,24 +6,25 @@
// ========================================================================================
// layout
// ========================================================================================
$header-height = 76px; //
$header-shrink-height = $header-height * 0.72; //
$scroll-progress-bar-height = 2px; //
$main-content-width = 80%; // PC
$main-content-width-tablet = 85%; //
$main-content-width-mobile = 90%; //
$circle-button-width = 40px; // tools
$tools-button-width = 32px; // tools
$component-interspace = 30px; // /PC
$header-height = 76px; // header height
$header-shrink-height = $header-height * 0.72; // header shrink height
$scroll-progress-bar-height = 2px; // scroll progress bar height
$main-content-width = 80%; // main content width (tablet)
$main-content-width-tablet = 86%; // main content width (PC)
$main-content-width-mobile = 90%; // main content width (mobile)
$circle-button-width = 38px; // post tool button width
$component-spacing-value = 30px; // component-spacing-value (PC)
// main 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;
// ========================================================================================
//
// media query
// ========================================================================================
$media-max-width = 780px; // ()
$media-max-width-mobile = 500px; //
$media-max-width = 780px; // media query max width (tablet)
$media-max-width-mobile = 500px; // media query max width (mobile)
keep-tablet()
@media (max-width: $media-max-width)
@ -76,6 +77,7 @@ $link-color = darken($default-text-color, 10%);
$copyright-info-color = #CC0033;
$avatar-background-color = #0066CC;
$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-avatar-background-color = darken($avatar-background-color, 10%);
$dark-loading-progress-bar-color = lighten($loading-progress-bar-color, 50%);
$dark-lazyload-background-color = rgba(50, 50, 50, 0.5);
// ========================================================================
@ -132,6 +135,7 @@ root-color(mode) {
--copyright-info-color: mode == 'light' ? $copyright-info-color : $dark-copyright-info-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;
--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-item {
margin-bottom: $component-interspace;
margin-bottom: $component-spacing-value;
&:last-child {
margin-bottom: 0;

View File

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

View File

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

View File

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

View File

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

View File

@ -18,7 +18,7 @@ $tag-name-font-size = 1.6rem;
font-weight: 600;
padding-bottom: 20px;
margin-bottom: $component-interspace;
margin-bottom: $component-spacing-value;
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) {
KEEP.initCodeCopy();
}
if (KEEP.theme_config.lazyload.enable === true) {
KEEP.initLazyLoad();
}
}
KEEP.refresh();