RavelloH's Blog

LOADing...



我妥协了,React与Pjax不可兼得

i-cant-have-both-react-and-pjax

技术/重构 1955

nextjspjaxjavascript


前言

暑假在开发一个项目(就是此博客),由于项目需要支持 SEO,所以采用了 React 框架,同时为了提升用户体验,采用了 Pjax 技术。然而,在开发过程中,发现 React 与 Pjax 存在一些冲突,导致页面无法正常加载。经过一番研究,最终决定放弃 Pjax,采用传统的页面跳转方式。

不过,我也额外做了些工作,使现在的“直接跳转”在视觉上与 Pjax 相同。

只是,因为失去了 Pjax,所以目前为止最大的问题是音乐播放器...

React 与 Pjax 的冲突

我们可以看看 Pjax 的必要要求:

  1. 不直接通过 script 标签的方式在跳转后的页面引入新的 js 文件,即每个页面的 js 文件应该是相同的,因为因为 pjax 而更改的 script 标签不会运行
    • 其实倒也不是绝对不行,我们还可以手动给会变化的 js 打个标签,页面重载后将其使用 document 操作放进页面中
  2. 服务器应该要返回 Pjax 所需要的元素,也可以是渲染后的整个文档
    • 原生 React 在浏览器端渲染,这个是肯定不行了,虽然 React 本身也可以在服务器端渲染完然后传字符串过来,但是打完包

解决方案

解决方案很简单,在页面切换途中动手脚,使前一个页面的退出状态与后一个页面的载入状态相同,视觉上就感觉不到页面有切换

首先我们应该阻拦用户的跳转操作(a 标签):

document.addEventListener("click", function (event) {
  var target = event.target;
  if (target.tagName === "A") {
    event.preventDefault();
    var url = target.href;

    // 这里放你的淡出操作
    // fadeOutPage("#viewmap")
    setTimeout(() => (window.location.href = url), 450);
  }
});

这样我们就能硬控用户450ms,用来加载我们的淡出动画 如果你担心用户的网络请求也会慢450ms,那么可以用instant.page实现预加载

淡出动画可以非常简单,你只需要找到页面中变动的部分(我这里是div#viewmap),然后用以下方式给他透明化:

function fadeOutPage(selector, time = 450) {
    const element = document.querySelector(selector);
    element.style.opacity = '1';
    element.style.transition = `opacity ${time}ms,left ${time}ms`;
    element.style.opacity = '0';
}

这样就做好了淡出,接下来处理下一个页面的淡入 这里直接看最复杂的要求:页面在载入时有loading遮罩 在这种情况下,我们需要判断上一页面是否是本站点,如果是的话我们就直接关闭遮罩

function isReferrerFromMySite() {
    const referrer = document.referrer;
    const myDomain = window.location.origin;

    if (referrer) {
        var referrerUrl = new URL(referrer);
        return referrerUrl.origin === myDomain;
    } else {
        return false;
    }
}

上面的代码使用referrer检查上一页面,返回<Boolean>,然后我们就可以在页面载入时判断了:

if (isReferrerFromMySite()) {
    document.getElementById("loading").style.display = "none";
}

最好是就单独整个scirpt标签,放在遮罩元素的下面

为此我精简了上面的所有代码,并且检查了window是否存在,防止出现Nextjs中的Server与Client不分的错误

后续

目前,音乐播放器还在开发中,暂时无法使用。

INFO

00:00


无正在播放的音乐
00:00/00:00

账号
User avatar
未登录未设置描述...