书到用时方恨少,技术到应用时才觉得自己有多菜鸟。为了使自己的网站速度快一点,刷新更加流畅一点,我也在自己网站上使用了一下 pjax,但因为一知半解,在刷新 splide 横幅时遇到了各种问题。表现如下:
一是从其他页面再点击链接回到横幅所在页面时,横幅不显示。
二是从横幅页面切换到其他页面后,然后(不刷新)点击浏览器的“转到上一页”按扭时,横幅下方的导航按钮虽然正常,但是点击没有反应。
三是从横幅页面切换到其他页面后,然后(不刷新)点击浏览器的“转到上一页”按扭时,横幅下方的导航按钮重复。
我最初的写法是:
<!-- splide 引入-->
<script src="<?php $this->options->themeUrl('splide/js/splide.min.js'); ?>"></script>
<link href="<?php $this->options->themeUrl('splide/css/themes/splide-default.min.css'); ?>" rel="stylesheet">
<link href="<?php $this->options->themeUrl('splide/css/splide.min.css'); ?>" rel="stylesheet">
<!--- 刷新选择器部分 --->
<main>
...
<!--- splide 实例的html部分 --->
<section class="splide" aria-labelledby="">
<div class="splide__track">
<ul class="splide__list">
<li class="splide__slide">Slide 01</li>
<li class="splide__slide">Slide 02</li>
<li class="splide__slide">Slide 03</li>
</ul>
</div>
</section>
...
</main>
<!--- pjax --->
<script>
$(document).pjax(
'a[href^="<?php Helper::options()->siteUrl() ?>"]:not(a[target="_blank"],a[no-pjax]), a[href^="?"]', {
container: 'main',
fragment: 'main',
timeout: 8000
}
).on('pjax:send', function() {
NProgress.start(); //加载动画效果开始
}).on('pjax:complete', function() {
NProgress.done(); //加载动画效果结束
//其他调用
...
});
</script>
<!--- 创建横幅实例 --->
<script>
new Splide('.splide').mount();
</script>
首先,我解决了问题一
发生问题一的原因是,pjax刷新处理后,没有重新初始化splide实例。于是,我在 pjax:complete 阶段再次写入了初始化splide实例方法。pjax 代码变成如下:
$(document).pjax(
'a[href^="<?php Helper::options()->siteUrl() ?>"]:not(a[target="_blank"],a[no-pjax]), a[href^="?"]', {
container: 'main',
fragment: 'main',
timeout: 8000
}
).on('pjax:send', function() {
NProgress.start(); //加载动画效果开始
}).on('pjax:complete', function() {
NProgress.done(); //加载动画效果结束
//其他调用
...
new Splide('.splide').mount();
});
可是这样,却导致了问题二的发生:从横幅页面切换到其他页面后,然后(不刷新)点击浏览器的“转到上一页”按扭时,横幅下方的导航按钮点击没有反应。
然后,我解决了问题二
发生问题二的原因是,浏览器前进后退时不会进行 pjax 请求,但会进行会按顺序执行如下事件:pjax:popstate、pjax:start、pjax:beforeReplace、pjax:end。于是,我将初始化splide实例方法写入到了 pjax:end 阶段,pjax 代码变成如下:
$(document).pjax(
'a[href^="<?php Helper::options()->siteUrl() ?>"]:not(a[target="_blank"],a[no-pjax]), a[href^="?"]', {
container: 'main',
fragment: 'main',
timeout: 8000
}
).on('pjax:send', function() {
NProgress.start(); //加载动画效果开始
}).on('pjax:complete', function() {
NProgress.done(); //加载动画效果结束
//其他调用
...
}).on('pjax:end', function() {
new Splide('.splide').mount();
});
再测试浏览器后退,发现导航按钮重复了.只不过前面的导航按钮点击还是无效,而后面的导航按钮点击是有效的。
终于,我解决了问题三
经百度搜索“pjax 刷新 splide 时导航按钮重复”,终于发生问题三的原因是:pjax 的内容更新过程中,splide 实例没有正确地被销毁而被重新初始化了。解决这个问题的一个策略是,在每次 PJAX 内容更新后,先销毁现有的 splide 实例,然后再重新初始化。
依样画葫芦,我写入了初始化和销毁 splide 实例函数,并在 pjax:beforeSend 阶段加入了销毁splide实例方法,最终的代码如下:
<!-- splide 引入-->
<script src="<?php $this->options->themeUrl('splide/js/splide.min.js'); ?>"></script>
<link href="<?php $this->options->themeUrl('splide/css/themes/splide-default.min.css'); ?>" rel="stylesheet">
<link href="<?php $this->options->themeUrl('splide/css/splide.min.css'); ?>" rel="stylesheet">
<!--- 刷新选择器部分 --->
<main>
...
<!--- splide 实例的html部分 --->
<section class="splide" aria-labelledby="">
<div class="splide__track">
<ul class="splide__list">
<li class="splide__slide">Slide 01</li>
<li class="splide__slide">Slide 02</li>
<li class="splide__slide">Slide 03</li>
</ul>
</div>
</section>
...
</main>
<!--- pjax --->
<script>
$(document).pjax(
'a[href^="<?php Helper::options()->siteUrl() ?>"]:not(a[target="_blank"],a[no-pjax]), a[href^="?"]', {
container: 'main',
fragment: 'main',
timeout: 8000
}
).on('pjax:beforeSend', function() {
destroySplide(); //销毁实例
}).on('pjax:send', function() {
NProgress.start(); //加载动画效果开始
}).on('pjax:complete', function() {
NProgress.done(); //加载动画效果结束
//其他调用
...
}).on('pjax:end', function() {
initSplide(); //初始化实例
});
</script>
<!--- 初始化和销毁横幅实例 --->
<script>
let splide;
function initSplide() {
if (!splide) {
splide = new Splide('.splide').mount();
}
}
function destroySplide() {
if (splide) {
splide.destroy();
splide = null;
}
}
// 页面加载时初始化
window.onload = initSplide;
// 页面卸载前销毁
window.onunload = destroySplide;
</script>