欢迎光临散文网 会员登陆 & 注册

WordPress主题 PJAX 无刷新以及渲染问题的修复

2023-04-02 00:04 作者:Ripple゜  | 我要投稿

近期为自己的wp主题配置了PJAX~此前使用的是Turbolinks插件,因为插件属于不可控元素,产生过多BUG后还是决定手动配置更为先进的PJAX(其实BUG更多了,但至少可以逐一排查…)

PJAX原理

PJAX(Pushstate + Ajax)是一种用于加快网页加载速度的技术。它结合了HTML5的pushState API和Ajax技术,使得在不刷新整个页面的情况下,可以实现局部页面内容的更新。PJAX的主要原理可以分为以下几个步骤:

  1. 用户点击链接:当用户点击一个链接时,PJAX会拦截该链接的点击事件。

  2. 阻止默认行为:PJAX会阻止浏览器执行默认的链接跳转行为,避免整个页面的刷新。

  3. 发送Ajax请求:接着,PJAX会通过Ajax发送一个请求到服务器,请求目标链接的内容。这个请求通常会包含一个特殊的请求头,以便服务器能够识别这是一个PJAX请求,从而仅返回局部更新所需的内容,而非整个页面的HTML代码。

  4. 更新URL和页面内容:当服务器返回局部内容后,PJAX会利用HTML5的pushState API来更新浏览器地址栏中的URL,然后用返回的内容替换页面中指定的容器元素。这样一来,用户就会感觉像是进行了一次正常的页面跳转,但实际上只是局部内容发生了更新。

  5. 更新浏览器历史记录:通过pushState API更新URL之后,浏览器的历史记录也会相应地更新。这样,用户在点击浏览器的前进和后退按钮时,可以按照预期的方式导航。

PJAX的优势在于减少了不必要的页面刷新,提高了用户体验。同时,由于只需要加载局部内容,它还有助于降低服务器负载。然而,PJAX也有一些局限性,例如对于不支持HTML5 pushState API的浏览器,PJAX可能无法正常工作。

引入PJAX

引入JS文件

前往主题的function.php,添加如下代码入队:

function add_pjax() {

  wp_register_script('pjax', 'https://cdn.bootcss.com/jquery.pjax/2.0.1/jquery.pjax.min.js', array('jquery'), '2.0.1', true);

  wp_enqueue_script('pjax');

}

add_action('wp_enqueue_scripts', 'add_pjax');

PHP

包裹PJAX容器

本段部分参考至https://alpha.skywt.cn/post/typecho-pjax-and-some-problems

F12检查自己博客的html结构,找到需要PJAX动态刷新的类,并将它包裹在PJAX容器中:

一般的网页结构:


<html>

  <head>

      <!-- ... -->

  </head>

  <body>

      <header><!-- 页眉,标题什么的 --></header>

      <nav><!-- 导航栏什么的 --></nav>

      <main id="pjax-container">

          <!-- 网站主体内容,文章列表 / 文章内容 / 评论什么的 -->

      </main>

      <script>

          // 下面要加上的代码

      </script>

      <footer><!-- 页脚什么的 --></footer>

  </body>

</html>

HTML

只需前往header.php以及footer.php中找到相应部分即可,在PJAX容器后方添加初始化代码(这里是Wordpress版本):


<script>

jQuery(document).ready(function($) {

  $(document).pjax('a[href^="<?php echo home_url(); ?>"]:not(a[target="_blank"])', {

      container: '#pjax-container',

      fragment: '#pjax-container'

  });


  $(document).on('pjax:send', function() {

      $('#pjax-container').fadeTo(700,0.0); //这里添加了一个淡入动画

      // alert('开始加载');

  // 开始加载时要运行的代码(如显示加载动画)

  });


  $(document).on('pjax:complete', function() {

      $('#pjax-container').fadeTo(700,1);

      // 完成加载时要运行的代码

  });

});

</script>

HTML

保存并清除缓存后,刷新后打开开发者工具,网络选项搜索PJAX,看见?_pjax=#pjax-container意味着PJAX配置成功。

加载指示器

引入PJAX时,用户点击超链后浏览器将不作回应,因此需要使用加载指示器显示页面正在加载中,HTML中加入


<div id="loading-spinner" class="loader" style="display:none;"></div>

HTML

对应CSS(这里使用CSS矢量动画作为加载指示)


@keyframes spin {

0% {

  transform: rotate(0deg);

}

100% {

  transform: rotate(360deg);

}

}


#loading-spinner {

position: fixed;

top: 20px;

right: 20px;

width: 24px;

height: 24px;

border: 2px solid #ccc;

border-top: 2px solid #3498db;

border-radius: 50%;

animation: spin 1s linear infinite;

z-index: 9999;

}

CSS

PJAX发送时,加载动画出现,完成时隐藏,这是我的完整JS


