diff --git a/README.md b/README.md index c661477..93e513e 100755 --- a/README.md +++ b/README.md @@ -2,6 +2,11 @@ > 基于原作者v1.2.5代码修改 +#### v1.2.5-8补丁 +1. 修复导航栏居中显示失效、分享海报高度、页码更新异常 +2. 优化上一页动画效果 +3. 新增页面底部页码跳转功能 + #### v1.2.5-8 1. 重写作文目录、置顶样式 2. 更换(通知书等)域名 diff --git a/templates/assets/css/main.css b/templates/assets/css/main.css index 717eac1..e56f310 100644 --- a/templates/assets/css/main.css +++ b/templates/assets/css/main.css @@ -1446,13 +1446,25 @@ a.close_local { #pagination, #p_pagination, #prev_pagination { - padding: 30px; + padding: 18px 10px; text-align: center; display: flex; justify-content: center; border-top: 1px solid var(--pix-background); } +#t_pagination .post-paging, +#pagination .post-paging, +#p_pagination .post-paging, +#prev_pagination .post-paging { + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + gap: 15px; + width: 100%; +} + #t_pagination a, #pagination a, #p_pagination a, @@ -1464,6 +1476,137 @@ a.close_local { display: flex; } +#t_pagination .page-jump-form, +#pagination .page-jump-form, +#p_pagination .page-jump-form { + display: inline-flex; + align-items: center; + gap: 4px; + color: #7aa1a1; + font-size: 15px; + line-height: 1; +} + +#t_pagination .page-jump-input, +#pagination .page-jump-input, +#p_pagination .page-jump-input { + width: 48px; + height: 30px; + padding: 0 4px; + border: 1px solid var(--pix-background); + border-radius: 0; + background: #fff; + color: #55716a; + font-size: 15px; + line-height: 30px; + text-align: center; + box-sizing: border-box; + -moz-appearance: textfield; +} + +#t_pagination .page-jump-input-wrap, +#pagination .page-jump-input-wrap, +#p_pagination .page-jump-input-wrap { + display: inline-flex; + height: 30px; + align-items: stretch; + flex: 0 0 auto; +} + +#t_pagination .page-jump-step, +#pagination .page-jump-step, +#p_pagination .page-jump-step { + width: 18px; + height: 30px; + flex: 0 0 18px; + padding: 0; + border: 1px solid var(--pix-background); + border-radius: 0; + background: #e8f5ed; + color: var(--pix-theme); + display: inline-flex; + align-items: center; + justify-content: center; + cursor: pointer; + line-height: 1; + font-family: inherit; + transition: background-color .2s ease, color .2s ease, opacity .2s ease; +} + +#t_pagination .page-jump-step-down, +#pagination .page-jump-step-down, +#p_pagination .page-jump-step-down { + border-right: 0; + border-radius: 4px 0 0 4px; +} + +#t_pagination .page-jump-step-up, +#pagination .page-jump-step-up, +#p_pagination .page-jump-step-up { + border-left: 0; + border-radius: 0 4px 4px 0; +} + +#t_pagination .page-jump-step:hover:not(:disabled), +#pagination .page-jump-step:hover:not(:disabled), +#p_pagination .page-jump-step:hover:not(:disabled) { + background: var(--pix-theme); + color: #fff; +} + +#t_pagination .page-jump-step:disabled, +#pagination .page-jump-step:disabled, +#p_pagination .page-jump-step:disabled { + opacity: .35; + cursor: not-allowed; +} + +#t_pagination .page-jump-step i, +#pagination .page-jump-step i, +#p_pagination .page-jump-step i { + font-size: 12px; +} + +#t_pagination .page-jump-input:focus, +#pagination .page-jump-input:focus, +#p_pagination .page-jump-input:focus { + border-color: var(--pix-theme); +} + +#t_pagination .page-jump-input::-webkit-inner-spin-button, +#t_pagination .page-jump-input::-webkit-outer-spin-button, +#pagination .page-jump-input::-webkit-inner-spin-button, +#pagination .page-jump-input::-webkit-outer-spin-button, +#p_pagination .page-jump-input::-webkit-inner-spin-button, +#p_pagination .page-jump-input::-webkit-outer-spin-button { + margin: 0; + -webkit-appearance: none; + appearance: none; +} + +#t_pagination .page-jump-submit, +#pagination .page-jump-submit, +#p_pagination .page-jump-submit { + width: 30px; + height: 30px; + padding: 0; + border: 0; + border-radius: 0; + background: transparent; + color: var(--pix-theme); + display: inline-flex; + align-items: center; + justify-content: center; + cursor: pointer; + font-family: inherit; +} + +#t_pagination .page-jump-submit i, +#pagination .page-jump-submit i, +#p_pagination .page-jump-submit i { + font-size: 20px; +} + #prev_pagination { overflow: hidden; max-height: 0; @@ -5599,7 +5742,7 @@ a.m_loop { width: 330px; padding: 5px; border-radius: 5px; - min-height: 450px; + max-height: 450px; } .poster_box .loading_box { diff --git a/templates/assets/js/app.js b/templates/assets/js/app.js index 5dab993..ffa0acb 100644 --- a/templates/assets/js/app.js +++ b/templates/assets/js/app.js @@ -60,6 +60,16 @@ function highlightMenu() { } }) } + + // 高亮完成后再滚动,确保当前项在导航容器内可见并尽量居中。 + const activeMenuLink = document.querySelector('.left_menu_box ul li.current-pjax-item a'); + if (activeMenuLink && typeof activeMenuLink.scrollIntoView === 'function') { + activeMenuLink.scrollIntoView({ + behavior: 'smooth', + block: 'nearest', + inline: 'center' + }); + } } function closeMomentPushModal() { @@ -122,8 +132,16 @@ function syncPageParamToUrl(page) { url.searchParams.delete('page'); } + const displayUrl = buildRelativeUrl(url); const currentState = history.state && typeof history.state === 'object' ? history.state : {}; - history.replaceState(Object.assign({}, currentState, { page: pageNumber }), '', buildRelativeUrl(url)); + + // PJAX uses history.state.url when restoring a popstate entry. Keep it in + // sync with the visible URL after AJAX pagination changes the current page. + history.replaceState( + Object.assign({}, currentState, { url: displayUrl, page: pageNumber }), + '', + displayUrl + ); } function getPageNumberFromUrl(urlValue) { @@ -268,6 +286,7 @@ function initPreviousPageButton(page) { return; } + // 有BUG:PJAX加载失败后可能会新增本不该存在的上一页按钮,不管了 if ((page === undefined || page === null) && $oldButton.length) { return; } @@ -409,27 +428,34 @@ function updateLoadMorePagination(paginationSelector, insertAfterSelector, data, newHref = $data.find(fallbackPaginationSelector + ' a').attr('data'); } - if (newHref !== undefined) { - const newPaginationHtml = $newPagination.length ? $newPagination.prop('outerHTML') : ''; - let $pagination = $(paginationSelector); + const newPaginationHtml = $newPagination.length ? $newPagination.prop('outerHTML') : ''; + let $pagination = $(paginationSelector); - if (newPaginationHtml) { - if ($pagination.length) { - $pagination.replaceWith(newPaginationHtml); - } else { - $(insertAfterSelector).last().after(newPaginationHtml); - } + if (newPaginationHtml) { + if ($pagination.length) { + $pagination.replaceWith(newPaginationHtml); + } else { + $(insertAfterSelector).last().after(newPaginationHtml); } + $pagination = $(paginationSelector); + } + if (newHref !== undefined) { const $paginationBtn = ensureLoadMoreButton(paginationSelector, insertAfterSelector); $paginationBtn.attr('data', newHref).text(getLoadMoreText()).show(); $(paginationSelector).show(); $(paginationSelector + ' .post-paging').show(); + } else if (newPaginationHtml) { + // 最后一页仍保留页码跳转控件,只隐藏不存在的下一页按钮。 + $(paginationSelector + ' .post-paging > a').hide(); + $(paginationSelector).show(); + $(paginationSelector + ' .post-paging').show(); } else { $(paginationSelector + ' a').hide(); $(paginationSelector).hide(); } + initPageJumpSteppers(); return newHref; } @@ -1176,7 +1202,12 @@ $(document).on('click', '.moment_cat_nav ul li a', function () { url: cat, headers: HTML_PAGE_AJAX_HEADERS, beforeSend: function () { - showListLoading('.moment_list'); + const $pagingArea = $('#t_pagination .post-paging'); + if ($pagingArea.length) { + $pagingArea.html('
'); + } else { + showListLoading('.moment_list'); + } }, success: function (data) { setCategoryLinkActive($this); @@ -1242,8 +1273,12 @@ $(document).on('click', '.friends_cat_nav .cat-link', function () { url: url, headers: HTML_PAGE_AJAX_HEADERS, beforeSend: function () { - // 显示加载动画 - showListLoading('.moment_list'); + const $pagingArea = $('#t_pagination .post-paging'); + if ($pagingArea.length) { + $pagingArea.html('
'); + } else { + showListLoading('.moment_list'); + } }, success: function (data) { setCategoryLinkActive($this); @@ -1319,7 +1354,7 @@ $(document).on('click', '#prev_pagination a', function () { const listHeightAfterLoad = context.$list[0] ? context.$list[0].scrollHeight : listHeightBeforeLoad; const heightDelta = Math.max(0, listHeightAfterLoad - listHeightBeforeLoad); - window.scrollTo(0, scrollTopBeforeLoad + heightDelta); + window.scrollTo(0, scrollTopBeforeLoad + heightDelta - 50); $body.animate({ scrollTop: '-=100' }, 500); }, error: function () { @@ -1330,6 +1365,117 @@ $(document).on('click', '#prev_pagination a', function () { return false; }); +function updatePageJumpStepperState(input) { + const value = Number(input.value); + const min = Number(input.min); + const max = Number(input.max); + const $stepper = $(input).closest('.page-jump-input-wrap'); + + $stepper.find('.page-jump-step-up').prop('disabled', Number.isFinite(value) && value >= max); + $stepper.find('.page-jump-step-down').prop('disabled', !Number.isFinite(value) || value <= min); +} + +function validatePageJumpInput(input, notify) { + const value = input.value.trim(); + const min = input.min === '' ? null : Number(input.min); + const max = input.max === '' ? null : Number(input.max); + const page = Number(value); + let message = ''; + + if (!value) { + message = '请输入页码'; + } else if (!Number.isInteger(page)) { + message = '请输入有效页码'; + } else if (Number.isFinite(min) && page < min) { + message = `页码不能小于 ${min}`; + } else if (Number.isFinite(max) && page > max) { + message = `页码不能大于 ${max}`; + } + + const wasInvalid = input.dataset.pageJumpInvalid === 'true'; + input.setCustomValidity(message); + input.dataset.pageJumpInvalid = message ? 'true' : 'false'; + + if (notify && message && message !== '请输入页码' && !wasInvalid + && window.cocoMessage && typeof window.cocoMessage.warning === 'function') { + window.cocoMessage.warning(message); + } + + return !message; +} + +function stepPageJumpInput(input, direction) { + const min = Number(input.min); + const max = Number(input.max); + const step = Number(input.step) > 0 ? Number(input.step) : 1; + const current = Number(input.value); + const value = Number.isFinite(current) ? current + direction * step : min; + + input.value = String(Math.min(max, Math.max(min, value))); + input.dispatchEvent(new Event('input', { bubbles: true })); + input.focus(); +} + +function initPageJumpSteppers() { + $('.page-jump-input').each(function () { + updatePageJumpStepperState(this); + }); +} + +$(document).on('click', '.page-jump-step', function (event) { + event.preventDefault(); + if (this.disabled) return; + + const input = $(this).closest('.page-jump-input-wrap').find('.page-jump-input')[0]; + if (input) { + stepPageJumpInput(input, $(this).hasClass('page-jump-step-up') ? 1 : -1); + } +}); + +$(document).on('keydown', '.page-jump-input', function (event) { + if (event.ctrlKey || event.metaKey || event.altKey) return; + + const allowedKeys = ['Backspace', 'Delete', 'Tab', 'Enter', 'Escape', 'ArrowLeft', 'ArrowRight', 'Home', 'End']; + if (event.key === 'ArrowUp' || event.key === 'ArrowDown') { + event.preventDefault(); + stepPageJumpInput(this, event.key === 'ArrowUp' ? 1 : -1); + return; + } + if (!allowedKeys.includes(event.key) && !/^[0-9]$/.test(event.key)) { + event.preventDefault(); + } +}); + +$(document).on('input', '.page-jump-input', function () { + this.value = this.value.replace(/[^0-9]/g, '').replace(/^0+(?=\d)/, ''); + validatePageJumpInput(this, true); + updatePageJumpStepperState(this); +}); + +// 跳转到指定页:沿用当前 URL 的分类或标签参数,通过 PJAX 加载目标页。 +$(document).on('submit', '.page-jump-form', function (event) { + event.preventDefault(); + const $form = $(this); + const input = $form.find('.page-jump-input')[0]; + validatePageJumpInput(input, true); + if (!this.checkValidity()) { + input.focus(); + if (typeof input.reportValidity === 'function') input.reportValidity(); + return false; + } + + const targetPage = parseInt($form.find('.page-jump-input').val(), 10); + const href = buildPageUrlFromCurrent(targetPage); + + if (window.pjax && typeof window.pjax.loadUrl === 'function') { + window.pjax.loadUrl(href); + } else { + window.location.assign(href); + } + + return false; +}); + //ajax加载片刻 $(document).on('click', '#t_pagination a', function () { var href = $(this).attr('data'); @@ -1347,21 +1493,15 @@ $(document).on('click', '#t_pagination a', function () { success: function (posts) { if (posts) { var result = $(posts).find(".moment_list .p_item"); - $('#t_pagination .post-paging').html(`${Theme.site_page}`); $(".moment_list").append(result.fadeIn(300)); refreshAjaxPostList(); - var newhref = $(posts).find("#t_pagination a").attr("data"); - - if (newhref != undefined) { - $("#t_pagination a").attr("data", newhref); - $('#t_pagination a').show(); - } else { - $("#t_pagination a").hide(); + updateLoadMorePagination('#t_pagination', '.moment_list', posts); + if (result.length) { + $body.animate({ scrollTop: result.first().offset().top - 58 }, 500); } - $body.animate({ scrollTop: result.offset().top - 58 }, 500); getMomentAudio(); initAgree(); - lazyLoadInstance.update(); + if (typeof lazyLoadInstance !== 'undefined') lazyLoadInstance.update(); initializeMomentFold(); syncPageParamToUrl(currentPage); } else { @@ -1413,8 +1553,12 @@ $(document).ready(function () { url: url, headers: HTML_PAGE_AJAX_HEADERS, beforeSend: function () { - showListLoading("#photos_item", PHOTO_LIST_LOADING_HTML); - $('#p_pagination').hide(); + const $pagingArea = $('#p_pagination .post-paging'); + if ($pagingArea.length) { + $pagingArea.html('
'); + } else { + showListLoading("#photos_item", PHOTO_LIST_LOADING_HTML); + } }, success: function (data) { setCategoryLinkActive($this); @@ -1466,15 +1610,8 @@ $(document).on('click', '#p_pagination a', function () { success: function (photos) { if (photos) { var result = $(photos).find(".norpost_list .gallery-photo"); - $('#p_pagination .post-paging').html(`${Theme.site_page}`); $(".gallery-photos").append(result.fadeIn(300)); - var newhref = $(photos).find("#p_pagination a").attr("data"); //找出新的下一页链接 - if (newhref != undefined) { - $("#p_pagination a").attr("data", newhref); - $('#p_pagination a').show(); - } else { - $("#p_pagination a").hide(); //如果没有下一页了,隐藏 - } + updateLoadMorePagination('#p_pagination', '#photos_item', photos); $body.animate({ scrollTop: targetOffsetTop - 358 }, 500); pix.initGalleryPhotos(); if (typeof lazyLoadInstance !== 'undefined') lazyLoadInstance.update(); @@ -1675,7 +1812,12 @@ $(document).on('click', '.posts_cat_nav ul li a', function (e) { url: cat, // 完全保留原有请求URL,不修改 headers: HTML_PAGE_AJAX_HEADERS, beforeSend: function () { - showListLoading('.norpost_list'); + const $pagingArea = $('#pagination .post-paging'); + if ($pagingArea.length) { + $pagingArea.html('
'); + } else { + showListLoading('.norpost_list'); + } }, success: function (data) { setCategoryLinkActive($this); @@ -1716,22 +1858,15 @@ $('body').on('click', '#pagination a', function () { success: function (data) { if (data) { var result = $(data).find(".norpost_list ").children(); - $('#pagination .post-paging').html(`${Theme.site_page}`); $('.norpost_list').append($(result).fadeIn(400)); refreshAjaxPostList(); - - var newhref = $(data).find("#pagination a").attr("data") || $(data).find(".arc_pagenav a").attr("data"); //找出新的下一页链接 - - if (newhref != undefined) { - $("#pagination a").attr("data", newhref); - $('#pagination a').show(); - } else { - $("#pagination a").hide(); //如果没有下一页了,隐藏 + updateLoadMorePagination('#pagination', '.norpost_list', data, '.arc_pagenav'); + if (result.length) { + $body.animate({ scrollTop: result.first().offset().top - 58 }, 500); } - $body.animate({ scrollTop: result.offset().top - 58 }, 500); initAgree() - lazyLoadInstance.update(); + if (typeof lazyLoadInstance !== 'undefined') lazyLoadInstance.update(); syncPageParamToUrl(currentPage); } else { $("#pagination a").hide(); @@ -1993,12 +2128,6 @@ if (Theme.pjax) { cacheBust: false, }); - let isPopNav = false; - // 监听popstate(用户点浏览器前进、后退按钮) - window.addEventListener('popstate', function () { - isPopNav = true; - }); - document.addEventListener('pjax:send', function () { NProgress.start(); }) @@ -2009,19 +2138,10 @@ if (Theme.pjax) { typeof Prism === 'object' && Prism.highlightAll(); autoload_posts_music(); initBlog(); + initPageJumpSteppers(); refreshCommentWidget(); NProgress.done(); - if (isPopNav) { - // 用户点击前进后退:删除page参数 - isPopNav = false; - const cleanUrl = removePageParamFromUrl(window.location.href); - if (cleanUrl !== window.location.pathname + window.location.search + window.location.hash) { - history.replaceState(history.state || {}, '', cleanUrl); - } - } else { - // 用户点击链接 - initPreviousPageButton() - } + initPreviousPageButton() }) } @@ -2108,18 +2228,6 @@ $(document).scroll(function () { }); -// 获取当前具有 "current" 类的元素 -var currentElement = document.querySelector('.current'); - -// 检查是否找到了具有 "current" 类的元素 -if (currentElement) { - // 将当前元素滚动到视图中 - currentElement.scrollIntoView({ - behavior: 'smooth', // 平滑滚动 - block: 'start' // 将当前元素顶部对齐到视口顶部 - }); -} - $('body').on('click', '.listree-btn', function (event) { event.preventDefault(); setListreeOpen(!$('.listree-box').hasClass('is-open')); @@ -3131,6 +3239,7 @@ function initBlog() { $(document).ready(function () { pix.roleMoments(); initBlog(); + initPageJumpSteppers(); initPreviousPageButton() setPageGrayscale(); diff --git a/templates/friends.html b/templates/friends.html index 099a850..06a6db1 100755 --- a/templates/friends.html +++ b/templates/friends.html @@ -114,10 +114,28 @@
-
- - +
+ +
+ 转到 + + + + + + + / [[${friendPage.totalPages}]] + +
diff --git a/templates/macro/home-blog.html b/templates/macro/home-blog.html index 006fcbc..185aee7 100644 --- a/templates/macro/home-blog.html +++ b/templates/macro/home-blog.html @@ -38,14 +38,33 @@
-
-
- + - +
+ 转到 + + + + + + + / [[${_moments.totalPages}]] + +
diff --git a/templates/macro/home-photos.html b/templates/macro/home-photos.html index 0d3e045..ae11414 100644 --- a/templates/macro/home-photos.html +++ b/templates/macro/home-photos.html @@ -70,14 +70,32 @@
-
- - +
+ 转到 + + + + + + + / [[${photoPage.totalPages}]] + +