Улучшить эту статьюИспользование сервиса $location
Сервис $location анализирует URL в адресной строке браузера (на основе window.location) и делает URL доступным для вашего приложения. Изменения в URL адресной строки отображаются в сервисе $location, а изменения в $location отражаются в адресной строке браузера.
Сервис $location:
- Предоставляет доступ к текущему URL в адресной строке браузера, так что вы можете:
- Отслеживать и наблюдать за URL.
- Изменять URL.
- Обеспечивает синхронизацию между собой и URL браузера, когда пользователь:
- Изменяет адрес в адресной строке браузера.
- Нажимает кнопки «Назад» или «Вперед» в браузере (или кликает на ссылку в истории).
- Нажимает на ссылку на странице.
- Представляет объект URL в виде набора методов (протокол, хост, порт, путь, поиск, хэш).
Сравнение $location и window.location
| window.location | Сервис $location | |
|---|---|---|
| назначение | предоставляет чтение/запись текущего местоположения браузера | то же |
| API | предоставляет «сырой» объект со свойствами, которые можно напрямую изменять | предоставляет методы в стиле jQuery для получения и установки значений |
| интеграция с жизненным циклом приложения AngularJS | нет | знает обо всех внутренних фазах жизненного цикла, интегрируется с $watch, ... |
| бесшовная интеграция с HTML5 API | нет | да (с резервным вариантом для устаревших браузеров) |
| осознает корневой каталог/контекст, из которого загружено приложение | нет — window.location.pathname возвращает "/docroot/actual/path" | да — $location.path() возвращает "/actual/path" |
Когда следует использовать $location?
Всякий раз, когда ваше приложение должно реагировать на изменения текущего URL или если вы хотите изменить текущий URL в браузере.
Что он не делает?
Он не вызывает полной перезагрузки страницы при изменении URL браузера. Чтобы перезагрузить страницу после изменения URL, используйте более низкоуровневый API, $window.location.href.
Обзор API
Сервис $location может вести себя по-разному в зависимости от конфигурации, заданной при его инициализации. По умолчанию подходит для многих приложений, но для других конфигурирование позволит использовать новые возможности.
После инициализации сервиса $location, можно взаимодействовать с ним с помощью методов получения и установки значений в стиле jQuery, которые позволяют получать или изменять текущий URL в браузере.
Конфигурация сервиса $location
Чтобы настроить сервис $location, получите $locationProvider и задайте параметры следующим образом:
-
html5Mode(mode):
{boolean|Object}
falseили{enabled: false}(по умолчанию) — см. Режим Hashbang
trueили{enabled: true}— см. Режим HTML5
{..., requireBase: true/false}(только для режима HTML5) — см. Относительные ссылки
{..., rewriteLinks: true/false/'string'}(только для режима HTML5) — см. Переписывание ссылок HTML
По умолчанию:{ enabled: false, requireBase: true, rewriteLinks: true } -
hashPrefix(prefix):
{string}
Префикс, используемый для Hashbang URL (используется в режиме Hashbang или в устаревших браузерах в режиме HTML5).
По умолчанию:'!'
Пример конфигурации
$locationProvider.html5Mode(true).hashPrefix('*');
Методы получения и установки
Сервис $location предоставляет методы получения только для чтения для частей URL (absUrl, protocol, host, port) и методы получения/установки для url, path, search, hash:
// get the current path
$location.path();
// change the path
$location.path('/newValue')
Все методы установки возвращают тот же объект $location для цепочки вызовов. Например, чтобы изменить несколько сегментов сразу, можно использовать цепочку установок:
$location.path('/newValue').search({key: value});
Метод replace
Существует специальный метод replace, который можно использовать для того, чтобы сообщить сервису $location, что при следующей синхронизации сервиса $location с браузером последняя запись истории должна быть заменена, а не создана новая. Это полезно при реализации перенаправлений, которые в противном случае нарушат работу кнопки «Назад» (возврат приведет к повторному вызову перенаправления). Чтобы изменить текущий URL без создания новой записи в истории браузера, можно вызвать:
$location.path('/someNewPath');
$location.replace();
// or you can chain these as: $location.path('/someNewPath').replace();
Обратите внимание, что установщики не обновляют window.location немедленно. Вместо этого, сервис $location осознает жизненный цикл scope и объединяет несколько мутаций $location в одно «сохранение» в объект window.location во время фазы жизненного цикла scope $digest. Поскольку несколько изменений состояния $location будут переданы браузеру как одно изменение, достаточно вызвать метод replace() один раз, чтобы сделать все «сохранение» операцией замены, а не добавлением в историю браузера. После обновления браузера сервис $location сбрасывает флаг, установленный методом replace(), и будущие мутации будут создавать новые записи истории, если метод replace() не будет вызван снова.
Методы установки и кодировка символов
Вы можете передавать специальные символы в сервис $location , и он будет кодировать их в соответствии с правилами, указанными в RFC 3986. При обращении к методам:
- Все значения, передаваемые методам установки
$location,path(),search(),hash(), кодируются. - Методы получения (вызовы методов без параметров) возвращают декодированные значения для следующих методов
path(),search(),hash(). - При вызове метода
absUrl(), возвращаемое значение — полный URL с закодированными сегментами. - При вызове метода
url(), возвращаемое значение — путь, поиск и хэш в формате/path?search=a&b=c#hash. Сегменты также закодированы.
Режимы Hashbang и HTML5
Сервис $location имеет два режима конфигурации, которые контролируют формат URL в адресной строке браузера: режим Hashbang (по умолчанию) и режим HTML5, основанный на использовании API истории HTML5. Приложения используют одинаковый API в обоих режимах, и сервис $location будет работать с соответствующими сегментами URL и API браузера для облегчения изменения URL браузера и управления историей.
| Режим Hashbang | Режим HTML5 | |
|---|---|---|
| конфигурация | по умолчанию | { html5Mode: true } |
| формат URL | Hashbang URL во всех браузерах | обычные URL в современных браузерах, Hashbang URL в старых браузерах |
| переписывание ссылок <a href=""> | нет | да |
| требует конфигурации на стороне сервера | нет | да |
Режим Hashbang (режим по умолчанию)
В этом режиме $location использует Hashbang URL во всех браузерах. AngularJS также не перехватывает и не переписывает ссылки в этом режиме. То есть ссылки работают как ожидается, а также выполняют полную перезагрузку страницы, когда были изменены части URL, кроме фрагмента хэша.
it('should show example', function() {
module(function($locationProvider) {
$locationProvider.html5Mode(false);
$locationProvider.hashPrefix('!');
});
inject(function($location) {
// open http://example.com/base/index.html#!/a
expect($location.absUrl()).toBe('http://example.com/base/index.html#!/a');
expect($location.path()).toBe('/a');
$location.path('/foo');
expect($location.absUrl()).toBe('http://example.com/base/index.html#!/foo');
expect($location.search()).toEqual({});
$location.search({a: 'b', c: true});
expect($location.absUrl()).toBe('http://example.com/base/index.html#!/foo?a=b&c');
$location.path('/new').search('x=y');
expect($location.absUrl()).toBe('http://example.com/base/index.html#!/new?x=y');
});
});
Режим HTML5
В режиме HTML5 сервис $location взаимодействует с URL браузера через API истории HTML5 для получения и установки значений пути и поиска. Это позволяет использовать обычные сегменты пути и поиска URL вместо их эквивалентов с Hashbang. Если API истории HTML5 не поддерживается браузером, сервис $location автоматически переходит к Hashbang URL. Это избавляет вас от необходимости беспокоиться о том, поддерживает ли браузер, отображающий ваше приложение, API истории; сервис $location прозрачно использует лучший доступный вариант.
- Открытие обычного URL в устаревшем браузере —> перенаправляет на Hashbang URL
- Открытие Hashbang URL в современном браузере —> переписывает на обычный URL
Обратите внимание, что в этом режиме AngularJS перехватывает все ссылки (подлежащие правилам «Переписывание ссылок HTML» ниже) и обновляет URL таким образом, чтобы никогда не происходила полная перезагрузка страницы.
it('should show example', function() {
module(function($locationProvider) {
$locationProvider.html5Mode(true);
$locationProvider.hashPrefix('!');
});
inject(function($location) {
// in browser with HTML5 history support:
// open http://example.com/#!/a -> rewrite to http://example.com/a
// (replacing the http://example.com/#!/a history record)
expect($location.path()).toBe('/a');
$location.path('/foo');
expect($location.absUrl()).toBe('http://example.com/foo');
expect($location.search()).toEqual({});
$location.search({a: 'b', c: true});
expect($location.absUrl()).toBe('http://example.com/foo?a=b&c');
$location.path('/new').search('x=y');
expect($location.url()).toBe('/new?x=y');
expect($location.absUrl()).toBe('http://example.com/new?x=y');
});
});
it('should show example (when browser doesn\'t support HTML5 mode', function() {
module(function($provide, $locationProvider) {
$locationProvider.html5Mode(true);
$locationProvider.hashPrefix('!');
$provide.value('$sniffer', {history: false});
});
inject(initBrowser({ url: 'http://example.com/new?x=y', basePath: '/' }),
function($location) {
// in browser without html5 history support:
// open http://example.com/new?x=y -> redirect to http://example.com/#!/new?x=y
// (again replacing the http://example.com/new?x=y history item)
expect($location.path()).toBe('/new');
expect($location.search()).toEqual({x: 'y'});
$location.path('/foo/bar');
expect($location.path()).toBe('/foo/bar');
expect($location.url()).toBe('/foo/bar?x=y');
expect($location.absUrl()).toBe('http://example.com/#!/foo/bar?x=y');
});
});
Резервный вариант для устаревших браузеров
Для браузеров, поддерживающих API истории HTML5, $location использует API истории HTML5 для записи пути и поиска. Если API истории не поддерживается браузером, $location предоставляет Hashbang URL. Это избавляет вас от необходимости беспокоиться о том, поддерживает ли браузер, отображающий ваше приложение, API истории; сервис $location делает это прозрачным для вас.
Переписывание ссылок HTML
При использовании режима API истории HTML5 вам не понадобятся специальные ссылки Hashbang. Вам нужно лишь указать обычные ссылки URL, такие как: <a href="/some?foo=bar">link</a>
Когда пользователь нажимает на эту ссылку:
- В устаревшем браузере URL меняется на
/index.html#!/some?foo=bar - В современном браузере URL меняется на
/some?foo=bar
В следующих случаях ссылки не переписываются; вместо этого браузер выполнит полную перезагрузку страницы по оригинальной ссылке.
- Ссылки, содержащие элемент
target,
Пример:<a href="/ext/link?a=b" target="_self">link</a> - Абсолютные ссылки, ведущие на другой домен,
Пример:<a href="http://angularjs.org/">link</a> - Ссылки, начинающиеся с '/', ведущие к другому базовому пути,
Пример:<a href="/not-my-base/link">link</a>
Если mode.rewriteLinks установлено в false в объекте конфигурации mode , переданном в $locationProvider.html5Mode(), браузер выполнит полную перезагрузку страницы для каждой ссылки. mode.rewriteLinks также может быть установлено в строку, что позволит переписывать ссылки только для элементов anchor, которые имеют данный атрибут.
Например, если mode.rewriteLinks установлено в 'internal-link':
-
<a href="/some/path" internal-link>link</a>будет переписан -
<a href="/some/path">link</a>выполнит полную перезагрузку страницы
Обратите внимание, что нормализация имен атрибутов здесь не применяется, поэтому 'internalLink' не будет соответствовать 'internal-link'.
Относительные ссылки
Убедитесь, что все относительные ссылки, изображения, скрипты и т. д. прописаны правильно. AngularJS требует указания базового URL в заголовке вашего основного HTML-файла (<base href="/my-base/index.html">) , если html5Mode.requireBase не установлено в false в объекте определения html5Mode, переданном в $locationProvider.html5Mode(). В этом случае относительные URL всегда будут разрешаться к этому базовому URL, даже если начальный URL документа был другим.
Существует одно исключение: ссылки, содержащие только фрагмент хеша (например, <a href="#target">), изменят только $location.hash() и не изменят URL иначе. Это полезно для прокрутки до якорей на одной странице без необходимости знать, на какой странице пользователь находится в данный момент.
Серверная сторона
Использование этого режима требует переписывания URL на серверной стороне, в основном необходимо переписать все ссылки на точку входа в ваше приложение (например, index.html). Необходимо также использовать тег <base>, так как он позволяет AngularJS различать часть URL, являющуюся базовой частью приложения, и путь, который должен обрабатываться приложением.
Ограничения base href
Сервис $location не может работать должным образом, если текущий URL находится за пределами URL, указанного как base href. Это может иметь неожиданные и запутанные последствия...
Рассмотрим базовый href, заданный следующим образом: <base href="/base/"> (т. е. приложение находится в папке под названием /base). URL /base фактически находится за пределами приложения (он относится к файлу base в корневой папке /).
Если вы хотите иметь возможность переходить к приложению по URL, такому как /base, то вы должны убедиться, что ваш сервер настроен на перенаправление таких запросов на /base/.
Дополнительную информацию см. в https://github.com/angular/angular.js/issues/14018.
Передача ссылок между разными браузерами
Благодаря возможности переписывания в режиме HTML5, ваши пользователи смогут открывать обычные URL-ссылки в старых браузерах и ссылки с hashbang в современных браузерах:
- Современные браузеры будут переписывать URL с hashbang на обычные URL.
- Старые браузеры будут перенаправлять обычные URL на URL с hashbang.
Здесь вы можете увидеть два $location экземпляра, которые показывают разницу между режимом Html5 и режимом Html5 Fallback. Обратите внимание, что для имитации различных уровней поддержки браузеров экземпляры $location подключены к сервису fakeBrowser, который вам не нужно настраивать в реальных проектах.
Обратите внимание, что при вводе URL с hashbang в первый браузер (или наоборот) он не переписывает/перенаправляет на обычный/hashbang URL, так как это преобразование происходит только при парсинге начального URL = при перезагрузке страницы.
В этих примерах мы используем <base href="/base/index.html" />. Входные данные представляют собой адресную строку браузера.
Браузер в режиме HTML5
Браузер в режиме HTML5 Fallback (режим Hashbang)
Ограничения
Переход при перезагрузке страницы
Сервис $location позволяет изменить только URL; он не позволяет перезагрузить страницу. Если вам нужно изменить URL и перезагрузить страницу или перейти на другую страницу, используйте более низкоуровневый API, $window.location.href.
Использование $location вне жизненного цикла области видимости
$location знает о жизненном цикле области видимости AngularJS scope. Когда URL изменяется в браузере, он обновляет $location и вызывает $apply, чтобы все $наблюдатели / $наблюдатели получили уведомление. Когда вы изменяете $location внутри стадии $digest, все в порядке; $location распространит это изменение в браузер и уведомит всех $наблюдателей / $наблюдателей. Если вы хотите изменить $location извне AngularJS (например, через событие DOM или во время тестирования), вы должны вызвать $apply, чтобы распространить изменения.
$location.path() и префиксы ! или /
Путь всегда должен начинаться с косой черты (/); установщик $location.path() добавит косую черту, если она отсутствует.
Обратите внимание, что префикс ! в режиме hashbang не является частью $location.path(); на самом деле это hashPrefix.
Обход вашего приложения
Большинство современных поисковых систем способны обходить приложения AJAX с динамическим содержимым, при условии, что все включенные ресурсы доступны ботам-роботам-поисковикам.
Также существует специальная схема обхода AJAX, разработанная Google, которая позволяет ботам обходить статический эквивалент динамически сгенерированной страницы, но эта схема устарела, и поддержка её может различаться в зависимости от поисковой системы.
Тестирование с помощью сервиса $location
При использовании сервиса $location во время тестирования вы находитесь вне жизненного цикла области видимости Angular. Это означает, что вы несете ответственность за вызов scope.$apply().
describe('serviceUnderTest', function() {
beforeEach(module(function($provide) {
$provide.factory('serviceUnderTest', function($location) {
// whatever it does...
});
});
it('should...', inject(function($location, $rootScope, serviceUnderTest) {
$location.path('/new/path');
$rootScope.$apply();
// test whatever the service should do...
}));
});
Двунаправленная привязка к $location
Так как $location использует геттеры/сеттеры, вы можете использовать ng-model-options="{ getterSetter: true }" для привязки его к ngModel:
Связанный API
© 2010–2020 Google, Inc.
Licensed under the Creative Commons Attribution License 3.0.
https://code.angularjs.org/1.8.2/docs/guide/$location