2009-01-27 11 views
22

Im trabajando en un proyecto en MVC y he disfrutado aprendiendo al respecto. 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?¿Cómo mantengo la posición de desplazamiento en MVC?

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

+0

Si está utilizando AJAX y jQuery a continuación, seleccione un elemento visible que es más alta en su página. Diga que es un ancla sin texto Luego en su $ (documento) .ready write $ ('# pageTop'). Focus(); –

Respuesta

8

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

En una devolución de datos, se establece éstos,

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 se llama 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.

+0

Humph! No sé cómo editar esto para poner una muestra de código muy bien: ¿alguien quiere decirme cómo estoy siendo estúpido? –

2

Mi propia solución está usando algo de información en el ViewData saber qué área debe ser mostrado en el backnavigation, y un poco de javascript para la posición de la página del cursor:

En la vista, un elemento como este:

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

Y el javascript para repositionate 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> 

Se puede usar un switch para determinar qué elemento de la página de vista que debe reubicar.

Espero que ayude.

+0

Esto no mantiene la ubicación exacta como lo hizo Web Forms. –

6

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 su uso 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 AJAX hace realmente fácil, y hay incluso formas predeterminadas como

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

que se encargará de la parte AJAX de las cosas para usted.

0

una forma muy poco agradable de hacer esto es el uso de cookies.

Si usa UNA página en su MVC que maneja las otras páginas, puede 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 al detectar estos eventos o ver el valor de scrollTop.

En una página nueva, 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 estaban.

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.

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

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

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

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

La página (ver) Me he vuelto de etiqueta usada < a href = "<%: Request.UrlReferrer% > #testname" > Volver </a >" Request.UrlReferrer se utiliza para ir a la página anterior. #testname desplaza la posición de la página a la etiqueta con el nombre "nombre_prueba".

1

Aquí es una solución simple, puro Javascript, que he probado en FF4 e IE9 solamente.

la idea es que esta solución debe poder funcionar fácilmente por volviendo a las etiquetas estándar #anchor en una página. Qué hago ing está reemplazando 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 no funciona por alguna razón, el navegador aún debe desplazarse a la posición #anchor ...

de marcado:

<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, puede ser más genérico/reutilizable - Estaría encantado alguien para mejorar en esto ... :-)

4

Inspirándose en formularios Web y la respuesta proporcionada por Richard Gadsden, otro enfoque usando javascript y la colección forma podría ser algo como esto:

@{ 
    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 siempre 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.

+0

¡Gracias, esto funcionó bien para mí con un mínimo esfuerzo! – Kon

+0

Un extra gracias de mi parte. Puse las últimas 3 líneas en mi sección $ (document) .ready() y todo funcionó muy bien. – Rocklan

26

he resuelto esto en JS:

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

A continuación, en el documento listo:

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

Muy bueno. Al utilizar un motor de enrutamiento como asp.net mvc, la página en el almacenamiento local puede no coincidir, pero realmente no es necesaria si usa un nombre único para el valor de desplazamiento de almacenamiento local ... $ (documento) .scroll (function() { localStorage ['myuniquename'] = $ (document) .scrollTop(); }); $ (document) .ready (function() { $ (document) .scrollTop (localStorage ['myuniquename']); }); – tintyethan

+0

Solía ​​usar esto en mis aplicaciones asp.net, pero ahora que uso MVC4 simplemente ya no quiere funcionar. La cantidad y magnitud con la que se desplaza parece ser tan aleatoria. No tengo idea de lo que está pasando. Pongo puntos de interrupción y veo que está haciendo "scrollTop (166)", pero el navegador simplemente lo ignora, otras veces funciona bien, y algunas veces solo se desplaza un poco de lo que se supone que debe. –

+0

Acabo de probar con un proyecto de Internet Application MVC4. Funciona. Tal vez haya un conflicto de scripts o depende de tu navegador.Agregué el fragmento después de '@ Scripts.Render (" ~/bundles/jquery ")' – Madagaga

0

utilizo .scrollTop como se muestra a continuación, muy fácil, incluso funciona con múltiples formas en el vista (tengo una vista muy larga, desglosada en varias formas):

Primero ponga esta propiedad dentro del modelo:

   public string scrollTop { get; set; } 

Y en la vista, en el interior Forma # 1:

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

dentro Forma # 2:

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

dentro Forma # 2:

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

y luego en el 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.

-1

@{ 
 

 
} 
 

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

Usted 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

Cuestiones relacionadas