Html 如何在 MVC 中保持滚动位置?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/484463/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 23:06:34  来源:igfitidea点击:

How do I maintain scroll position in MVC?

htmlasp.net-mvcmodel-view-controllerscroll-position

提问by Papa Burgundy

Im working on a project in MVC and have enjoyed learning about it. There are a few growing pains but once you figure them out it's not bad. One thing that is really simple in the WebForms world is maintaining the scroll position on a page. All you do is set the MaintainScrollPositionOnPostback property to true. However, in MVC, Im not using postbacks so this will not work for me. What is the standard way of handling this?

我正在 MVC 中从事一个项目,并且很喜欢了解它。有一些成长的烦恼,但一旦你弄清楚它们就不错了。在 WebForms 世界中,真正简单的一件事是维护页面上的滚动位置。您所做的就是将MaintainScrollPositionOnPostback 属性设置为true。但是,在 MVC 中,我不使用回发,所以这对我不起作用。处理这个问题的标准方法是什么?

Edit:Ajax is acceptable, but I was also wondering how you would do it without AJAX.

编辑:Ajax 是可以接受的,但我也想知道如果没有 AJAX,你会怎么做。

采纳答案by Richard Gadsden

The way MaintainScrollPositionOnPostback works is that it has a pair of hidden fields: __SCROLLPOSITIONX and __SCROLLPOSITIONY

MaintainScrollPositionOnPostback 的工作方式是它有一对隐藏字段:__SCROLLPOSITIONX 和 __SCROLLPOSITIONY

On a postback, it sets these,

在回发时,它设置了这些,

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

and then it calls RestoreScrollPosition:

然后它调用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;
}

But as most people said, MVC should be avoiding postbacks anyway.

但正如大多数人所说,MVC 无论如何都应该避免回发。

回答by Madagaga

I've resolved this in JS :

我已经在 J​​S 中解决了这个问题:

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

Then in document ready :

然后准备好文档:

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

回答by Nick Berardi

Actually there is no standard way of handling this, this was a Microsoft hack to support their post back model. They needed this because every control did a post back and the user would constantly be pushed back to the top of the page.

实际上没有标准的方法来处理这个,这是一个微软的黑客来支持他们的回发模型。他们需要这样做,因为每个控件都会回发一次,并且用户会不断被推回到页面顶部。

The recommendation for use with MVC is to do most of your post back to servers using AJAX. So that the page doesn't have to rerender the the focus is not moved. jQuery makes AJAX really easy, and there is even default forms like

与 MVC 一起使用的建议是使用 AJAX 将大部分帖子发回服务器。这样页面就不必重新渲染焦点不会移动。jQuery 让 AJAX 变得非常简单,甚至还有像这样的默认表单

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

Which will take care of the AJAX side of things for you.

它将为您处理 AJAX 方面的事情。

回答by Sniffdk

Taking inspiration from WebForms and the answer provided by Richard Gadsden, another approach using javascript and the form collection could look something like this:

从 WebForms 和 Richard Gadsden 提供的答案中汲取灵感,另一种使用 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);
});

The code provided is for inspiration and is in no way prettified. It could probably be done in a few different ways, I guess it all comes down to how you decide to persist the scrollTop value of your document across the POST. It is fully working and should be cross browser safe since we are using jQuery to do the scrolling. I believe the code provided is self-explanatory, but I will be happy to provide a more detailed description on whats going on, just let me know.

提供的代码仅供参考,绝不是美化的。它可能以几种不同的方式完成,我想这一切都取决于您如何决定在整个 POST 中保留文档的 scrollTop 值。由于我们使用 jQuery 进行滚动,因此它完全正常工作并且应该是跨浏览器安全的。我相信所提供的代码是不言自明的,但我很乐意提供有关正在发生的事情的更详细的描述,请告诉我。

回答by mapache

My own workaround is using some info in the ViewDatato know what area must be shown in the backnavigation, and a little javascript to position the page's cursor:

我自己的解决方法是使用一些信息在ViewData知道面积必须在backnavigation显示,和一点点的JavaScript来定位页面的光标:

In the View, an element like this:

在视图中,一个元素是这样的:

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

And the javascript to repositionate the page:

以及重新定位页面的 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>

You could use a switchto determine what element from the view page you must relocate.

您可以使用 aswitch来确定您必须重新定位视图页面中的哪个元素。

Hope it helps.

希望能帮助到你。

回答by the1johan

I used name attributes in tags. No javascript used.

我在标签中使用了名称属性。没有使用 javascript。

The page that I wanted to return to had <a> tags with name attribute, e.g. <a name="testname">.

