Подтвердить что ты не робот

Как сохранить положение прокрутки в MVC?

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

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

4b9b3361

Ответ 1

Как работает MaintainScrollPositionOnPostback, он имеет пару скрытых полей: __СШИРЕНИЕ ПОСЛЕДОВАТЕЛЬНОСТИ и __Противопоказания

В обратном порядке он устанавливает эти значения,

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

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

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

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

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

Ответ 3

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

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

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

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

Ответ 4

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

Ответ 5

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

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

Ответ 6

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

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

Ответ 7

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

На страницу, на которую я хотел вернуться, была <a> теги с атрибутом имени, например. < a name= "testname" > .

Страница (просмотр) Я вернулась из использованного тега < a href= "<%: Request.UrlReferrer% > #testname" > Назад </a> ". Request.UrlReferrer используется для перехода на предыдущую страницу. #testname прокручивает позицию страницы для тега с именем "testname".

Ответ 8

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

Идея состоит в том, что это решение должно грамотно деградировать, возвращаясь к стандартным тегам #anchor на странице. То, что я делаю, заменяет теги #anchor "на лету" с координатами X и Y, затем при загрузке я просто читаю эти значения из строки запроса и прокручиваю туда. Если по какой-то причине это не удается, браузер должен перейти в положение #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.

Если вы используете страницу ONE в своем MVC, которая обрабатывает другие страницы, вы можете использовать фрагмент кода, который загружает каждую страницу, которая создает куки файл (если он не существует) называется "scrolltop". Есть способы, чтобы javascript автоматически обновлял этот файл cookie, когда пользователь прокручивается вверх или вниз, захватывая эти события или просматривая значение scrollTop.

На новой странице вам просто нужно загрузить сохраненную позицию и сделать вид прокрутки там в 0 миллисекунд (с Mootools или любым Ajax script это должно быть возможно), и пользователь будет именно там, где они были.

Я не знаю много о asp, поэтому я не знаю, существует ли метод для привязки к текущей y-позиции. Javascript - это быстрый и простой способ. Якорями в HTMl может быть вариант, если бы у вас был закреплен каждый элемент и помещен якорь на другие страницы.

Ответ 10

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

Ответ 11

@{

}

<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>