web-dev-qa-db-ja.com

MVCでスクロール位置を維持するにはどうすればよいですか?

私はMVCでプロジェクトに取り組んでおり、それについて学ぶことを楽しんでいます。いくつかの成長痛がありますが、一度それらを理解すると、それは悪くありません。 WebFormsの世界で本当に簡単なことの1つは、ページのスクロール位置を維持することです。 MaintainScrollPositionOnPostbackプロパティをtrueに設定するだけです。ただし、MVCでは、ポストバックを使用していないため、これは機能しません。これを処理する標準的な方法は何ですか?

編集: Ajaxは受け入れられますが、AJAXなしでどのように行うのかも疑問に思いました。

25
Papa Burgundy

MaintainScrollPositionOnPostbackが機能する方法は、__ SCROLLPOSITIONXと__SCROLLPOSITIONYの2つの非表示フィールドがあることです。

ポストバックでは、これらを設定します、

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はとにかくポストバックを避けるべきです。

8
Richard Gadsden

私はJSでこれを解決しました:

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

次に、ドキュメントの準備ができました:

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

実際、これを処理する標準的な方法はありません。これは、ポストバックモデルをサポートするためのMicrosoftのハックでした。すべてのコントロールがポストバックを行い、ユーザーは常にページの上部にプッシュバックされるため、これが必要でした。

MVCで使用するための推奨事項は、AJAXを使用してほとんどの投稿をサーバーに戻すことです。ページを再レンダリングする必要がないように、フォーカスは移動されません。 jQueryはAJAXを本当に簡単にし、次のようなデフォルトのフォームもあります

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

これはあなたのためにAJAX側の面倒を見るでしょう。

6
Nick Berardi

WebFormsとRichardGadsdenによって提供された回答からインスピレーションを得て、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);
});

提供されているコードはインスピレーションを得るためのものであり、決して見栄えがするものではありません。それはおそらくいくつかの異なる方法で行うことができます。それはすべて、POST全体でドキュメントのscrollTop値を永続化する方法にかかっていると思います。 jQueryを使用してスクロールを実行しているため、完全に機能しており、クロスブラウザで安全である必要があります。提供されたコードは自明であると思いますが、何が起こっているのかについてより詳細な説明を提供させていただきますので、お知らせください。

4
Sniffdk

私自身の回避策は、ViewDataの情報を使用して、バックナビゲーションに表示する必要のある領域と、ページのカーソルを配置するための小さな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を使用して、ビューページから再配置する必要のある要素を決定できます。

それが役に立てば幸い。

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

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

これは、FF4とIE9でのみテストしたシンプルで純粋なJavascriptソリューションです。

このソリューションは、ページ上の標準の#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];
}

これは私のニーズに合っていますが、より一般的/再利用可能である可能性があります-誰かがこれを改善してくれることを嬉しく思います... :-)

1
user744322

タグに名前属性を使用しました。 JavaScriptは使用されていません。

戻りたいページには、名前属性を持つ<a>タグがありました。 <aname = "testname">。

使用済みタグ<ahref = "<%:Request.UrlReferrer%>#testname">戻る</a> "から戻ったページ(ビュー)。Request.UrlReferrerは前のページに移動するために使用されます。#testnameはページをスクロールします「testname」という名前でタグ付けする位置。

1
the1johan

これを行うための良い方法は、Cookieを使用することです。

他のページを処理するMVCで1つのページを使用する場合は、「scrolltop」と呼ばれるCookie(存在しない場合)を作成するすべてのページをロードするコードスニペットを使用できます。ユーザーがこれらのイベントをキャッチするか、scrollTop値を監視することにより、ユーザーが上下にスクロールしたときにjavascriptがこのCookieを自動的に更新するようにする方法があります。

新しいページでは、保存された位置をロードし、0ミリ秒でビューをスクロールさせる必要があります(Mootoolsまたは任意のAjaxスクリプトを使用すると、これが可能になります)。ユーザーは正確に元の場所に移動します。

Aspについてはよくわからないので、現在のy位置に固定するメソッドが存在するかどうかはわかりません。 Javascriptは速くて簡単な方法です。すべての要素をアンカーして他のページにアンカーを投稿した場合、HTM1のアンカーがオプションになる可能性があります。

0
xaddict

以下に示すように.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値を取得します。最終的に、ページはWebフォームのように動作し、すべてがそのまま残ります。

0
Yogi