Улучшить эту документациюИспользование сервиса $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, ... |
| бесшовное интегрирование с API HTML5 | нет | да (с резервным вариантом для устаревших браузеров) |
| осознаёт docroot/контекст, из которого загружено приложение | нет - 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 во время фазы $digest scope. Поскольку несколько изменений состояния $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 | URL с Hashbang во всех браузерах | обычные URL в современных браузерах, URL с Hashbang в старых браузерах |
| переписывание ссылок <a href=""> | нет | да |
| требует конфигурации на стороне сервера | нет | да |
Режим Hashbang (режим по умолчанию)
В этом режиме $location использует URL с Hashbang во всех браузерах. 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 автоматически вернётся к использованию URL с Hashbang. Это избавляет вас от необходимости беспокоиться о том, поддерживает ли браузер, отображающий ваше приложение, API истории или нет; сервис $location прозрачно использует наилучший доступный вариант.
- Открытие обычного URL в устаревшем браузере -> перенаправление на URL с Hashbang
- Открытие URL с Hashbang в современном браузере -> переписывание на обычный 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 предоставляет URL с Hashbang. Это избавляет вас от необходимости беспокоиться о том, поддерживает ли браузер, отображающий ваше приложение, 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 также может быть установлено в строку, которая позволит переписывать ссылки только для элементов якоря, у которых есть данный атрибут.
Например, если 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, указанного в качестве базового href. Это может привести к неочевидным и непонятным последствиям...
Представьте, что базовый href задан следующим образом: <base href="/base/"> (т.е. приложение находится в папке, названной /base). URL /base фактически находится вне приложения (он ссылается на файл base в корневой папке /).
Если вы хотите иметь возможность переходить к приложению по URL-адресу, такому как /base, то вы должны убедиться, что ваш сервер настроен на перенаправление таких запросов на /base/.
Дополнительную информацию см. в https://github.com/angular/angular.js/issues/14018.
Отправка ссылок между разными браузерами
Благодаря возможности переписывания в режиме HTML5, ваши пользователи смогут открывать обычные ссылки в старых браузерах и ссылки с хэштегами в современных браузерах:
- Современные браузеры будут переписывать URL-адреса с хэштегами в обычные URL-адреса.
- Старые браузеры будут перенаправлять обычные URL-адреса в URL-адреса с хэштегами.
Здесь вы можете увидеть два $location экземпляра, которые демонстрируют разницу между режимами Html5 и Html5 Fallback. Обратите внимание, что для имитации разного уровня поддержки браузеров экземпляры $location подключены к сервису fakeBrowser, который вам не нужно настраивать в реальных проектах.
Обратите внимание, что при вводе URL-адреса с хэштегами в первый браузер (или наоборот) он не переписывается/перенаправляется в обычный/хэштег 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). Это означает, что вы сами должны вызвать 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–2018 Google, Inc.
Licensed under the Creative Commons Attribution License 4.0.
https://code.angularjs.org/1.7.8/docs/guide/$location