From d4ad5fad3d3d207fa2ae345444011ad897c9df60 Mon Sep 17 00:00:00 2001 From: journey-ad Date: Mon, 21 Oct 2024 12:22:51 +0800 Subject: [PATCH] feat(web): Add lazyload --- assets/img/failed.svg | 1 + assets/img/loading.svg | 1 + assets/script.js | 56 ++++++++++++++++++++++++++++++++++++ assets/style.css | 9 ++++++ views/index.pug | 65 +++++++++++++----------------------------- 5 files changed, 87 insertions(+), 45 deletions(-) create mode 100644 assets/img/failed.svg create mode 100644 assets/img/loading.svg diff --git a/assets/img/failed.svg b/assets/img/failed.svg new file mode 100644 index 0000000..35a9920 --- /dev/null +++ b/assets/img/failed.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/img/loading.svg b/assets/img/loading.svg new file mode 100644 index 0000000..023b81b --- /dev/null +++ b/assets/img/loading.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/script.js b/assets/script.js index dee5d84..b8fbb07 100644 --- a/assets/script.js +++ b/assets/script.js @@ -105,7 +105,63 @@ } })(); +(() => { + function lazyLoad(options = {}) { + const { + selector = 'img[data-src]:not([src])', + loading = '', + failed = '', + rootMargin = '200px', + threshold = 0.01 + } = options; + const images = document.querySelectorAll(selector); + + const observer = new IntersectionObserver((entries, observer) => { + entries.forEach(entry => { + if (entry.isIntersecting) { + const img = entry.target; + observer.unobserve(img); + + if (failed) { + const handleError = () => { + img.onerror = null; + img.src = failed; + img.setAttribute('data-failed', ''); + }; + img.onerror = handleError; + } + + img.removeAttribute('data-loading'); + img.src = img.getAttribute('data-src'); + } + }); + }, { rootMargin, threshold }); + + images.forEach(img => { + if (loading) { + img.src = loading; + img.setAttribute('data-loading', ''); + } + observer.observe(img); + }); + } + + const lazyLoadOptions = { + selector: 'img[data-src]:not([src])', + loading: '/img/loading.svg', + failed: '/img/failed.svg', + rootMargin: '200px', + threshold: 0.01 + }; + if (document.readyState === 'loading') { + document.addEventListener("DOMContentLoaded", () => lazyLoad(lazyLoadOptions)); + } else { + lazyLoad(lazyLoadOptions); + } +})(); + +// back to top (() => { let isShow = false; let lock = false; diff --git a/assets/style.css b/assets/style.css index 0fdae66..010f353 100644 --- a/assets/style.css +++ b/assets/style.css @@ -1,3 +1,12 @@ +html { + scroll-padding: 50px 0; +} + +img[data-loading], +img[data-failed] { + width: 40px; +} + @media screen and (min-width: 800px) { body { max-width: min(90%, 800px); diff --git a/views/index.pug b/views/index.pug index 9deef33..76f8af8 100644 --- a/views/index.pug +++ b/views/index.pug @@ -23,14 +23,7 @@ html } script. - var __global_data = { - site: "#{site}" - }; - - style. - html { - scroll-padding: 50px 0; - } + var __global_data = { site: "#{site}" }; body h1#main_title(style='margin-top: 0.5em;') @@ -60,23 +53,18 @@ html each theme in Object.keys(themeList) div.item(data-theme=theme) h5 #{theme} - img(src=`${site}/@demo?theme=${theme}` alt=theme) + img(data-src=`${site}/@demo?theme=${theme}` alt=theme) h3 Credits ul - li - a(href='https://glitch.com/', target='_blank', rel='nofollow') Glitch - li - a(href='https://space.bilibili.com/703007996', target='_blank', title='A-SOUL_Official') A-SOUL - li - a(href='https://github.com/moebooru/moebooru', target='_blank', rel='nofollow') moebooru + li: a(href='https://glitch.com/', target='_blank', rel='nofollow') Glitch + li: a(href='https://space.bilibili.com/703007996', target='_blank', title='A-SOUL_Official') A-SOUL + li: a(href='https://github.com/moebooru/moebooru', target='_blank', rel='nofollow') moebooru li a(href='javascript:alert("!!! NSFW LINK !!!\\nPlease enter the url manually")') gelbooru.com | NSFW - li - a(href='https://icons8.com/icon/80355/star', target='_blank', rel='nofollow') Icons8 - span - i And all booru site... + li: a(href='https://icons8.com/icon/80355/star', target='_blank', rel='nofollow') Icons8 + span: i And all booru site... h3 Tool .tool @@ -88,14 +76,11 @@ html th Value tbody tr - td - code name + td: code name td Unique counter name - td - input#name(type='text', placeholder=':name') + td: input#name(type='text', placeholder=':name') tr - td - code theme + td: code theme td Select a counter image theme, default is code moebooru td @@ -104,40 +89,30 @@ html each theme in Object.keys(themeList) option(value=theme) #{theme} tr - td - code padding + td: code padding td Set the minimum length, between 1-32, default is code 7 - td - input#padding(type='number', value='7', min='1', max='32', step='1', oninput='this.value = this.value.replace(/[^0-9]/g, "")') + td: input#padding(type='number', value='7', min='1', max='32', step='1', oninput='this.value = this.value.replace(/[^0-9]/g, "")') tr - td - code offset + td: code offset td Set the offset pixel value, between -500-500, default is code 0 - td - input#offset(type='number', value='0', min='-500', max='500', step='1', oninput='this.value = this.value.replace(/[^0-9|\-]/g, "")') + td: input#offset(type='number', value='0', min='-500', max='500', step='1', oninput='this.value = this.value.replace(/[^0-9|\-]/g, "")') tr - td - code scale + td: code scale td Set the image scale, between 0.1-2, default is code 1 - td - input#scale(type='number', value='1', min='0.1', max='2', step='0.1', oninput='this.value = this.value.replace(/[^0-9|\.]/g, "")') + td: input#scale(type='number', value='1', min='0.1', max='2', step='0.1', oninput='this.value = this.value.replace(/[^0-9|\.]/g, "")') tr - td - code pixelated + td: code pixelated td Enable pixelated mode, Enum 0/1, default is code 1 - td - input#pixelated(type='checkbox', checked, style='margin: .5rem .75rem;') + td: input#pixelated(type='checkbox', checked, style='margin: .5rem .75rem;') tr - td - code darkmode + td: code darkmode td Enable dark mode, Enum 0/1/auto, default is code auto - td - select#darkmode(name="darkmode") + td: select#darkmode(name="darkmode") option(value="auto", selected) auto option(value="1") yes option(value="0") no