HEIGE-PCloud / DoIt

A clean, elegant and advanced blog theme for Hugo.
https://hugodoit.pages.dev
MIT License
794 stars 196 forks source link

[FEATURE] Some feature:支持pjax刷新 #78

Closed GaHoWong closed 3 years ago

GaHoWong commented 3 years ago

Describe the feature you want 描述你的功能需求

你好,我最近遇到了一些棘手的问题,在我使用APlayer音乐播放器当作背景音乐时,当我点击主题的其他地方,音乐就会刷新并重新播放,这种体验很糟糕。也让我很苦恼,当我去寻找解决方法是发现使用PJAX可以完美解决我的问题,我还发现hexo最热门的那几个主题同样使用了PJAX,比如next、butterfly、sakura、material-x等等主题。

使用pjax的体验很好,在点击其它地方时,比如footer、header这些可以不用重复加载,减少服务器压力,提高加载速度,提升用户体验。

pjax具有以下优点: 按需请求,每次只需加载页面的部分内容,而不用重复加载一些公共的资源文件和不变的页面结构,大大减小了数据请求量,以减轻对服务器的带宽和性能压力,还大大提升了页面的加载速度 常规页面跳转需要重新加载画面上的内容,会有明显的闪烁,而且往往和跳转前的页面没有连贯性,用户体验不是很好。如果再遇上页面比较庞大、网速又不是很好的情况,用户体验就更加雪上加霜了。使用pjax后,由于只刷新部分页面,切换效果更加流畅,而且可以定制过度动画,在等待页面加载的时候体验就比较舒服了。

Useful reference 有价值的参考

If available, provide useful links to fulfill the feature. 如果可以的话, 提供实现这个功能的相关参考链接. 1.pjax使用小结:https://www.jianshu.com/p/557cad38e7dd 2.让你的网站实现 pjax 无刷新:https://paugram.com/coding/add-pjax-to-your-website.html 3.这是一个运用了pjax的hugo主题:https://github.com/vvc-Dream/hugo-maupassant-pjax

HEIGE-PCloud commented 3 years ago

pjax刷新确实是一个很有用的功能,但使用它需要修改大量代码。我会试着进行修改,但很难在短期内添加pjax的支持 UwU

GaHoWong commented 3 years ago

pjax刷新确实是一个很有用的功能,但使用它需要修改大量代码。我会试着进行修改,但很难在短期内添加pjax的支持 UwU

好,这是个长期且困难的计划,短期内确实很难实现,有你这句话我就放心。love it and just do It! 加油

HEIGE-PCloud commented 3 years ago

大部分的修改已经做完了,但是一直没有能够解决一个非常关键的问题。

类似于这个 issue https://github.com/MoOx/pjax/issues/230 DoIt 主题在不同页面上会有不同数量和内容的 <script> tag,所以所有可以开关的 script(如 KaTeX,lightgallery)都需要进行 pjax-reload。

我的实现方式是将所有 script (包括部分 CSS)拆分进两个不同的 <div> 中。

<div class="assets">
    <script type="text/javascript" src="/lib/autocomplete/autocomplete.min.js"></script>
    <script type="text/javascript" src="/lib/algoliasearch/algoliasearch-lite.umd.min.js"></script>
    <script type="text/javascript" src="/lib/lazysizes/lazysizes.min.js"></script>
    <script type="text/javascript" src="/lib/topbar/topbar.min.js"></script>
    <script type="text/javascript" src="/lib/pjax/pjax.min.js"></script>
    <script type="text/javascript" src="/js/theme.min.js"></script>
</div>
<div class="pjax-assets">
    <script type="text/javascript" src="/lib/lightgallery/lightgallery.min.js"></script>
    <script type="text/javascript" src="/lib/lightgallery/lg-thumbnail.min.js"></script>
    <script type="text/javascript" src="/lib/lightgallery/lg-zoom.min.js"></script>
    <script type="text/javascript" src="/lib/clipboard/clipboard.min.js"></script>
    <script type="text/javascript" src="/lib/sharer/sharer.min.js"></script>
    <script type="text/javascript">window.config={"code":{"copyTitle":"Copy to clipboard","maxShownLines":10},"comment":{},"lightGallery":{"actualSize":false,"exThumbImage":"data-thumbnail","hideBarsDelay":2000,"selector":".lightgallery","speed":400,"thumbContHeight":80,"thumbWidth":80,"thumbnail":true},"search":{"algoliaAppID":"5YGRNRQK1G","algoliaIndex":"en_index","algoliaSearchKey":"0ff6874805de24b84aa1d5ebccad56cd","highlightTag":"em","maxResultLength":10,"noResultsFound":"No results found","snippetLength":30,"type":"algolia"},"sharerjs":true};</script>
    <link rel="stylesheet" href="/lib/lightgallery/lightgallery.min.css">
</div>

assets 中存放的是所有不需要刷新,也不会有变动的 script,而 pjax-assets 则会被整个刷新(selectors: [".pjax-assets", ...])。但是在更新后,<div> 中所有的 <script> tag 都会被移除,而其他 tag (如 <link>)则不受影响。 pjax 的日志中 oldElnewEl 也没有问题,不知道是在哪一步做的过滤。我尝试了不同的 switch callbacks,但并没有能解决这个问题。

我现在正在试着重写 switch callback,手动将 newEl 中的元素添加到 pjax-asssets 里,不知道能否解决这个问题。

想请教一下,有没有同学知道如何解决这个问题,或是有相关的博客文章,感谢!

PaperStrike commented 3 years ago

在更新后,<div> 中所有的 <script> tag 都会被移除,而其他 tag (如 <link>)则不受影响

这是因为动态执行脚本需要 JS 中构造全新脚本元素(可见 执行 - Pjax 的 2021 重构),MoOx/pjax 大多数时候选择将构造的新 <script> 放到 <head> 里(不清楚动机,而且的确会影响一些依赖自身 DOM 位置的脚本)。

具体到源码,

  1. 各元素 switch 完成后(afterAllSwitches),对 selectors 选择的每个元素调用一次 executeScripthttps://github.com/MoOx/pjax/blob/480334b18253c721ba648675e90261f948e2bca0/index.js#L208-L213

  2. executeScript 获取传递元素内部 <script>,将其从其父元素移除,执行(evalScript): https://github.com/MoOx/pjax/blob/480334b18253c721ba648675e90261f948e2bca0/lib/execute-scripts.js#L10-L17

  3. evalScript 在传递的 <script> 无父元素时,放到 <head> 等元素里执行: https://github.com/MoOx/pjax/blob/480334b18253c721ba648675e90261f948e2bca0/lib/eval-script.js#L4-L5

只要 .pjax-asssets 中的脚本不依赖自身所属的 DOM 元素位置,虽然在 .pjax-asssets 里看不到了,其执行不会受到什么影响。如果有那样的依赖,就需要改写 MoOx/pjax 源码,或换其他的 Pjax 库这样子。