前言
暑假在开发一个项目(就是此博客),由于项目需要支持 SEO,所以采用了 React 框架,同时为了提升用户体验,采用了 Pjax 技术。然而,在开发过程中,发现 React 与 Pjax 存在一些冲突,导致页面无法正常加载。经过一番研究,最终决定放弃 Pjax,采用传统的页面跳转方式。
不过,我也额外做了些工作,使现在的“直接跳转”在视觉上与 Pjax 相同。
只是,因为失去了 Pjax,所以目前为止最大的问题是音乐播放器...
React 与 Pjax 的冲突
我们可以看看 Pjax 的必要要求:
- 不直接通过 script 标签的方式在跳转后的页面引入新的 js 文件,即每个页面的 js 文件应该是相同的,因为因为 pjax 而更改的 script 标签不会运行
- 其实倒也不是绝对不行,我们还可以手动给会变化的 js 打个标签,页面重载后将其使用 document 操作放进页面中
- 服务器应该要返回 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不分的错误
后续
目前,音乐播放器还在开发中,暂时无法使用。