【问题标题】:How do I maintain scroll position in MVC?如何在 MVC 中保持滚动位置?
【发布时间】:2010-10-03 19:46:09
【问题描述】:

我正在从事 MVC 中的一个项目,并且很喜欢学习它。有一些成长的痛苦,但一旦你弄清楚它们就不错了。在 WebForms 世界中真正简单的一件事是保持页面上的滚动位置。您只需将 MaintainScrollPositionOnPostback 属性设置为 true。但是,在 MVC 中,我不使用回发,所以这对我不起作用。处理此问题的标准方法是什么?

编辑: Ajax 是可以接受的,但我也想知道如果没有 AJAX 怎么办。

【问题讨论】:

  • 如果您使用 AJAX 和 jQuery,请选择页面顶部的可见元素。说它是一个没有文本的锚 然后在你的 $(document).ready 中写 $('#pageTop').focus();

标签: html asp.net-mvc model-view-controller scroll-position


【解决方案1】:

我已经在 J​​S 中解决了这个问题:

$(document).scroll(function(){
    localStorage['page'] = document.URL;
    localStorage['scrollTop'] = $(document).scrollTop();
});

然后在文档中准备好:

$(document).ready(function(){
    if (localStorage['page'] == document.URL) {
        $(document).scrollTop(localStorage['scrollTop']);
    }
});

【讨论】:

  • 非常好。在使用像asp.net mvc这样的路由引擎时,本地存储中的页面可能不匹配,但是如果您为本地存储滚动值使用唯一名称,则确实不需要... $(document).scroll(function () { localStorage['myuniquename'] = $(document).scrollTop(); }); $(document).ready(function () { $(document).scrollTop(localStorage['myuniquename']); });
  • 我曾经在我的 asp.net 应用程序中使用它,但现在我使用 MVC4 它只是不想再工作了。它向下滚动的momand和数量似乎如此随机。我不知道是怎么回事。我放了断点,看到它在做“scrollTop(166)”,但浏览器只是忽略它,其他时候它工作正常,有时它只滚动了它应该滚动的一点点。
  • 我刚刚尝试了一个 Internet Application MVC4 项目。有用。可能存在脚本冲突或取决于您的浏览器。我在@Scripts.Render("~/bundles/jquery") 之后添加了 sn-p
  • 又好又简单!感谢您的回答
  • 这是一个非常优雅的解决方案!恭喜您的回答,谢谢。
【解决方案2】:

MaintainScrollPositionOnPostback 的工作方式是它有一对隐藏字段: __SCROLLPOSITIONX 和 __SCROLLPOSITIONY

在回发时,它会设置这些,

function WebForm_GetScrollY() {
if (__nonMSDOMBrowser) {
    return window.pageYOffset;
}
else {
    if (document.documentElement && document.documentElement.scrollTop) {
        return document.documentElement.scrollTop;
    }
    else if (document.body) {
        return document.body.scrollTop;
    }
}
return 0;
}
function WebForm_SaveScrollPositionSubmit() {
    if (__nonMSDOMBrowser) {
        theForm.elements['__SCROLLPOSITIONY'].value = window.pageYOffset;
        theForm.elements['__SCROLLPOSITIONX'].value = window.pageXOffset;
    }
    else {
        theForm.__SCROLLPOSITIONX.value = WebForm_GetScrollX();
        theForm.__SCROLLPOSITIONY.value = WebForm_GetScrollY();
    }
    if ((typeof(this.oldSubmit) != "undefined") && (this.oldSubmit != null)) {
        return this.oldSubmit();
    }
    return true;
    }

然后调用RestoreScrollPosition:

function WebForm_RestoreScrollPosition() {
    if (__nonMSDOMBrowser) {
        window.scrollTo(theForm.elements['__SCROLLPOSITIONX'].value, theForm.elements['__SCROLLPOSITIONY'].value);
    }
    else {
        window.scrollTo(theForm.__SCROLLPOSITIONX.value, theForm.__SCROLLPOSITIONY.value);
    }
    if ((typeof(theForm.oldOnLoad) != "undefined") && (theForm.oldOnLoad != null)) {
        return theForm.oldOnLoad();
    }
    return true;
}

但正如大多数人所说,无论如何,MVC 都应该避免回发。

【讨论】:

  • 哼!无法弄清楚如何编辑它以很好地放入代码示例 - 有人想告诉我我有多愚蠢吗?
【解决方案3】:

实际上没有标准的方法来处理这个问题,这是微软为了支持他们的回发模型而进行的黑客攻击。他们需要这个,因为每个控件都会发回一个帖子,并且用户会不断地被推回页面顶部。

与 MVC 一起使用的建议是使用 AJAX 将您的大部分帖子发回服务器。这样页面就不必重新渲染焦点不会移动。 jQuery 让 AJAX 变得非常简单,甚至还有像

这样的默认表单
<% Ajax.BeginForm(...) %>

这将为您处理 AJAX 方面的事情。

