next-theme / hexo-theme-next

🎉 Elegant and powerful theme for Hexo.
https://theme-next.js.org
Other
2.34k stars 420 forks source link

文章目录项目不能正确的被高亮 #149

Closed SharryXu closed 3 years ago

SharryXu commented 3 years ago

Issue Checklist


Expected behavior

  1. 最后一个导航选项能被选中,然后网页滚动到最底部。

Actual behavior

  1. 滚动到了最底部。
  2. 但是仍然选中(高亮)了倒数第二个导航选项。

issue

Steps to reproduce the behavior

  1. 打开网址 https://blog.sharryxu.com/2020/11/27/surface-go2-user-experience/
  2. 点击左下角的箭头,打开侧边栏。
  3. 点击最后一个导航选项。
  4. 选择最后的一个导航选项。

Environment Information

Node.js and NPM Information

Node version:
v14.15.1
NPM version:
6.14.8

Package dependencies Information

hexo-site@0.0.0 C:\Users\Sharry.xu\Desktop\blog\blog
+-- hexo@5.2.0
+-- hexo-deployer-git@2.1.0
+-- hexo-deployer-rsync@1.0.0
+-- hexo-generator-archive@1.0.0
+-- hexo-generator-category@1.0.0
+-- hexo-generator-index@2.0.0
+-- hexo-generator-searchdb@1.3.3
+-- hexo-generator-tag@1.0.0
+-- hexo-renderer-ejs@1.0.0
+-- hexo-renderer-markdown-it@5.0.0
+-- hexo-renderer-stylus@2.0.1
+-- hexo-server@2.0.0
+-- hexo-tag-replace@0.1.0
+-- markdown-it@12.0.2
+-- markdown-it-abbr@1.0.4
+-- markdown-it-emoji@2.0.0
+-- markdown-it-footnote@3.0.2
+-- markdown-it-ins@3.0.0
+-- markdown-it-sub@1.0.0
`-- markdown-it-sup@1.0.0

Hexo Configuration

# Hexo Configuration
## Docs: https://hexo.io/docs/configuration.html
## Source: https://github.com/hexojs/hexo/

# Site
title: Sharry
subtitle:
description: Stay Hungry, Stay Foolish.
author: Sharry Xu
language: zh-Hans
timezone: Asia/Shanghai
email: sharry.r.xu@gmail.com

# URL
## If your site is put in a subdirectory, set url as 'http://yoursite.com/child' and root as '/child/'
url: https://blog.sharryxu.com
root: /
permalink: :year/:month/:day/:title/
permalink_defaults:

# Directory
source_dir: source
public_dir: public
tag_dir: tags
archive_dir: archives
category_dir: categories
code_dir: downloads/code
i18n_dir: :lang
skip_render:

# Writing
new_post_name: :title.md # File name of new posts
default_layout: post
titlecase: false # Transform title into titlecase
filename_case: 0
render_drafts: false
post_asset_folder: true
relative_link: false
future: true
highlight:
  enable: true
  line_number: true
  auto_detect: false
  tab_replace: ''
  wrap: true
  hljs: false

# Home page setting
# path: Root path for your blogs index page. (default = '')
# per_page: Posts displayed per page. (0 = disable pagination)
# order_by: Posts order. (Order by date descending by default)
index_generator:
  path: ''
  per_page: 10
  order_by: -date

# Category & Tag
default_category: uncategorized
category_map:
tag_map:

# Date / Time format
## Hexo uses Moment.js to parse and display date
## You can customize the date format as defined in
## http://momentjs.com/docs/#/displaying/format/
date_format: YYYY-MM-DD
time_format: HH:mm:ss

# Pagination
## Set per_page to 0 to disable pagination
per_page: 10
pagination_dir: page

# Extensions
## Plugins: https://hexo.io/plugins/
## Themes: https://hexo.io/themes/
theme: "next"

# Deployment
## Docs: https://hexo.io/docs/deployment.html
deploy:
  type: rsync
  host: blog.sharryxu.com
  user: sharry
  root: /home/sharry/data/www
  port: 22
  delete: true
  verbose: true
  ignore_errors: false

# Markdown
markdown:
  preset: 'default'
  render:
    html: true
    xhtmlOut: false
    breaks: true
    linkify: true
    typographer: true
    quotes: '“”‘’'
  plugins:
    - markdown-it-abbr
    - markdown-it-footnote
    - markdown-it-ins
    - markdown-it-sub
    - markdown-it-sup
    - markdown-it-attrs
  anchors:
    level: 2 # Minimum level for ID creation. (Ex. h2 to h6)
    collisionSuffix: 'v' # A suffix that is prepended to the number given if the ID is repeated.
    permalink: true # If true, creates an anchor tag with a permalink besides the heading.
    permalinkClass: header-anchor # Class used for the permalink anchor tag.
    permalinkSymbol: '' # The symbol used to make the permalink.

tag_replace:
  enable: true
  image:
    absolute_path: https://resources.sharryxu.com/blog/articles

NexT Configuration

favicon:
  small: https://s.gravatar.com/avatar/be79faa5b40b39e1363ef1f1d5abb922?s=16
  medium: https://s.gravatar.com/avatar/be79faa5b40b39e1363ef1f1d5abb922?s=32
  apple_touch_icon: https://s.gravatar.com/avatar/be79faa5b40b39e1363ef1f1d5abb922
  safari_pinned_tab: https://s.gravatar.com/avatar/be79faa5b40b39e1363ef1f1d5abb92

avatar:
  # Replace the default image and set the url here.
  url: https://www.gravatar.com/avatar/be79faa5b40b39e1363ef1f1d5abb922 

Other Information

我做了些初步搜索,觉得是如下的两个函数的问题。但是,可能比较不太好修。因为最后一个导航选项对应的内容占比不到一页的高度,所以导致最后一个导航选项不能被正确高亮。

文件地址 https://github.com/next-theme/hexo-theme-next/blob/master/source/js/utils.js

  registerScrollPercent: function() {
    const backToTop = document.querySelector('.back-to-top');
    const readingProgressBar = document.querySelector('.reading-progress-bar');
    // For init back to top in sidebar if page was scrolled after page refresh.
    window.addEventListener('scroll', () => {
      if (backToTop || readingProgressBar) {
        const contentHeight = document.body.scrollHeight - window.innerHeight;
        const scrollPercent = contentHeight > 0 ? Math.min(100 * window.scrollY / contentHeight, 100) : 0;
        if (backToTop) {
          backToTop.classList.toggle('back-to-top-on', Math.round(scrollPercent) >= 5);
          backToTop.querySelector('span').innerText = Math.round(scrollPercent) + '%';
        }
        if (readingProgressBar) {
          readingProgressBar.style.width = scrollPercent.toFixed(2) + '%';
        }
      }
      if (!Array.isArray(NexT.utils.sections)) return;
      let index = NexT.utils.sections.findIndex(element => {
        return element && element.getBoundingClientRect().top > 0;
      });
      if (index === -1) {
        index = NexT.utils.sections.length - 1;
      } else if (index > 0) {
        index--;
      }
      // 在这里传过来的值,是倒数第二个导航选项
      this.activateNavByIndex(index);
    });

    backToTop && backToTop.addEventListener('click', () => {
      window.anime({
        targets  : document.scrollingElement,
        duration : 500,
        easing   : 'linear',
        scrollTop: 0
      });
    });
  },

  activateNavByIndex: function(index) {
    const target = document.querySelectorAll('.post-toc li a.nav-link')[index];
    if (!target || target.classList.contains('active-current')) return;

    document.querySelectorAll('.post-toc .active').forEach(element => {
      element.classList.remove('active', 'active-current');
    });
    target.classList.add('active', 'active-current');
    let parent = target.parentNode;
    while (!parent.matches('.post-toc')) {
      if (parent.matches('li')) parent.classList.add('active');
      parent = parent.parentNode;
    }
    // Scrolling to center active TOC element if TOC content is taller then viewport.
    const tocElement = document.querySelector('.sidebar-panel-container');
    window.anime({
      targets  : tocElement,
      duration : 200,
      easing   : 'linear',
      scrollTop: tocElement.scrollTop - (tocElement.offsetHeight / 2) + target.getBoundingClientRect().top - tocElement.getBoundingClientRect().top
    });
  }
welcome[bot] commented 3 years ago

Thanks for opening this issue, maintainers will get back to you as soon as possible!

issue-label-bot[bot] commented 3 years ago

Issue-Label Bot is automatically applying the label Bug to this issue, with a confidence of 0.56. Please mark this comment with :thumbsup: or :thumbsdown: to give our bot feedback!

Links: app homepage, dashboard and code for this bot.

stevenjoezhang commented 3 years ago

其实没问题,因为判定点是屏幕最上方,而不是屏幕中心,因此直到「注意事项」到达屏幕最上方前,高亮的项目都是倒数第二个导航选项。

SharryXu commented 3 years ago

Hi @stevenjoezhang ,非常感谢您的快速回复 👍 ,我想的是能否在滚动后,再判断点击的是哪个选项,然后赋予相应的 Class 参数?这样的话,确实会给人的感觉好很多,您觉得呢?不然容易给人造成一种选不上的感觉。。。

stevenjoezhang commented 3 years ago

谢谢反馈,但问题是即使在点击之后,最后一个选项正确高亮了,用户一旦滚动页面,即使只滚动了1个像素,高亮的项目就会跃变回倒数第二个,这同样是非常不自然的。

SharryXu commented 3 years ago

因为这个问题是由于最后一个导航项目所对应的内容不足一页高度导致的,所以理论上你向上滚动鼠标,不管多少,都会带入上一节的内容,所以高亮的项目会因此发生改变是合理的,你觉得呢?

stevenjoezhang commented 3 years ago

我不确定,对于代码逻辑合理的现象,对于用户而言或许是反直觉的。也许可以看看其他网站/主题是怎么处理的?

SharryXu commented 3 years ago

嗯嗯,有道理,回头我仔细研究下。再次感谢楼主 👍 。有空了我直接提交 PR,到时候你看看合不合理 😄

stevenjoezhang commented 3 years ago

看到了一篇用 IntersectionObserver 实现的文章: https://www.zhangxinxu.com/wordpress/2020/12/js-intersectionobserver-nav/

NexT 曾经也用过 IntersectionObserver : https://github.com/theme-next/hexo-theme-next/pull/1125 后来又修改了一次,因为这样判断逻辑是单向的,比较简单和直接。 要彻底解决这个问题,可能需要考虑用户的历史操作,例如点击了哪个选项,是向上还是向下滚动,滚动到位之前用户是否进行了其它操作,等等。

stevenjoezhang commented 2 years ago

这里微调了一下 #322

github-actions[bot] commented 1 year ago

This thread has been automatically locked since there has not been any recent activity after it was closed. It is possible issue was solved or at least outdated. Feel free to open new for related bugs.