我想返回的页面有带有名称属性的 <a> 标签,例如 <a name="testname">。

The page (view) I returned from used tag <a href="<%: Request.UrlReferrer %>#testname">Back</a>". Request.UrlReferrer is used to go to previous page. #testname scrolls the page position to tag with name "testname".

我从使用的标签返回的页面(视图)<a href="<%: Request.UrlReferrer %>#testname">Back</a>"。Request.UrlReferrer 用于转到上一页。#testname 滚动页面用名称“testname”标记的位置。

回答by Mike Flynn

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

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

回答by user744322

Here's a simple, pure Javascript solution which I've tested in FF4 and IE9 only.

这是我仅在 FF4 和 IE9 中测试过的简单纯 Javascript 解决方案。

The idea is that this solution should degrade gracefully by falling back to the standard #anchortags on a page. What I'm doing is replacing those #anchortags on the fly with the X and Y coordinates, then on load, I simply read those values from the querystring and scroll there. If this fails for some reason, the browser should still navigate to the #anchorposition...

这个想法是这个解决方案应该通过回退到#anchor页面上的标准标签来优雅地降级。我正在做的是用#anchorX 和 Y 坐标动态替换这些标签,然后在加载时,我只是从查询字符串中读取这些值并在那里滚动。如果由于某种原因失败,浏览器仍应导航到该#anchor位置...

Markup:

标记:

<a href="/somecontroller/someaction/#someanchor">My Link</a>

jQuery:

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

A couple of helper methods:

几个辅助方法:

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

This fits my needs, but could be more generic/reusable - I'd be happy for someone to improve on this... :-)

这符合我的需求,但可能更通用/可重用 - 我很乐意有人对此进行改进...... :-)

回答by xaddict

a very not-nice way to do this is using cookies.

一个非常不好的方法是使用 cookie。

If you use ONE page in your MVC which handles the other pages you could a code-snippet to it that loads every page which creates a cookie (if non-existent) called "scrolltop". There are ways to have javascript automatically update this cookie when the user scrolls up or down by catching these events or watching the scrollTop value.

如果您在 MVC 中使用一个页面来处理其他页面,您可以向它添加一个代码片段,加载每个页面,这些页面创建一个名为“scrolltop”的 cookie(如果不存在)。当用户向上或向下滚动时,通过捕获这些事件或查看 scrollTop 值,可以让 javascript 自动更新此 cookie。

On a new page you just have to load the saved position and make the view scroll there in 0 milliseconds (with Mootools or any Ajax script this should be possible) and the user will be exactly where they were.

在一个新页面上,您只需要加载保存的位置并使视图在 0 毫秒内滚动到那里(使用 Mootools 或任何 Ajax 脚本这应该是可能的),并且用户将准确地位于他们所在的位置。

I don't know much about asp so I don't know if a method exists to anchor to a current y-position. Javascript is a fast and easy way. Anchors in HTMl could be an option if you had every element anchored and posted the anchor to other pages.

我不太了解 asp,所以我不知道是否存在锚定到当前 y 位置的方法。Javascript 是一种快速简便的方法。如果您将每个元素都锚定并将锚点发布到其他页面,则 HTMl 中的锚点可能是一种选择。

回答by Colin Wiseman

10 years on and a different JS solution. The other JS solution waits for the page to scroll and when the page loads scrolls to whatever position was saved. That's fine for probably most folks (although it doesn't remove the value so the page would always scroll to that position when you reviewed that page...). My solution is to wait for the form to submit:

10 年过去了,一个不同的 JS 解决方案。另一个 JS 解决方案等待页面滚动,并在页面加载时滚动到保存的任何位置。这可能对大多数人来说都很好(尽管它不会删除该值,因此当您查看该页面时该页面将始终滚动到该位置......)。我的解决方案是等待表单提交:

(Yes, it is using jQuery, but the site has a lot of it...)

(是的,它使用的是 jQuery,但该站点有很多...)

    // OWNER'S FORM POSITION
    if ($("[js-owner-request]").length) {
        $("[js-owner-request]").on("submit", function() {
            localStorage['owner-request__scrollTop'] = $(this).offset().top;
        });

        if (localStorage['owner-request__scrollTop'] !== "null") {
            $(document).scrollTop(localStorage['owner-request__scrollTop']);
            localStorage['owner-request__scrollTop'] = "null"; // set to null so we don't always scroll...
        }
    }

This scrolls back to the top of the form, that way any error messages would be visible as you might have scrolled beyond the validation summary.

这将滚动回表单顶部,这样任何错误消息都将可见,因为您可能已经滚动到验证摘要之外。