$ location / html5とハッシュバングモードの切り替え/リンクの書き換え


179

Angularがtempaltes内のアンカータグのhref属性に表示されるURLを書き換えて、html5モードでもハッシュバングモードでも機能するように見えました。位置情報サービスドキュメントには、 HTMLリンクの書き換えによってハッシュバングの状況が処理されると記載されているようです。したがって、HTML5モードでない場合はハッシュが挿入され、HTML5モードの場合は挿入されないことを期待します。

ただし、書き換えは行われていないようです。次の例では、モードを変更することはできません。アプリケーションのすべてのリンクは手動で書き換える必要があります(または実行時に変数から派生させる必要があります。モードに応じてすべてのURLを手動で書き換える必要がありますか?

Angular 1.0.6、1.1.4、1.1.3でクライアント側のURLの書き換えが行われていないようです。すべてのhref値の先頭に、ハッシュバングモードの場合は#/、html5モードの場合は/を付ける必要があるようです。

書き換えを発生させるために必要な設定はありますか?ドキュメントを読み違えていますか?他にばかげたことをしていますか?

ここに小さな例があります:

<head>
    <script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.3/angular.js"></script>
</head>

<body>
    <div ng-view></div>
    <script>
        angular.module('sample', [])
            .config(
        ['$routeProvider', '$locationProvider',
            function ($routeProvider, $locationProvider) {

                //commenting out this line (switching to hashbang mode) breaks the app
                //-- unless # is added to the templates
                $locationProvider.html5Mode(true);

                $routeProvider.when('/', {
                    template: 'this is home. go to <a href="https://stackoverflow.com/about"/>about</a>'
                });
                $routeProvider.when('/about', {
                    template: 'this is about. go to <a href="https://stackoverflow.com/"/>home</a'
                });
            }
        ])
            .run();
    </script>
</body>

補遺:私の質問を再読する際に、誰がいつ書き換えをやりたかったかについて明確に明記せずに「書き換え」という用語を使用したことがわかりました。問題は、AngularがパスをレンダリングするときにURLを書き換える方法と、2つのモード間でJSコードのパスを均一に解釈する方法についてです。WebサーバーにHTML5互換の要求の書き換えを行わせる方法についてではありません


1
これがAngular 1.6 のソリューションです。
Mistalis 2017年

回答:


361

ドキュメントでは、AngularJSルーティングについてはあまり明確ではありません。HashbangとHTML5モードについて説明します。実際、AngularJSルーティングは3つのモードで動作します。

  • ハッシュバンモード
  • HTML5モード
  • HTML5モードでのハッシュバング

各モードには、それぞれのLocationUrlクラス(LocationHashbangUrl、LocationUrl、およびLocationHashbangInHTML5Url)があります。

URLの書き換えをシミュレートするには、実際にはhtml5modeをtrueに設定し、次のように$ snifferクラスを装飾する必要があります。

$provide.decorator('$sniffer', function($delegate) {
  $delegate.history = false;
  return $delegate;
});

これについて詳しく説明します。

ハッシュバンモード

構成:

$routeProvider
  .when('/path', {
    templateUrl: 'path.html',
});
$locationProvider
  .html5Mode(false)
  .hashPrefix('!');

これは、次のようなHTMLファイルでハッシュ付きのURLを使用する必要がある場合です。

<a href="index.html#!/path">link</a>

ブラウザでは、次のリンクを使用する必要があります。 http://www.example.com/base/index.html#!/base/path

純粋なハッシュバングモードで確認できるように、HTMLファイル内のすべてのリンクは、 "index.html#!"などのベースで始まる必要があります。

HTML5モード

構成:

$routeProvider
  .when('/path', {
    templateUrl: 'path.html',
  });
$locationProvider
  .html5Mode(true);

HTMLファイルでベースを設定する必要があります

<html>
  <head>
    <base href="/">
  </head>
</html>

このモードでは、HTMLファイルで#なしのリンクを使用できます

<a href="/path">link</a>

ブラウザのリンク:

http://www.example.com/base/path

HTML5モードでのハッシュバング

このモードは、実際にはHTML5モードを使用しているが、互換性のないブラウザーでアクティブ化されます。$ snifferサービスを装飾し、履歴をfalseに設定することで、互換性のあるブラウザーでこのモードをシミュレートできます。

構成:

$provide.decorator('$sniffer', function($delegate) {
  $delegate.history = false;
  return $delegate;
});
$routeProvider
  .when('/path', {
    templateUrl: 'path.html',
  });
$locationProvider
  .html5Mode(true)
  .hashPrefix('!');

HTMLファイルにベースを設定します。

<html>
  <head>
    <base href="/">
  </head>
</html>

この場合、リンクはHTMLファイルにハッシュなしで書き込むこともできます

<a href="/path">link</a>

ブラウザのリンク:

http://www.example.com/index.html#!/base/path

@jupiterさん、詳しい説明ありがとうございます。強打をスキップしてハッシュを保持し、Angularをトリックしてモードに応じて2セットのURLを必要としないようにすることができるかどうかを確認します!
laurelnaiad 2013年

1
私はあなたの問題を適切に理解していないと思います。ハッシュなしのURLだけを使用しないのはなぜですか?これらは、履歴APIをサポートするブラウザーと履歴APIをサポートしないブラウザーで動作します。AngularJSがリンクのクリックをインターセプトするため、AngularJSは、履歴APIをサポートしていないブラウザーで#をクリックすると、ロケーションバーに#バージョンを配置します。
木星

私は両方のモードをサポートする必要があるフレームワークに取り組んでいます。アプリの作成者は、テンプレートにハッシュがあるかどうか、および/または相対パスの解釈に変更があるかどうかを気にすることなく、どちらか一方を選択できる必要があります。あなたのトリックが「あなたがすることはすべてモードを変更すること」であることを真実にするのに役立つことを願っています(実用的な解決策が「モードをhtml5に設定してからブラウザの機能について角度をつけて嘘をつく」場合でも)。
laurelnaiad 2013年

1
$provideは未定義ですか?
Petrus Theron 2013

1
@pate-デコレータを設定するときに、config関数に$ provideを挿入する必要があります。
laurelnaiad 2013

8

将来の読者のために、Angular 1.6を使用している場合は、以下も変更する必要がありますhashPrefix

appModule.config(['$locationProvider', function($locationProvider) {
    $locationProvider.html5Mode(true);
    $locationProvider.hashPrefix('');
}]);

HTMLでベースを設定することを忘れないでください<head>

<head>
    <base href="/">
    ...
</head>

変更ログに関する詳細情報here


3
@Mistalisに感謝します。あなたの答えはうまくいきます。ルーティング後にページを更新すると、ページが見つからないというエラーが発生します。私を助けてください..
Ashish Mehta 2017年

@AshishMehtaこんにちはアシッシュ。この回答を読むことをお勧めします。問題が解決する可能性があります。バイバイ!:)
Mistalis

