From 38bf8bc86779b6dadeeb34c5f2c68261b3c043ef Mon Sep 17 00:00:00 2001 From: XPoet Date: Wed, 6 Jan 2021 18:36:28 +0800 Subject: [PATCH] feat: add loading progress bar --- layout/_partial/pjax/pjax.ejs | 18 +- layout/_partial/progress-bar.ejs | 4 + layout/page.ejs | 102 +++++----- source/css/common/variables.styl | 27 +-- source/css/layout/_partial/first-screen.styl | 6 +- source/css/layout/_partial/header.styl | 2 +- source/css/layout/_partial/progress-bar.styl | 45 +++++ source/css/layout/page.styl | 185 ++++++++----------- source/css/style.styl | 1 + source/js/utils.js | 53 ++++-- 10 files changed, 252 insertions(+), 191 deletions(-) create mode 100644 layout/_partial/progress-bar.ejs create mode 100644 source/css/layout/_partial/progress-bar.styl diff --git a/layout/_partial/pjax/pjax.ejs b/layout/_partial/pjax/pjax.ejs index 4edac82..f177c1b 100644 --- a/layout/_partial/pjax/pjax.ejs +++ b/layout/_partial/pjax/pjax.ejs @@ -5,21 +5,27 @@ selectors: [ 'head title', '.page-container', - '.pjax', + '.pjax' ], history: true, debug: false, cacheBust: false, timeout: 0, - // analytics: false, - // currentUrlFullReload: false, - // scrollRestoration: false, + analytics: false, + currentUrlFullReload: false, + scrollRestoration: false, // scrollTo: true, }); - window.addEventListener('pjax:complete', () => { - KEEP.refresh(); + + document.addEventListener('pjax:send', () => { + KEEP.utils.loadingProgressBarStart(); + }); + + document.addEventListener('pjax:complete', () => { + KEEP.utils.loadingProgressBarEnd(); pjax.executeScripts(document.querySelectorAll('script[data-pjax], .pjax script')); + KEEP.refresh(); }); }); diff --git a/layout/_partial/progress-bar.ejs b/layout/_partial/progress-bar.ejs new file mode 100644 index 0000000..7bf694e --- /dev/null +++ b/layout/_partial/progress-bar.ejs @@ -0,0 +1,4 @@ +
+ + +
diff --git a/layout/page.ejs b/layout/page.ejs index 6396aa0..003f16b 100644 --- a/layout/page.ejs +++ b/layout/page.ejs @@ -1,59 +1,53 @@ -
+<%- partial('_partial/progress-bar') %> +
<% if (theme.style.first_screen.enable === true && is_home() && !page.prev) { %> <%- partial('_partial/first-screen') %> <% } %> - +
-
- -
- -
- <%- partial('_partial/header') %> -
- -
- -
- - <% if (is_home()) { %> - <%- partial('home-content') %> - - <% } else if (is_archive()) { %> - <%- partial('archive-content') %> - - <% } else if (is_post()) { %> - <%- partial('article-content') %> - - <% } else if (is_category()) { %> - <%- partial('category-content') %> - - <% } else if (is_tag()) { %> - <%- partial('tag-content') %> - - <% } else if (page.title === 'category' || page.title === 'categories') { %> - <%- partial('category-list') %> - - <% } else if (page.title === 'tag' || page.title === 'tags') { %> - <%- partial('_partial/tagcloud') %> - - <% } else { %> - <%- partial('_partial/empty-page') %> - - <% } %> -
- -
- -
- <%- partial('_partial/footer') %> -
+
+ <%- partial('_partial/header') %>
-
+ +
+ +
+ + <% if (is_home()) { %> + <%- partial('home-content') %> + + <% } else if (is_archive()) { %> + <%- partial('archive-content') %> + + <% } else if (is_post()) { %> + <%- partial('article-content') %> + + <% } else if (is_category()) { %> + <%- partial('category-content') %> + + <% } else if (is_tag()) { %> + <%- partial('tag-content') %> + + <% } else if (page.title === 'category' || page.title === 'categories') { %> + <%- partial('category-list') %> + + <% } else if (page.title === 'tag' || page.title === 'tags') { %> + <%- partial('_partial/tagcloud') %> + + <% } else { %> + <%- partial('_partial/empty-page') %> + + <% } %> +
+ +
+ +
+ <%- partial('_partial/footer') %> +
+
<% if (is_post()) { %> <% if (is_post() && theme.toc.enable === true) { %> - <% } %> - <%- partial('_partial/image-viewer') %> -
+ <% if (theme.local_search.enable) { %> + <%- partial('_partial/local-search') %> + <% } %> -<% if (theme.local_search.enable) { %> - <%- partial('_partial/local-search') %> -<% } %> + diff --git a/source/css/common/variables.styl b/source/css/common/variables.styl index b8f3573..4291982 100644 --- a/source/css/common/variables.styl +++ b/source/css/common/variables.styl @@ -6,15 +6,15 @@ // ======================================================================================== // layout // ======================================================================================== -$header-height = 76px; // 头部默认高度 -$header-shrink-height = $header-height * 0.72; // 头部收缩高度 -$header-progress-height = 2.8px; // 头部进度条高度 -$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-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) $temp-content-max-width = hexo-config('style.content_max_width'); $content-max-width = $temp-content-max-width ? convert($temp-content-max-width) : 1000px; @@ -22,8 +22,8 @@ $content-max-width = $temp-content-max-width ? convert($temp-content-max-width) // ======================================================================================== // 媒体查询 // ======================================================================================== -$media-max-width = 780px; // 媒体查询最大宽度 (平板) -$media-max-width-mobile = 500px; // 媒体查询最大宽度(手机) +$media-max-width = 780px; // 媒体查询最大宽度 (平板) +$media-max-width-mobile = 500px; // 媒体查询最大宽度(手机) keep-tablet() @media (max-width: $media-max-width) @@ -75,6 +75,7 @@ $scroll-bar-bg-color = darken($background-color, 10%); $link-color = darken($default-text-color, 10%); $copyright-info-color = #CC0033; $avatar-background-color = #0066CC; +$loading-progress-bar-color = #990000; // ======================================================================================== @@ -96,7 +97,8 @@ $dark-scroll-bar-color = darken($dark-background-color, 30%); $dark-scroll-bar-bg-color = lighten($dark-background-color, 10%); $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, 20%); +$dark-avatar-background-color = darken($avatar-background-color, 10%); +$dark-loading-progress-bar-color = lighten($loading-progress-bar-color, 50%); // ======================================================================== @@ -129,6 +131,7 @@ root-color(mode) { --link-color: mode == 'light' ? $link-color : $dark-link-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; + --loading-progress-bar-color: mode == 'light' ? $loading-progress-bar-color : $dark-loading-progress-bar-color; } diff --git a/source/css/layout/_partial/first-screen.styl b/source/css/layout/_partial/first-screen.styl index 3cd0801..875eef6 100644 --- a/source/css/layout/_partial/first-screen.styl +++ b/source/css/layout/_partial/first-screen.styl @@ -10,14 +10,14 @@ $first-screen-img = $temp-img ? $temp-img:'/images/bg.svg'; width: 100%; overflow: hidden; background: url($first-screen-img) center center / cover no-repeat; - background-position-y: $header-height - $header-progress-height; + background-position-y: $header-height - $scroll-progress-bar-height; +keep-tablet() { - background-position-y: $header-height * 0.9 - $header-progress-height; + background-position-y: $header-height * 0.9 - $scroll-progress-bar-height; } +keep-mobile() { - background-position-y: $header-height * 0.8 - $header-progress-height; + background-position-y: $header-height * 0.8 - $scroll-progress-bar-height; } .content { diff --git a/source/css/layout/_partial/header.styl b/source/css/layout/_partial/header.styl index 1be5a8d..653eb9e 100644 --- a/source/css/layout/_partial/header.styl +++ b/source/css/layout/_partial/header.styl @@ -10,7 +10,7 @@ $menu-bar-line-height = 2.5px; align-items: center; justify-content: center; background: var(--background-color); - padding-top: $header-progress-height; + padding-top: $scroll-progress-bar-height; transition(); hover-style(1.02, 1.02); diff --git a/source/css/layout/_partial/progress-bar.styl b/source/css/layout/_partial/progress-bar.styl new file mode 100644 index 0000000..065d10a --- /dev/null +++ b/source/css/layout/_partial/progress-bar.styl @@ -0,0 +1,45 @@ +.progress-bar-container { + position: fixed; + top: 0; + left: 0; + width: 100%; + z-index: $z-index-9; + + .loading-progress-bar { + position: absolute; + top: 0; + left: 0; + height: 1px; + width: 0; + background: var(--loading-progress-bar-color); + box-shadow: 0 1px 3px var(--loading-progress-bar-color); + visibility: hidden; + opacity: 0; + z-index: $z-index-8; + transition(); + + &.show { + transition(); + opacity: 1; + visibility: visible; + } + } + + + .scroll-progress-bar { + position: absolute; + top: 0; + left: 0; + width: 0; + height: $scroll-progress-bar-height; + visibility: hidden; + background: var(--primary-color); + transition: all 0.1s ease; + z-index: $z-index-7; + + &.hide { + transition: none; + visibility: hidden; + } + } +} diff --git a/source/css/layout/page.styl b/source/css/layout/page.styl index c763a0e..7b3b459 100644 --- a/source/css/layout/page.styl +++ b/source/css/layout/page.styl @@ -1,135 +1,114 @@ $temp-width = hexo-config('style.left_side_width'); -$page-aside-width = $temp-width ? convert($temp-width):260px; +$page-aside-width = $temp-width ? convert($temp-width) : 260px; .page-container { position: relative; - padding-top: $header-progress-height; - transition(); +keep-tablet() { padding-left: 0 !important; } + .page-main-content { + padding-top: $header-height; + position: relative; - .page-header { - .header-progress { - visibility: hidden; - position: fixed; - width: 0; - height: $header-progress-height; - top: 0; - left: 0; - background: var(--primary-color); - transition: all 0.1s ease; - z-index: $z-index-7; - } - } - - - .page-main { - - .page-main-content { - padding-top: $header-height; - position: relative; - - .header-shrink & { - padding-top: $header-shrink-height; - transition(); - - +keep-tablet() { - padding-top: $header-shrink-height * 0.9; - } - - +keep-mobile() { - padding-top: $header-shrink-height * 0.8; - } - } + .header-shrink & { + padding-top: $header-shrink-height; + transition(); +keep-tablet() { - padding-top: $header-height * 0.9; + padding-top: $header-shrink-height * 0.9; } +keep-mobile() { - padding-top: $header-height * 0.8; + padding-top: $header-shrink-height * 0.8; + } + } + + +keep-tablet() { + padding-top: $header-height * 0.9; + } + + +keep-mobile() { + padding-top: $header-height * 0.8; + } + + .page-main-content-top { + position: fixed; + top: 0; + right: 0; + width: 100%; + height: $header-height; + z-index: $z-index-5; + box-sizing: border-box; + transition(); + + &.hide { + transform: translateY(-102%); } - .page-main-content-top { - position: fixed; - top: 0; - right: 0; - width: 100%; - height: $header-height; - z-index: $z-index-5; + .header-shrink & { + height: $header-shrink-height; + + +keep-tablet() { + height: $header-shrink-height * 0.9; + } + + +keep-mobile() { + height: $header-shrink-height * 0.8; + } + } + + + +keep-tablet() { + height: $header-height * 0.9; + padding-left: 0 !important; + } + + + +keep-mobile() { + height: $header-height * 0.8; + } + + } + + .page-main-content-middle { + box-sizing: border-box; + width: 100%; + display: flex; + justify-content: center; + padding: $component-interspace 0; + + +keep-tablet() { + padding: $component-interspace * 0.8 0; + } + + +keep-mobile() { + padding: $component-interspace * 0.6 0; + } + + .main-content { + position: relative; box-sizing: border-box; + width: $main-content-width; + max-width: $content-max-width; + height: 100%; transition(); - &.hide { - transform: translateY(-102%); - } - - .header-shrink & { - height: $header-shrink-height; - - +keep-tablet() { - height: $header-shrink-height * 0.9; - } - - +keep-mobile() { - height: $header-shrink-height * 0.8; - } - } - - +keep-tablet() { - height: $header-height * 0.9; - padding-left: 0 !important; - } - - - +keep-mobile() { - height: $header-height * 0.8; - } - - } - - .page-main-content-middle { - box-sizing: border-box; - width: 100%; - display: flex; - justify-content: center; - padding: $component-interspace 0; - - +keep-tablet() { - padding: $component-interspace * 0.8 0; + width: $main-content-width-tablet; } +keep-mobile() { - padding: $component-interspace * 0.6 0; - } - - .main-content { - position: relative; - box-sizing: border-box; - width: $main-content-width; - max-width: $content-max-width; - height: 100%; - transition(); - - +keep-tablet() { - width: $main-content-width-tablet; - } - - +keep-mobile() { - width: $main-content-width-mobile; - } + width: $main-content-width-mobile; } } + } - .page-main-content-bottom { - width: 100%; - } + .page-main-content-bottom { + width: 100%; } } diff --git a/source/css/style.styl b/source/css/style.styl index 0b5e82b..5a35b56 100644 --- a/source/css/style.styl +++ b/source/css/style.styl @@ -6,6 +6,7 @@ @import "layout/_partial/local-search.styl" @import "layout/_partial/toc.styl" @import "layout/_partial/comment/comment.styl" +@import "layout/_partial/progress-bar.styl" @import "layout/_partial/header.styl" @import "layout/_partial/tools.styl" @import "layout/_partial/side-tools.styl" diff --git a/source/js/utils.js b/source/js/utils.js index 4205f5c..dda0621 100644 --- a/source/js/utils.js +++ b/source/js/utils.js @@ -4,11 +4,13 @@ KEEP.initUtils = () => { html_root_dom: document.querySelector('html'), pageContainer_dom: document.querySelector('.page-container'), - headerProgress_dom: document.querySelector('.header-progress'), pageTop_dom: document.querySelector('.page-main-content-top'), firstScreen_dom: document.querySelector('.first-screen-container'), + scrollProgressBar_dom: document.querySelector('.scroll-progress-bar'), + loadingProgressBar_dom: document.querySelector('.loading-progress-bar'), innerHeight: window.innerHeight, + loadingProgressBarTimer: null, prevScrollValue: 0, defaultFontSize: 0, @@ -31,9 +33,9 @@ KEEP.initUtils = () => { const percent = Math.round(scrollTop / (scrollHeight - clientHeight) * 100).toFixed(0); const ProgressPercent = (scrollTop / (scrollHeight - clientHeight) * 100).toFixed(3); - if (this.headerProgress_dom) { - this.headerProgress_dom.style.visibility = percent === '0' ? 'hidden' : 'visible'; - this.headerProgress_dom.style.width = `${ProgressPercent}%`; + if (this.scrollProgressBar_dom) { + this.scrollProgressBar_dom.style.visibility = percent === '0' ? 'hidden' : 'visible'; + this.scrollProgressBar_dom.style.width = `${ProgressPercent}%`; } // hide header handle @@ -125,7 +127,7 @@ KEEP.initUtils = () => { }); }, - // go comment + // go comment anchor goComment() { this.goComment_dom = document.querySelector('.go-comment'); if (this.goComment_dom) { @@ -150,12 +152,10 @@ KEEP.initUtils = () => { // init page height handle initPageHeightHandle() { if (this.firstScreen_dom) return; - - const temp_h1 = this.getElementHeight('.header-progress'); - const temp_h2 = this.getElementHeight('.page-main-content-top'); - const temp_h3 = this.getElementHeight('.page-main-content-middle'); - const temp_h4 = this.getElementHeight('.page-main-content-bottom'); - const allDomHeight = temp_h1 + temp_h2 + temp_h3 + temp_h4; + const temp_h1 = this.getElementHeight('.page-main-content-top'); + const temp_h2 = this.getElementHeight('.page-main-content-middle'); + const temp_h3 = this.getElementHeight('.page-main-content-bottom'); + const allDomHeight = temp_h1 + temp_h2 + temp_h3; const innerHeight = window.innerHeight; const pb_dom = document.querySelector('.page-main-content-bottom'); if (allDomHeight < innerHeight) { @@ -245,6 +245,37 @@ KEEP.initUtils = () => { post && post.forEach(v => { v.innerHTML = this.getHowLongAgo(Date.now() - new Date(v.dataset.date).getTime()) }) + }, + + // loading progress bar start + loadingProgressBarStart() { + this.loadingProgressBarTimer && clearInterval(this.loadingProgressBarTimer); + this.loadingProgressBar_dom.style.width = '0'; + this.scrollProgressBar_dom.classList.add('hide'); + + let width = 20; + const maxWidth = 95; + + this.loadingProgressBar_dom.classList.add('show'); + this.loadingProgressBar_dom.style.width = width + '%'; + + this.loadingProgressBarTimer = setInterval(() => { + width += parseInt((Math.random() * 10).toFixed(2)); + if (width > maxWidth) width = maxWidth; + this.loadingProgressBar_dom.style.width = width + '%'; + }, 100); + }, + + // loading progress bar end + loadingProgressBarEnd() { + this.loadingProgressBarTimer && clearInterval(this.loadingProgressBarTimer); + this.loadingProgressBar_dom.style.width = '100%'; + + const tempTimeout = setTimeout(() => { + this.loadingProgressBar_dom.classList.remove('show'); + this.scrollProgressBar_dom.classList.remove('hide'); + clearTimeout(tempTimeout); + }, 200); } }