wake-up-neo.com

Wie halte ich die Bildlaufposition in MVC aufrecht?

Ich arbeite an einem Projekt in MVC und habe es genossen, davon zu lernen. Es gibt ein paar wachsende Schmerzen, aber sobald Sie sie herausfinden, ist es nicht schlimm. In der WebForms-Welt ist es ganz einfach, die Bildlaufposition auf einer Seite beizubehalten. Sie setzen lediglich die Eigenschaft MaintainScrollPositionOnPostback auf true. In MVC verwende ich jedoch keine Postbacks, sodass dies bei mir nicht funktioniert. Wie wird das standardmäßig gehandhabt?

Edit: Ajax ist akzeptabel, aber ich habe mich auch gefragt, wie du es ohne AJAX machen würdest.

24
Papa Burgundy

Die Funktionsweise von MaintainScrollPositionOnPostback besteht darin, dass zwei ausgeblendete Felder vorhanden sind: __SCROLLPOSITIONX und __SCROLLPOSITIONY

Auf einem Postback setzt es diese,

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

und dann ruft es RestoreScrollPosition auf:

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

Aber wie die meisten Leute sagten, sollte MVC sowieso Postbacks vermeiden.

8
Richard Gadsden

Ich habe das in JS gelöst:

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

Dann im Dokument fertig:

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

Eigentlich gibt es keine Standardmethode, dies war ein Hack von Microsoft, um das Post-Back-Modell zu unterstützen. Sie brauchten dies, weil jedes Steuerelement einen Beitrag zurücksetzte und der Benutzer ständig an den oberen Rand der Seite zurückgeschoben wurde.

Die Empfehlung für die Verwendung mit MVC besteht darin, den größten Teil Ihres Beitrags mithilfe von AJAX an Server zurückzusenden. Damit die Seite nicht neu gerendert werden muss, wird der Fokus nicht verschoben. jQuery macht AJAX wirklich einfach, und es gibt sogar Standardformulare wie

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

Welche kümmert sich um die AJAX Seite der Dinge für Sie.

6
Nick Berardi

Ein anderer Ansatz mit Javascript und der Formularsammlung könnte etwa so aussehen, wenn man sich von WebForms und der Antwort von Richard Gadsden inspirieren lässt:

@{
    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);
});

Der bereitgestellte Code dient als Inspiration und ist in keiner Weise verschönert. Dies könnte wahrscheinlich auf verschiedene Arten geschehen. Ich denke, es hängt alles davon ab, wie Sie sich entscheiden, den scrollTop-Wert Ihres Dokuments über den POST hinweg beizubehalten. Es ist voll funktionsfähig und sollte browserübergreifend sicher sein, da wir jQuery zum Scrollen verwenden. Ich bin der Meinung, dass der bereitgestellte Code selbsterklärend ist, aber ich würde mich freuen, eine detailliertere Beschreibung der Vorgänge zu geben. Lassen Sie es mich einfach wissen.

4
Sniffdk

Meine eigene Problemumgehung besteht darin, mithilfe einiger Informationen in der ViewData zu wissen, welcher Bereich in der Rücknavigation angezeigt werden muss, und mit ein wenig Javascript den Cursor der Seite zu positionieren:

In der Ansicht ein Element wie das folgende:

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

Und das Javascript, um die Seite neu zu positionieren:

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

Sie können eine switch verwenden, um zu bestimmen, welches Element auf der Ansichtsseite Sie verschieben müssen.

Ich hoffe es hilft.

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

 <a name="Error"></a>
2
Mike Flynn

Hier ist eine einfache, reine Javascript-Lösung, die ich nur in FF4 und IE9 getestet habe.

Die Idee ist, dass diese Lösung sich verschlechtern sollte, indem auf die Standard-#anchor-Tags auf einer Seite zurückgegriffen wird. Ich ersetze diese #anchor-Tags im laufenden Betrieb durch die X- und Y-Koordinaten. Beim Laden lese ich diese Werte einfach aus dem Querystring und scrolle dorthin. Wenn dies aus irgendeinem Grund fehlschlägt, sollte der Browser immer noch zur Position #anchor navigieren ...

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

Ein paar Hilfsmethoden:

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

Das passt zu meinen Bedürfnissen, könnte aber allgemeiner/wiederverwendbarer sein - ich würde mich freuen, wenn jemand dies verbessern könnte ... :-)

1
user744322

Ich habe Namensattribute in Tags verwendet. Kein Javascript verwendet.

Die Seite, zu der ich zurückkehren wollte, hatte <a> Tags mit dem Attribut name, z. <a name="testname">.

Die Seite (Ansicht), die ich vom verwendeten Tag <a href="<%: Request.UrlReferrer %> #testname "> Back </a>" zurückgegeben habe. Mit Request.UrlReferrer wird zur vorherigen Seite gewechselt. #Testname scrollt die Seite Position, um mit dem Namen "Testname" zu taggen.

1
the1johan

ein sehr unangenehmer Weg, dies zu tun, ist die Verwendung von Cookies.

Wenn Sie EINE Seite in Ihrer MVC verwenden, die die anderen Seiten behandelt, können Sie einen Code-Snippet dazu erstellen, der jede Seite lädt, die ein Cookie namens "scrolltop" (falls nicht vorhanden) erstellt. Es gibt Möglichkeiten, JavaScript zu veranlassen, dieses Cookie automatisch zu aktualisieren, wenn der Benutzer einen Bildlauf nach oben oder unten ausführt, indem er diese Ereignisse abfängt oder den scrollTop-Wert überwacht.

Auf einer neuen Seite müssen Sie nur die gespeicherte Position laden und die Ansicht in 0 Millisekunden dorthin scrollen lassen (mit Mootools oder einem Ajax-Skript sollte dies möglich sein), und der Benutzer ist genau dort, wo er war.

Ich weiß nicht viel über asp, daher weiß ich nicht, ob es eine Methode gibt, um an einer aktuellen y-Position zu verankern. Javascript ist ein schneller und einfacher Weg. Anker in HTMl können eine Option sein, wenn Sie jedes Element verankert und den Anker auf anderen Seiten veröffentlicht haben.

0
xaddict

Ich benutze .scrollTop wie unten gezeigt, sehr einfach, es funktioniert sogar mit mehreren Formularen in der Ansicht (ich habe eine sehr lange Ansicht, die in mehrere Formulare unterteilt ist):

Fügen Sie diese Eigenschaft zuerst in das Modell ein:

               public string scrollTop { get; set; }

Und in der Ansicht in Formular 1:

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

in Formular 2:

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

in Formular 2:

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

und dann unten in der Ansicht:

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

Ihre Bildlaufposition bleibt beim Zurückschreiben immer erhalten, da in den @ Html.HiddenFor -Feldern Ihr aktueller Bildlauf gespeichert und beim Zurückschreiben an das Modell übergeben wird. Wenn die Seite aufgerufen wird, wird der scrollTop-Wert vom Modell abgerufen. Am Ende würde sich Ihre Seite wie ein Webformular verhalten, alles bleibt intakt.

0
Yogi