0

これは私が理解するのに少し時間がかかったので、これが私がそれを機能させた方法です-#for SEOなしのAngular WebAPI ASP Routing

  1. Index.htmlに追加-base href = "/">
  2. $ locationProvider.html5Mode(true);を追加します。app.config

  3. 画像のアップロードで特定のコントローラー(ホームコントローラーにある)を無視する必要があるため、RouteConfigにそのルールを追加しました

         routes.MapRoute(
            name: "Default2",
            url: "Home/{*.}",
            defaults: new { controller = "Home", action = "SaveImage" }
        );
  4. Global.asaxに次の行を追加します。APIと画像のアップロードパスを無視するようにして、通常どおり機能するようにします。

     private const string ROOT_DOCUMENT = "/Index.html";
    
    protected void Application_BeginRequest(Object sender, EventArgs e)
    {
        var path = Request.Url.AbsolutePath;
        var isApi = path.StartsWith("/api", StringComparison.InvariantCultureIgnoreCase);
        var isImageUpload = path.StartsWith("/home", StringComparison.InvariantCultureIgnoreCase);
    
        if (isApi || isImageUpload)
            return;
    
        string url = Request.Url.LocalPath;
        if (!System.IO.File.Exists(Context.Server.MapPath(url)))
            Context.RewritePath(ROOT_DOCUMENT);
    }
  5. リダイレクトするには、window.locationではなく$ location.url( '/ XXX')を使用してください...

  6. CSSファイルを絶対パスで参照する

ではなく

<link href="app/content/bootstrapwc.css" rel="stylesheet" />

最後の注意-この方法でこれを行うと、完全に制御できるようになり、Web構成に対して何もする必要がなくなりました。

これが理解するのに少し時間がかかったので、これが役立つことを願っています。


0

HTML5モードと固定トークンを使用してアプリケーションにアクセスし、(ユーザーが自分のページを更新できるようにトークンを保持するために)hashbangメソッドに切り替えたいと思っていました。

アプリにアクセスするためのURL:

http://myapp.com/amazing_url?token=super_token

次に、ユーザーがページをロードすると、次のようになります。

http://myapp.com/amazing_url?token=super_token#/amazing_url

次に、ユーザーがナビゲートすると:

http://myapp.com/amazing_url?token=super_token#/another_url

これにより、トークンをURLに保持し、ユーザーが閲覧しているときの状態を保持します。URLの可視性を少し失いましたが、完全な方法はありません。

したがって、HTML5モードを有効にしてから、このコントローラーを追加しないでください。

.config ($stateProvider)->
    $stateProvider.state('home-loading', {
         url: '/',
         controller: 'homeController'
    })
.controller 'homeController', ($state, $location)->
    if window.location.pathname != '/'
        $location.url(window.location.pathname+window.location.search).replace()
    else
        $state.go('home', {}, { location: 'replace' })
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.