如何在MVC中保持滚动位置?

时间:2009-01-27 17:53:24

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

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

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

12 个答案:

答案 0 :(得分:37)

我在JS中解决了这个问题:

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

然后在文件准备中:

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

答案 1 :(得分:8)

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应该避免回发。

答案 2 :(得分:6)

实际上没有标准的处理方法,这是微软支持他们的回发模式。他们需要这个,因为每个控件都会发回一个帖子,用户会不断被推回到页面顶部。

与MVC一起使用的建议是使用AJAX将大部分回发到服务器。这样页面就不必重新渲染焦点就不会移动。 jQuery使AJAX非常简单,甚至还有默认表单,如

<% Ajax.BeginForm(...) %>

将为您处理AJAX方面的问题。

答案 3 :(得分: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进行滚动。我相信所提供的代码是不言自明的,但我很乐意提供有关最新情况的详细说明,请告诉我。

答案 4 :(得分:3)

我自己的解决方法是使用ViewData中的一些信息来了解必须在backnavigation中显示哪些区域,并使用一些小的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来确定您必须重新定位的视图页面中的哪个元素。

希望它有所帮助。

答案 5 :(得分:2)

<%
   if(!ViewData.ModelState.IsValid)
   {
%>
   window.location.hash = 'Error';
<%
   }
%>

 <a name="Error"></a>

答案 6 :(得分:1)

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

我想要返回的页面有&lt; a&gt;具有名称属性的标签,例如&lt; a name =“testname”&gt;。

我从旧标签&lt; a href =“&lt;%:Request.UrlReferrer%&gt; #testname”&gt;返回&lt; / a&gt;“返回的页面(视图)。 Request.UrlReferrer用于转到上一页。 #testname将页面位置滚动到标记为“testname”的标记。

答案 7 :(得分:1)

这是一个简单,纯粹的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];
}

这符合我的需求,但可能更通用/可重复使用 - 我很乐意有人改进这个......: - )

答案 8 :(得分:0)

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

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

在新页面上,您只需加载保存的位置并使视图在0毫秒内滚动(使用Mootools或任何Ajax脚本,这应该是可能的),用户将完全放在原来的位置。

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

答案 9 :(得分:0)

我使用.scrollTop如下所示,非常简单,它甚至可以在视图中使用多个表单(我有一个非常长的视图,分为多种形式):

首先将此属性放在模型中:

               public string scrollTop { get; set; }

在视图中,在表单#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值。最后,您的页面会像webform一样,一切都保持不变。

答案 10 :(得分:0)

10年后,采用了另一种JS解决方案。另一个JS解决方案等待页面滚动,并在页面加载时滚动到保存的任何位置。对于大多数人来说,这很好(尽管它不会删除值,所以当您查看该页面时,页面将始终滚动到该位置...)。我的解决方案是等待表单提交:

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

$(document).ready(function() {
  var $form = $('#title_form');

  var root = $('#url_root').val();
  var php_file = 'assets/ajax/update.php';
  var url = root + php_file;

  $('#project_title').on('change', function() {
    $form.trigger('submit');
  });

  $form.on('submit', function(e) {
    e.preventDefault();

    $.ajax({
      type: "POST",
      url: url,
      data: $(this).serialize(),
      success: function(response) {
        var jsonData = JSON.parse(response);
        console.log(jsonData);
      }
    });
  });
});

这将滚动回到表单的顶部,这样,当您滚动到验证摘要之外时,所有错误消息都将可见。

答案 11 :(得分:-1)

&#13;
&#13;
@{

}

<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>
&#13;
&#13;
&#13;

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

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