Skip to content

在启用PJAX的情况下,后退时页面滚动位置异常 #1343

@LunaSpica

Description

@LunaSpica

问题描述:
在启用PJAX的情况下,后退时页面滚动位置异常。

问题出处:
iro主题设置--全局设置--额外设置--功能--PJAX局部刷新

实际行为描述:
启用"PJAX 局部刷新"后,在博客首页打开任意文章,然后点击浏览器的后退按钮(鼠标后退按钮)回到首页,首页的页面位置与打开文章前对比,首页自动向下滚动了.

预期的行为:
启用"PJAX 局部刷新"后,在博客首页打开任意文章,然后点击浏览器的后退按钮,返回上级页面时,上级页面应保持原来的滚动位置

复现步骤:
打开pjax后稳定触发

配置与环境:

  • 问题站点链接:
  • https://kiseki.blog/
  • https://www.suiyue.site/
  • PHP 版本:8.3.24
  • 数据库类型 / 版本:mysqlnd 8.3.24
  • WordPress 版本:6.8.3
  • 主题版本:3.0.4
  • 使用的插件:
  • WP Statistics
  • WordPress 导入工具
  • 浏览器:Google Chrome 版本 142.0.7444.163(正式版本) (64 位)

截图
打开文章前:
Image

打开文章后:

Image

执行后退操作后:

Image

补充信息:
可以注意到,首页向下滚动了.

解决方案(借助AI)
在主题的functions.php文件末尾,iro_action_operator();调用之前添加以下代码:

代码说明:
该解决方案通过监听PJAX事件,在页面跳转前保存当前滚动位置,在返回时恢复位置,确保用户体验的一致性。

add_action('wp_footer', function() {
    ?>
    <script>
    (function() {
        console.log('=== 改进的PJAX滚动修复 ===');
        
        var savedScrollPositions = {};
        var lastValidScrollY = 0;
        var isProcessing = false;
        
        // 记录最后一次有效滚动位置
        var scrollTimer = null;
        window.addEventListener('scroll', function() {
            clearTimeout(scrollTimer);
            scrollTimer = setTimeout(function() {
                if (window.scrollY > 10) { // 只记录有意义的滚动位置
                    lastValidScrollY = window.scrollY;
                    console.log('记录有效滚动位置:', lastValidScrollY);
                }
            }, 100);
        });
        
        // 改进的PJAX事件处理
        document.addEventListener('pjax:send', function() {
            if (isProcessing) return;
            
            isProcessing = true;
            
            // 使用最后一次有效滚动位置,而不是当前可能已被重置的位置
            var currentUrl = window.location.href;
            var scrollToSave = lastValidScrollY > 0 ? lastValidScrollY : window.scrollY;
            
            savedScrollPositions[currentUrl] = {
                x: window.scrollX,
                y: scrollToSave,
                time: Date.now(),
                valid: scrollToSave > 10 // 标记是否有效
            };
            
            console.log('PJAX发送 - 保存位置:', scrollToSave, '有效:', scrollToSave > 10);
            
            setTimeout(function() {
                isProcessing = false;
            }, 50);
        });
        
        // 处理完成事件
        document.addEventListener('pjax:complete', function() {
            setTimeout(function() {
                var currentUrl = window.location.href;
                var savedPos = savedScrollPositions[currentUrl];
                
                if (savedPos && savedPos.valid && savedPos.y > 10) {
                    console.log('PJAX完成 - 尝试恢复位置:', savedPos.y);
                    
                    // 分步滚动,确保生效
                    var attempts = 0;
                    var scrollInterval = setInterval(function() {
                        attempts++;
                        window.scrollTo(savedPos.x, savedPos.y);
                        
                        if (Math.abs(window.scrollY - savedPos.y) < 10 || attempts >= 5) {
                            clearInterval(scrollInterval);
                            console.log('滚动完成 - 最终位置:', window.scrollY, '目标位置:', savedPos.y);
                        }
                    }, 50);
                }
            }, 100);
        });
        
        // 改进的popstate处理
        window.addEventListener('popstate', function(event) {
            setTimeout(function() {
                var currentUrl = window.location.href;
                var savedPos = savedScrollPositions[currentUrl];
                
                if (savedPos && savedPos.valid && savedPos.y > 10) {
                    console.log('POPSTATE - 恢复位置:', savedPos.y);
                    
                    var attempts = 0;
                    var scrollInterval = setInterval(function() {
                        attempts++;
                        window.scrollTo(savedPos.x, savedPos.y);
                        
                        if (Math.abs(window.scrollY - savedPos.y) < 10 || attempts >= 5) {
                            clearInterval(scrollInterval);
                            console.log('Popstate滚动完成');
                        }
                    }, 50);
                }
            }, 150);
        });
        
        // 确保浏览器使用自动滚动恢复
        if (window.history && window.history.scrollRestoration) {
            window.history.scrollRestoration = 'auto';
            console.log('设置历史记录滚动恢复: auto');
        }
        
        console.log('=== 改进方案加载完成 ===');
    })();
    </script>
    <?php
});

iro_action_operator();```

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions