html asp.net-mvc model-view-controller scroll-position

html - ¿Cómo mantengo la posición de desplazamiento en MVC?



asp.net-mvc model-view-controller (11)

Estoy trabajando en un proyecto en MVC y he disfrutado aprendiendo sobre él. Hay algunos dolores de crecimiento pero una vez que los descubres no está mal. Una cosa que es realmente simple en el mundo de WebForms es mantener la posición de desplazamiento en una página. Todo lo que hace es establecer la propiedad MaintainScrollPositionOnPostback en verdadero. Sin embargo, en MVC, no estoy usando devoluciones, así que esto no funcionará para mí. ¿Cuál es la forma estándar de manejar esto?

Editar: Ajax es aceptable, pero también me preguntaba cómo lo harías sin AJAX.


Aquí hay una solución simple y pura de Javascript que he probado solo en FF4 e IE9.

La idea es que esta solución se degrade #anchor cayendo de nuevo a las etiquetas estándar #anchor en una página. Lo que estoy haciendo es reemplazar esas etiquetas #anchor sobre la marcha con las coordenadas X e Y, y luego en carga, simplemente leo esos valores de la cadena de consulta y me desplazo hacia allí. Si esto falla por alguna razón, el navegador debe navegar a la posición #anchor ...

Margen:

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

Un par de métodos de ayuda:

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

Esto se ajusta a mis necesidades, pero podría ser más genérico / reutilizable. Me gustaría que alguien mejore en esto ... :-)


En realidad, no hay una forma estándar de manejar esto, este fue un truco de Microsoft para soportar su modelo posterior a la publicación. Lo necesitaban porque cada control devolvía una publicación y el usuario se veía constantemente empujado hacia la parte superior de la página.

La recomendación para usar con MVC es hacer la mayor parte de su publicación a los servidores que usan AJAX. Para que la página no tenga que volverse a enviar, el foco no se mueve. jQuery hace que AJAX sea realmente fácil, e incluso hay formas predeterminadas como

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

Que se encargará del lado AJAX de las cosas para usted.


Inspirándose en WebForms y en la respuesta proporcionada por Richard Gadsden, otro enfoque que utiliza javascript y la colección de formularios podría verse más o menos así:

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

El código provisto es para inspiración y no está de ninguna manera embellecido. Probablemente se podría hacer de diferentes maneras, supongo que todo se reduce a cómo decide persistir en el valor de scrollTop de su documento en el POST. Está funcionando completamente y debería ser seguro para navegadores cruzados, ya que estamos utilizando jQuery para hacer el desplazamiento. Creo que el código proporcionado se explica por sí mismo, pero estaré encantado de proporcionarle una descripción más detallada de lo que está sucediendo, solo háganmelo saber.


La forma en que funciona MaintainScrollPositionOnPostback es que tiene un par de campos ocultos: __SCROLLPOSITIONX y __SCROLLPOSITIONY

En una devolución de datos, establece estos,

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

y luego llama a 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; }

Pero como dijo la mayoría de la gente, MVC debería evitar las devoluciones de todos modos.


Lo resolví en JS:

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

Luego, en el documento listo:

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


Mi propia solución es usar cierta información en ViewData para saber qué área debe mostrarse en el backnavigation, y un pequeño javascript para ubicar el cursor de la página:

En la vista, un elemento como este:

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

Y el javascript para reposicionar la página:

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

Podría usar un switch para determinar qué elemento de la página de vista debe reubicar.

Espero eso ayude.


Usé atributos de nombre en las etiquetas. No se usó javascript

La página a la que quería volver tenía etiquetas <a> con un atributo de nombre, por ejemplo, <a name="testname">.

La página (vista) que devolví de la etiqueta usada <a href="<%: Request.UrlReferrer %> #testname "> Atrás </a>". Request.UrlReferrer se usa para ir a la página anterior. #Testname desplaza la página posición para etiquetar con el nombre "nombre de prueba".


Yo uso .scrollTop como se muestra a continuación, muy fácil, incluso funciona con múltiples formas en la vista (tengo una vista muy larga, dividida en múltiples formas):

Primero coloque esta propiedad dentro del modelo:

public string scrollTop { get; set; }

Y en la vista, dentro de la Forma n. ° 1:

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

dentro de la Forma n. ° 2:

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

dentro de la Forma n. ° 2:

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

y luego en la parte inferior de la vista:

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

Su posición de desplazamiento siempre se conserva en la devolución de datos porque los campos @ Html.HiddenFor almacenan su desplazamiento actual y lo pasan al modelo en la publicación. Y luego, cuando aparece la página, obtiene el valor de scrollTop del modelo. Al final, su página se comportará como un formulario web, todo permanece intacto.


una forma muy poco agradable de hacer esto es usar cookies.

Si usa UNA página en su MVC que maneja las otras páginas, podría usar un fragmento de código que carga cada página que crea una cookie (si no existe) llamada "scrolltop". Hay formas de que javascript actualice automáticamente esta cookie cuando el usuario se desplaza hacia arriba o hacia abajo mediante la captura de estos eventos o viendo el valor de scrollTop.

En una nueva página, solo tiene que cargar la posición guardada y hacer que la vista se desplace allí en 0 milisegundos (con Mootools o cualquier script Ajax esto debería ser posible) y el usuario estará exactamente donde estaba.

No sé mucho sobre asp, así que no sé si existe un método para anclar a una posición y actual. Javascript es una manera rápida y fácil. Los anclajes en HTMl podrían ser una opción si tuvieras todos los elementos anclados y publicaras el ancla en otras páginas.


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

Puede usar esto para mantener la posición de desplazamiento después de la devolución de datos.

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


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