Улучшить эту документациюДекораторы в AngularJS
ПРИМЕЧАНИЕ: Это руководство предназначено для разработчиков, уже знакомых с основами AngularJS. Если вы только начинаете, мы рекомендуем сначала ознакомиться с руководством по началу работы.Что такое декораторы?
Декораторы — это паттерн проектирования, используемый для разделения модификации или декорирования класса без изменения исходного кода. В AngularJS декораторы — это функции, которые позволяют изменять сервис, директиву или фильтр перед их использованием.
Как использовать декораторы
Существует два способа регистрации декораторов
-
$provide.decorator, и module.decorator
Каждый предоставляет доступ к $delegate, который представляет собой экземпляр сервиса/директивы/фильтра, перед тем, как его передать сервису, который его потребовал.
$provide.decorator
Функция декоратора позволяет получить доступ к $delegate сервиса после его создания. Например:
angular.module('myApp', [])
.config([ '$provide', function($provide) {
$provide.decorator('$log', [
'$delegate',
function $logDecorator($delegate) {
var originalWarn = $delegate.warn;
$delegate.warn = function decoratedWarn(msg) {
msg = 'Decorated Warn: ' + msg;
originalWarn.apply($delegate, arguments);
};
return $delegate;
}
]);
}]);
После создания сервиса $log декоратор срабатывает. Функция декоратора получает объект $delegate, чтобы предоставить доступ к сервису, который соответствует селектору в декораторе. Этот $delegate будет сервисом, который вы декорируете. Возвращаемое значение функции предоставленной декоратору заменит декорируемый сервис, директиву или фильтр.
Этот $delegate может быть изменён или полностью заменён. Учитывая сервис myService с методом someFn, следующие решения могут быть жизнеспособными:
Полная замена $delegate
angular.module('myApp', [])
.config([ '$provide', function($provide) {
$provide.decorator('myService', [
'$delegate',
function myServiceDecorator($delegate) {
var myDecoratedService = {
// new service object to replace myService
};
return myDecoratedService;
}
]);
}]);
Изменение $delegate
angular.module('myApp', [])
.config([ '$provide', function($provide) {
$provide.decorator('myService', [
'$delegate',
function myServiceDecorator($delegate) {
var someFn = $delegate.someFn;
function aNewFn() {
// new service function
someFn.apply($delegate, arguments);
}
$delegate.someFn = aNewFn;
return $delegate;
}
]);
}]);
Расширение $delegate
angular.module('myApp', [])
.config([ '$provide', function($provide) {
$provide.decorator('myService', [
'$delegate',
function myServiceDecorator($delegate) {
function helperFn() {
// an additional fn to add to the service
}
$delegate.aHelpfulAddition = helperFn;
return $delegate;
}
]);
}]);
Декораторы имеют разные правила для различных сервисов. Это связано с тем, что сервисы регистрируются по-разному. Сервисы выбираются по имени, однако фильтры и директивы выбираются путём добавления "Filter" или "Directive" в конец имени. $delegate определяется типом сервиса.
| Тип сервиса | Селектор | $delegate |
|---|---|---|
| Сервис | serviceName | Значение, возвращаемое сервисом object или function |
| Директива | directiveName + 'Directive' | Экземпляр Array.<DirectiveObject>1
|
| Фильтр | filterName + 'Filter' | Значение, возвращаемое фильтром function |
1. Может быть зарегистрировано несколько директив с одним и тем же селектором/именем
$delegate сервиса. Необходимо не только сохранять ожидаемое поведение для потребителей, но и учитывать, что некоторые функции (например, регистрация директив) не происходят после декорации, а во время создания/регистрации исходного сервиса. Это означает, например, что действие, такое как добавление объекта директивы в массив $delegate директив, скорее всего, приведёт к неожиданному поведению. Кроме того, следует проявлять особую осторожность при декорировании основных сервисов, директив или фильтров, так как это может неожиданно или негативно повлиять на функциональность фреймворка. module.decorator
Эта функция аналогична функции $provide.decorator, но доступна через API модуля. Это позволяет отделить декоративные паттерны от блоков конфигурации модулей.
Как и в случае с $provide.decorator, функция module.decorator выполняется во время фазы конфигурации приложения. Это означает, что вы можете определить module.decorator до определения декорируемого сервиса.
Поскольку вы можете применять несколько декораторов, важно отметить, что применение декораторов всегда происходит в порядке объявления:
- Если сервис декорируется как
$provide.decorator, так иmodule.decorator, декораторы применяются в указанном порядке:
angular
.module('theApp', [])
.factory('theFactory', theFactoryFn)
.config(function($provide) {
$provide.decorator('theFactory', provideDecoratorFn); // runs first
})
.decorator('theFactory', moduleDecoratorFn); // runs seconds
- Если сервис был объявлен несколько раз, декоратор будет декорировать последний объявленный сервис:
angular
.module('theApp', [])
.factory('theFactory', theFactoryFn)
.decorator('theFactory', moduleDecoratorFn)
.factory('theFactory', theOtherFactoryFn);
// `theOtherFactoryFn` is selected as 'theFactory' provider and it is decorated via `moduleDecoratorFn`.
Примеры применения
В следующих разделах представлены примеры декоратора сервиса, декоратора директивы и декоратора фильтра.
В этом примере показано, как мы можем заменить сервис $log своим собственным для отображения сообщений об ошибках.
Пропущенные интерполированные выражения в атрибутах ng-href могут легко остаться незамеченными. Мы можем декорировать ngHref чтобы предупреждать нас об этих случаях.
Предположим, что мы создали приложение, которое использует стандартный формат для многих наших фильтров Date. Внезапно требования изменились (что случается нечасто), и нам нужно, чтобы все наши стандартные даты были отформатированы как 'shortDate', а не как 'mediumDate'.
© 2010–2018 Google, Inc.
Licensed under the Creative Commons Attribution License 4.0.
https://code.angularjs.org/1.7.8/docs/guide/decorators