参考教程

优化步骤

Pjax能够实现页面的局部刷新而非整体重载资源,在一定程度上能够减少网站反复加载重复资源,从而优化访问体验。

  1. 博主目前使用的是Butterfly主题,而最新版Butterfly主题已经将该教程方案集成在主题中。只需在主题配置文件中搜索pjax,将其enable参数设置为true即可开启。

  2. 重载第三方js

    在魔改主题时,肯定会不可避免的添加一系列第三方js,此时就会遇到切换页面后,由于通过 Pjax切换的页面并没有完全刷新,浏览器不会将网页从头执行一遍,因此有些JS将不会生效。
    得益于Butterfly已经将解决方案集成在[Blogroot]\themes\butterfly\layout\includes\third-party\pjax.pug文件下。

    1
    2
    3
    $('script[data-pjax]').each(function () {
    $(this).parent().append($(this).remove())
    })
    1
    2
    3
    4
    5
    6
    7
    document.querySelectorAll('script[data-pjax]').forEach(item => {
    const newScript = document.createElement('script')
    const content = item.text || item.textContent || item.innerHTML || ""
    Array.from(item.attributes).forEach(attr => newScript.setAttribute(attr.name, attr.value))
    newScript.appendChild(document.createTextNode(content))
    item.parentNode.replaceChild(newScript, item)
    })

    这个函数会对在script标签中添加了data-pjax属性的的js,在页面切换后执行重载,达到局部刷新的效果。
    所以我们要做的事情十分简单,给这些js引入的位置添加data-pjax属性即可。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    inject:
    head:
    # 首页电子钟
    - <link rel="stylesheet" href="/clock/css/clock.css"/>
    bottom:
    # 首页电子钟
    - <script src="/clock/js/vue.min.js"></script>
    - - <script src="/clock/js/clock.js"></script>
    + - <script data-pjax src="/clock/js/clock.js"></script>

    使用data-pjax的过程中,务必考虑到变量被反复声明的问题。例如在clock.js中,有用const定义了api密钥的常量,但是添加data-pjax之后,切换页面时会反复声明这个常量。和const的生命周期起冲突。解决方案有(以下方案二选一即可,全部都做反而有bug

    1. 把声明常量的代码放到单独的js中,并且不加data-pjax。
    2. 将const声明改成用let或者var声明。
  3. 如果不是在主题配置文件的inject中引入,而是通过在特定页面写入,可能不方便在标签处直接添加data-pjax属性,参考教程中有给出解决方案。
    可以修改[Blogroot]\themes\butterfly\layout\includes\third-party\pjax.pug的内容。给他多加一个选择器。(实质其实就是第4步的变种,可以跳过第3步直接参考第4步)

    旧版方案

    此处修改的是特定选择器,必须是pjax-reload下的第一个script标签才行。并不是很方便多行插入。请看新版方案。

    1
    2
    3
    4
    -   $('script[data-pjax]').each(function () {
    + $('script[data-pjax], .pjax-reload script').each(function () {
    $(this).parent().append($(this).remove())
    })
    1
    2
    3
    4
    5
    6
    7
    8
    -   document.querySelectorAll('script[data-pjax]').forEach(item => {
    + document.querySelectorAll('script[data-pjax], .pjax-reload script').forEach(item => {
    const newScript = document.createElement('script')
    const content = item.text || item.textContent || item.innerHTML || ""
    Array.from(item.attributes).forEach(attr => newScript.setAttribute(attr.name, attr.value))
    newScript.appendChild(document.createTextNode(content))
    item.parentNode.replaceChild(newScript, item)
    })

    然后将你需要重载的JS方法函数名或者JS片段用<div class="pjax-reload"></div>包裹起来。此处以butui.js为例。

    1
    2
    3
    4
    5
    6
    7
    -   <script src="/js/botui.js"></script>
    + <script data-pjax src="/js/botui.js"></script>
    + <div class="pjax-reload">
    <script>
    bot_ui_ini()
    </script>
    + </div>
    新版方案

    butterfly主题中,有按照第4步中所述,在pjax选择器中添加了.js-pjax的类名,也就是说,只要是在类名为js-pjax元素包裹下的内容就会执行局部重载。

    • 网页写法
      1
      2
      3
      4
      5
      6
      <div class="js-pjax">
      <script>
      bot_ui_ini()
      // 可以是函数引用,可以是代码片段。甚至可以是任何需要重载的网页元素。
      </script>
      </div>
    • pug写法
      1
      2
      3
      4
      .js-pjax
      script.
      bot_ui_ini()
      // 可以是函数引用,可以是代码片段。甚至可以是任何需要重载的网页元素。
    • markdown写法,同html写法,此处加上raw标签是为了告诉渲染引擎这段不需要渲染。
      1
      2
      3
      4
      5
      6
      7
      8
      {% raw %}
      <div class="js-pjax">
      <script>
      bot_ui_ini()
      // 可以是函数引用,可以是代码片段。甚至可以是任何需要重载的网页元素。
      </script>
      </div>
      {% endraw %}
  4. 集成在插件中的js

    集成在插件中的js是最难办的,它们往往是通过在页面中使用添加了指定iddiv等标签界定位置,然后由插件去渲染。我们按照上面的方法给这些静态标签添加pjax重载毫无意义。毕竟要重载的起码得是个js才行。

    • 可以考虑使用最新版Butterfly主题自带的pjax屏蔽设置(不推荐)。

      1
      2
      3
      4
      5
      6
      7
        pjax:
      - enable: false
      + enable: true
      exclude:
      + - /artitalk/
      + - /about/
      # 此处填页面的相对路径。
    • 但是这样子一来,如果有添加Aplayer的全局音乐或其他全局配置的话,会在切换到屏蔽了Pjax的页面时被强制刷新,不符合流畅的用户体验。那就只能修改源码了。

      此处以HCLonely开发的hexo-charts插件为例。插件中用特定iddiv标签作为定位。

      1
      2
      3
      4
      5
      6
      <!-- 发布文章统计图 -->
      <div id="posts-chart"></div>
      <!-- 文章标签统计图 -->
      <div id="tags-chart" data-length="10"></div>
      <!-- 文章分类统计图 -->
      <div id="categories-chart"></div>

      那么给它们添加pjax,就需要在pjax选择器中添加这几个id,找到[Blogroot]\themes\butterfly\layout\includes\third-party\pjax.pug中的pjaxSelectors。添加需要局部刷新的标签类。写法类似css选择器。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
          script.
      let pjaxSelectors = [
      'title',
      '#config_change',
      '#body-wrap',
      '#rightside-config-hide',
      '#rightside-config-show',
      + '#posts-chart',
      + '#tags-chart',
      + '#categories-chart',
      '.js-pjax'
      ]

pjaxpwagulp堪称BUG御三家,请在使用前做好心理准备。啊咧咧,温馨提示放最后会不会有点戏耍读者的意思。