【讨论】:

    【解决方案4】:

    从 WebForms 和 Richard Gadsden 提供的答案中汲取灵感,使用 javascript 和表单集合的另一种方法可能如下所示:

    @{
        var scrollPositionX = string.Empty;        
        if(IsPost) {
            scrollPositionX = Request.Form["ScrollPositionX"];
        }
    }
    
    <form action="" method="post">
        <input type="hidden" id="ScrollPositionX" name="ScrollPositionX" value="@scrollPositionX" />
        <input type="submit" id="Submit" name="Submit" value="Go" />
    </form>
    
    $("#Submit").click(function () {
        $("#ScrollPositionX").val($(document).scrollTop());
    });
    
    $("#ScrollPositionX").each(function () {
        var val = parseInt($(this).val(), 10);
        if (!isNaN(val))
            $(document).scrollTop(val);
    });
    

    提供的代码仅供参考,绝非美化。它可能可以通过几种不同的方式完成,我想这一切都取决于您决定如何在 POST 中保留文档的 scrollTop 值。由于我们使用 jQuery 进行滚动,因此它可以正常工作并且应该是跨浏览器安全的。我相信所提供的代码是不言自明的,但我很乐意提供更详细的说明,让我知道。

    【讨论】:

    • 我特别感谢您。我将最后 3 行放入我的 $(document).ready() 部分,一切都很好。
    【解决方案5】:

    我自己的解决方法是使用ViewData 中的一些信息来了解必须在后退导航中显示哪些区域,并使用一些 javascript 来定位页面的光标:

    在视图中,一个像这样的元素:

    <h3 id="tasks">
        Contained tasks
    </h3>
    

    以及重新定位页面的 javascript:

    <script type="text/javascript">
        addOnLoad(goAnchor);
    
        function goAnchor() {
            var paging = <%= //Here you determine (from the ViewData or whatever) if you have to position the element %>;
            if (paging == "True") {
                window.location.hash = "tasks";
            }
    </script>
    

    您可以使用switch 来确定您必须重新定位视图页面中的哪个元素。

    希望对你有帮助。

    【讨论】:

    • 这不会像 Web 表单那样保留确切的位置。
    【解决方案6】:

    我在标签中使用了名称属性。没有使用 javascript。

    我想要返回的页面有 带有 name 属性的标签,例如

    我从使用标签返回的页面(视图)Back"。 Request.UrlReferrer 用于转到上一页。 #testname 滚动页面位置以标记名称为“testname”。

    【讨论】:

      【解决方案7】:
      <%
         if(!ViewData.ModelState.IsValid)
         {
      %>
         window.location.hash = 'Error';
      <%
         }
      %>
      
       <a name="Error"></a>
      

      【讨论】:

        【解决方案8】:

        这是一个简单的纯 Javascript 解决方案,我仅在 FF4 和 IE9 中测试过。

        这个想法是这个解决方案应该通过回退到页面上的标准#anchor标签来优雅地降级。我正在做的是用 X 和 Y 坐标即时替换那些#anchor 标签,然后在加载时,我只需从查询字符串中读取这些值并滚动到那里。如果由于某种原因失败,浏览器仍应导航到#anchor 位置...

        标记:

        <a href="/somecontroller/someaction/#someanchor">My Link</a>
        

        jQuery:

        $(function() {
        
        // RESTORE SCROLL POSITION
        RestoreScrollPosition();
        
        // SAVE SCROLL POSITION
        $('a:not(a[href^="http"])').filter('[href$="#someanchor"]').each(function() {
            $(this).click(function() {
                var href = $(this).attr('href').replace("#someanchor","");
                if (href.indexOf('?') == -1) {
                    href = href + '?x='
                } else {
                    href = href + '&x='
                }
                href = href + window.pageXOffset;
                href = href + '&y=' + window.pageYOffset;
                $(this).attr('href', href);
            });
        });
        }
        

        几个辅助方法:

        function RestoreScrollPosition() {
        
            var scrollX = gup('x');
            var scrollY = gup('y');
        
            if (scrollX != null && scrollY != null) {
                window.scrollTo(scrollX, scrollY);
                return true;
            }
            return false;
        }
        
        function gup(name) {
            name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
            var regexS = "[\\?&]" + name + "=([^&#]*)";
            var regex = new RegExp(regexS);
            var results = regex.exec(window.location.href);
            if (results == null)
                return "";
            else
                return results[1];
        }
        

        这符合我的需求,但可能更通用/可重复使用 - 我很高兴有人对此进行改进... :-)

        【讨论】:

          【解决方案9】:

          使用 cookie 是一种非常不好的方法。

          如果你在你的 MVC 中使用一个页面来处理其他页面,你可以使用 code-sn-p 来加载每个页面,该页面会创建一个名为“scrolltop”的 cookie(如果不存在)。 当用户向上或向下滚动时,通过捕获这些事件或查看 scrollTop 值,有一些方法可以让 javascript 自动更新此 cookie。

          在一个新页面上,您只需加载保存的位置并让视图在 0 毫秒内滚动到那里(使用 Mootools 或任何 Ajax 脚本应该是可能的),用户将准确地回到他们所在的位置。

          我对 asp 了解不多,所以我不知道是否存在锚定到当前 y 位置的方法。 Javascript 是一种快速简便的方法。如果您将每个元素都锚定并将锚点发布到其他页面,则 HTMl 中的锚点可能是一种选择。

          【讨论】:

            【解决方案10】:

            我使用 .scrollTop 如下所示,非常简单,它甚至可以在视图中处理多个表单(我的视图很长,分解为多个表单):

            先把这个属性放到模型里面:

                           public string scrollTop { get; set; }
            

            在视图中,Form #1 内部:

                           @Html.HiddenFor(m => m.scrollTop, new {@id="ScrollForm1"})
            

            在表格 #2 内:

                           @Html.HiddenFor(m => m.scrollTop, new {@id="ScrollForm2"})
            

            在表格 #2 内:

                           @Html.HiddenFor(m => m.scrollTop, new {@id="ScrollForm3"})
            

            然后在视图的底部:

             $(document).ready(function () {
                $(document).scrollTop(@Model.scrollTop);
                $(document).scroll(function () {
                    $("#ScrollForm1").val($(document).scrollTop());
                    $("#ScrollForm2").val($(document).scrollTop());
                    $("#ScrollForm3").val($(document).scrollTop());
                  });
               });
            

            您的滚动位置始终在回发时保留,因为 @Html.HiddenFor 字段存储您当前的滚动并将其传递给发布时的模型。然后,当页面出现时,它会从模型中获取 scrollTop 值。最后,您的页面将表现得像网络表单一样,一切都保持不变。

            【讨论】:

              【解决方案11】:

              10 年过去了,一个不同的 JS 解决方案。另一个 JS 解决方案等待页面滚动,当页面加载时滚动到保存的任何位置。这对大多数人来说都很好(尽管它不会删除该值,因此当您查看该页面时页面总是会滚动到该位置......)。我的解决方案是等待表单提交:

              (是的,它使用的是 jQuery,但该网站有很多...)

                  // OWNER'S FORM POSITION
                  if ($("[js-owner-request]").length) {
                      $("[js-owner-request]").on("submit", function() {
                          localStorage['owner-request__scrollTop'] = $(this).offset().top;
                      });
              
                      if (localStorage['owner-request__scrollTop'] !== "null") {
                          $(document).scrollTop(localStorage['owner-request__scrollTop']);
                          localStorage['owner-request__scrollTop'] = "null"; // set to null so we don't always scroll...
                      }
                  }
              

              这会滚动回表单的顶部,这样任何错误消息都将可见,因为您可能已经滚动到验证摘要之外。

              【讨论】:

                【解决方案12】:

                @{
                
                }
                
                <html>
                
                <head>
                    <script type="text/javascript">
                
                window.onload = function () {
                    var div = document.getElementById("dvScroll");
                   var div_position = document.getElementById("div_position");
                    var position = parseInt(@Request.Form("div_position"));
                    if (isNaN(position)) {
                        position = 0;
                    }
                
                    div.scrollTop = position;
                    div.onscroll = function () {
                        div_position.value = div.scrollTop;
                    };
                };
                
                </script>
                </head>
                
                <body>
                
                <div id="dvScroll" style="overflow-y: scroll; height: 260px; width: 300px">
                
                    1. This is a sample text
                
                    <br />
                
                    2. This is a sample text
                
                    <br />
                
                    3. This is a sample text
                
                    <br />
                
                    4. This is a sample text
                
                    <br />
                
                    5. This is a sample text
                
                    <br />
                
                    6. This is a sample text
                
                    <br />
                
                    7. This is a sample text
                
                    <br />
                
                    8. This is a sample text
                
                    <br />
                
                    9. This is a sample text
                
                    <br />
                
                    10. This is a sample text
                
                    <br />
                
                    11. This is a sample text
                
                    <br />
                
                    12. This is a sample text
                
                    <br />
                
                    13. This is a sample text
                
                    <br />
                
                    14. This is a sample text
                
                    <br />
                
                    15. This is a sample text
                
                    <br />
                
                    16. This is a sample text
                
                    <br />
                
                    17. This is a sample text
                
                    <br />
                
                    18. This is a sample text
                
                    <br />
                
                    19. This is a sample text
                
                    <br />
                
                    20. This is a sample text
                
                    <br />
                
                    21. This is a sample text
                
                    <br />
                
                    22. This is a sample text
                
                    <br />
                
                    23. This is a sample text
                
                    <br />
                
                    24. This is a sample text
                
                    <br />
                
                    25. This is a sample text
                
                    <br />
                
                </div>
                
                <hr />
                <form method="post">
                <input type="hidden" id="div_position" name="div_position" />
                <input type="submit" value="Cool" />
                    </form> 
                </body>
                </html>

                您可以使用它在回发后保持滚动位置。

                来源:http://www.aspsnippets.com/Articles/Maintain-Scroll-Position-of-DIV-on-PostBack-in-ASPNet.aspx

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2011-11-28
                  • 2020-04-05
                  • 1970-01-01
                  • 2013-09-30
                  • 1970-01-01
                  • 2013-04-16
                  • 1970-01-01
                  • 2011-03-22
                  相关资源
                  最近更新 更多