jQuery(document).ready(function ($) {

  $(document).pjax('a[href^="<?php echo home_url(); ?>"]:not(a[target="_blank"])', {

      container: '#pjax-container',

      fragment: '#pjax-container'

  });


  $(document).on('pjax:send', function () {

      // 显示加载指示器

      $('#loading-spinner').show();


      window.scrollTo({ top: 0, behavior: 'smooth' });

      $('#pjax-container').fadeTo(400, 0.0);

      $('#toc').empty();

  });


  $(document).on('pjax:complete', function () {

      // 隐藏加载指示器

      $('#loading-spinner').hide();


      // 初始化左侧小组件

      Toc.init({

          $nav: $('#toc')

      });

      $('body').scrollspy({

          target: '#toc'

      });

       

      trackPjaxPageView();

       

      $('#pjax-container').fadeTo(400, 1);

  });

});

JavaScript

遇到的一些问题

PJAX意味着随之而来的无数BUG…

Matomo追踪代码

如果启用了Matomo或其他的一些追踪代码(它们一般放在Header内),意味着用户通过PJAX进入的界面无法被记入统计数据,因此必须在PJAX完成后重新载入这段JS,首先定义一个新函数


function trackPjaxPageView() {

  if (typeof _paq !== 'undefined') {

      _paq.push(['setReferrerUrl', document.referrer]);

      _paq.push(['setDocumentTitle', document.title]);

      _paq.push(['setCustomUrl', window.location.href]);

      _paq.push(['trackPageView']);

  }

}

JavaScript

PJAX完成后调用它:


$(document).on('pjax:complete', function() {

trackPjaxPageView();

      $('#pjax-container').fadeTo(700,1);

  });


var _paq = window._paq = window._paq || [];

_paq.push(['trackPageView']);

_paq.push(['enableLinkTracking']);

(function() {

  var u="//analy.hiripple.com/";//这是我的matomo地址

  _paq.push(['setTrackerUrl', u+'matomo.php']);

  _paq.push(['setSiteId', '1']);

  var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];

  g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);

})();

JavaScript

左侧目录刷新

将PJAX容器包裹在正文,意味着左侧小工具栏所有元素都不会刷新(例如这个使用了bootstrap-toc.js的小目录)


$(document).on('pjax:complete', function() {

      // 初始化左侧小组件,查询官方的说明文档

      Toc.init({

          $nav: $('#toc'),

          $scope: $(document.body)

      });

      $('body').scrollspy({

          target: '#toc'

      });

      $('#pjax-container').fadeTo(700,1);

  });

JavaScript

即使重新初始化,也存在前一界面目录未清除的问题,在发送PJAX时清除目录:


$(document).on('pjax:send', function() {

      $('#pjax-container').fadeTo(700,0.0);

$('#toc').empty(); //清除目录

  });

JavaScript

Lazyload/lightbox

PJAX可能会导致Lazyload无法加载的情况:


function pjax_reload() {

var imgs = document.querySelectorAll("#main img.lazyload");

lazyload(imgs);

}

jQuery(document).ready(function($) {


  // 初始化fancybox

  jQuery('[data-fancybox="gallery"]').fancybox();


  // 初始化lazyload

  pjax_reload();


  $(document).pjax('a[href^="<?php echo home_url(); ?>"]:not(a[target="_blank"])', {

      container: '#pjax-container',

      fragment: '#pjax-container'

  });


  $(document).on('pjax:send', function() {

      $('#pjax-container').fadeTo(700,0.0);

  });


  $(document).on('pjax:complete', function() {

      jQuery('[data-fancybox="gallery"]').fancybox();


      // 重新初始化lazyload

      pjax_reload();


      $('#pjax-container').fadeTo(700,1);

  });

});

JavaScript

或者直接使用图片loading='lazy'属性,这是HTML5中的原生懒加载。原生懒加载不需要额外的处理,浏览器会自动处理懒加载。

点击事件

这里需要切换夜间模式


function initDarkModeToggle() {

const toggleBtnMoon = document.getElementById("moon-icon");

const toggleBtnSun = document.getElementById("sun-icon");


function applyDarkMode() {

  document.body.classList.add("dark-mode");

  localStorage.setItem("theme", "dark-mode");

  toggleBtnMoon.style.display = "none";

  toggleBtnSun.style.display = "block";

}


function removeDarkMode() {

  document.body.classList.remove("dark-mode");

  localStorage.setItem("theme", "light-mode");

  toggleBtnMoon.style.display = "block";

  toggleBtnSun.style.display = "none";

}


if (localStorage.getItem("theme") === "dark-mode") {

  applyDarkMode();

} else {

  removeDarkMode();

}


toggleBtnMoon.addEventListener("click", applyDarkMode);

toggleBtnSun.addEventListener("click", removeDarkMode);

}

$(document).on('pjax:complete', function() {

initDarkModeToggle();

});


最初发表于https://hiripple.com/archives/2982

WordPress主题 PJAX 无刷新以及渲染问题的修复的评论 (共 条)

分享到微博请遵守国家法律