Как мне сохранить позицию прокрутки в MVC? - PullRequest
25 голосов
/ 27 января 2009

Я работаю над проектом в MVC и с удовольствием узнал об этом. Есть несколько растущих болей, но как только вы их выясните, это не плохо. Одна вещь, которая действительно проста в мире WebForms - это сохранение позиции прокрутки на странице. Все, что вам нужно сделать, это установить для свойства MaintainScrollPositionOnPostback значение true. Тем не менее, в MVC я не использую обратные передачи, так что это не будет работать для меня. Какой стандартный способ справиться с этим?

Редактировать: Ajax приемлем, но мне также было интересно, как бы вы сделали это без AJAX.

Ответы [ 11 ]

37 голосов
/ 25 апреля 2013

Я решил это в JS:

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

Тогда в документе готово:

$(document).ready(function(){
    if (localStorage['page'] == document.URL) {
        $(document).scrollTop(localStorage['scrollTop']);
    }
});
8 голосов
/ 04 февраля 2009

Способ 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 все равно следует избегать обратных передач.

6 голосов
/ 27 января 2009

На самом деле не существует стандартного способа справиться с этим, это был взлом Microsoft для поддержки их модели постбэк. Они нуждались в этом, потому что каждый элемент управления отправлял сообщение назад, а пользователь постоянно возвращался наверх страницы.

Рекомендация для использования с MVC состоит в том, чтобы отправлять большую часть ваших сообщений обратно на серверы, использующие AJAX. Чтобы страница не перерисовывалась, фокус не перемещается. JQuery делает AJAX действительно простым, и даже есть формы по умолчанию, такие как

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

Что позаботится о стороне AJAX для вас.

4 голосов
/ 13 июля 2011

Вдохновленный веб-формами и ответом Ричарда Гадсдена, другой подход, использующий 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);
});

Код предоставлен для вдохновения и ни в коем случае не является предварительным подтверждением. Вероятно, это можно сделать несколькими различными способами, я полагаю, все сводится к тому, как вы решили сохранить значение scrollTop вашего документа в POST. Он полностью работает и должен быть безопасным для всех браузеров, так как мы используем jQuery для прокрутки. Я считаю, что приведенный код не требует пояснений, но я буду рад предоставить более подробное описание того, что происходит, просто дайте мне знать.

3 голосов
/ 27 января 2009

Мой собственный обходной путь использует некоторую информацию в 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, чтобы определить, какой элемент со страницы просмотра необходимо переместить.

Надеюсь, это поможет.

2 голосов
/ 15 июня 2010
<%
   if(!ViewData.ModelState.IsValid)
   {
%>
   window.location.hash = 'Error';
<%
   }
%>

 <a name="Error"></a>
1 голос
/ 09 мая 2011

Вот простое, чистое решение Javascript, которое я тестировал только в FF4 и IE9.

Идея состоит в том, что это решение должно изящно ухудшаться, возвращаясь к стандартным тегам #anchor на странице. Я заменяю эти теги #anchor на лету координатами X и Y, а затем при загрузке просто считываю эти значения из строки запроса и прокручиваю там. Если по какой-то причине это не удается, браузер все равно должен перейти в положение #anchor ...

Markup:

<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];
}

Это соответствует моим потребностям, но может быть более общим / многократно используемым - я был бы рад, если бы кто-то улучшил это ...: -)

1 голос
/ 18 января 2011

Я использовал атрибуты имени в тегах. JavaScript не используется.

Страница, на которую я хотел вернуться, содержала теги с атрибутом name, например .

Страница (просмотр), которую я возвратил из использованного тега #testname"> Назад". Request.UrlReferrer используется для перехода на предыдущую страницу. #testname прокручивает позицию страницы до тега с именем «testname».

0 голосов
/ 30 июня 2016

@{

}

<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

0 голосов
/ 01 января 2014

Я использую .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 из модели. В конце ваша страница будет вести себя как веб-форма, все останется нетронутым.

...