Угловое директивное обучение
Цель обучения: Чтобы лучше понять использование директивы ng.
Директива может быть одной из самых сложных вещей в AngularJS. Обычно мы понимаем это как команду. AngularJS поставляется со многими предустановленными директивами, такими как ng-app и ng-controller. Можно обнаружить, что все директивы, которые поставляются с AngularJS, возглавляются ng-.
Итак, что же такое Директива? Мое личное понимание таково: инкапсулировать фрагмент html и js вместе, чтобы сформировать повторно используемый независимый объект с определенными функциями. Давайте подробно объясним общее использование директивы.
Общий формат определения и описание параметров директивы AnguarJS
См. код ниже:
var myDirective = angular.module('directives', []);
myDirective.directive('directiveName', function($inject) {
return {
template: '<div></div>',
replace: false,
transclude: true,
restrict: 'E',
scope: {},
controller: function($scope, $element) {
},
complie: function(tElement, tAttrs, transclude) {
return {
pre: function preLink(scope, iElement, iAttrs, controller) {
},
post: function postLink(scope, iElement, iAttrs, controller) {
}
};
},
link: function(scope, iElement, iAttrs) {
}
};
});
- Здесь объект возвращается напрямую, и объект включает в себя множество атрибутов, которые являются определениями пользовательских директив. Подробное значение будет объяснено ниже.
- описание параметра возвращаемого объекта
return {
name: '',
priority: 0,
terminal: true,
scope: {},
controller: fn,
require: fn,
restrict: '',
template: '',
templateUrl: '',
replace: '',
transclude: true,
compile: fn,
link: fn
}
Как показано выше, в возвращаемом объекте есть много атрибутов, и эта строка атрибутов используется для определения директивы.
Давайте объясним их функции один за другим.
-
name
- Указывает имя текущей области.Как правило, при объявлении используется значение по умолчанию, и нет необходимости устанавливать это свойство вручную.
-
priority
- приоритет. Когда для одного и того же элемента DOM определено несколько директив, иногда необходимо указать порядок их выполнения. Это свойство используется для сортировки перед вызовом функции компиляции директивы. Если приоритеты совпадают, то порядок выполнения неопределен (по опыту сначала выполняются те, у которых более высокие приоритеты, а те, у которых одинаковые приоритеты, связываются первыми, а затем выполняются).
-
teminal
- Последняя группа. Если установлено значение true, это означает, что текущим приоритетом будет последний набор директив, которые будут выполняться, то есть директивы с более низким приоритетом, чем эта директива, не будут выполняться. Тот же приоритет будет по-прежнему выполняться, но порядок не определен.
-
scope
-
true
- Для этой директивы будет создана новая область. Он по-прежнему создает только одну область, если для нескольких директив одного и того же элемента требуется новая область. Новые правила области не применяются к корневым шаблонам, поскольку корневые шаблоны имеют тенденцию получать новую область действия.
-
{}
- Будет создана новая, независимая область видимости.Отличие этой области от общей области видимости в том, что она не наследуется от родительской области через прототип. Это очень полезно для создания повторно используемых компонентов, которые могут эффективно предотвратить чтение или изменение данных родительской области. Эта отдельная область создает набор хэшей с набором свойств локальной области из родительской области. Эти свойства локальной области полезны для создания псевдонимов для значений в шаблонах. Локальное определение — это хэш-сопоставление набора свойств локальной области с его источником.
-
-
controller
- конструктор контроллера. Контроллер инициализируется перед этапом предварительной компоновки и позволяет совместно использовать другие директивы через требование с указанным именем. Это позволит директивам общаться друг с другом и улучшать поведение друг друга. По умолчанию контроллер внедряет следующие локальные объекты:
- $scope Область в сочетании с текущим элементом
- $element текущий элемент
- $attrs объект атрибутов текущего элемента
- $transclude функция связывания транспонирования, предварительно привязанная к текущей области
- конструктор контроллера. Контроллер инициализируется перед этапом предварительной компоновки и позволяет совместно использовать другие директивы через требование с указанным именем. Это позволит директивам общаться друг с другом и улучшать поведение друг друга. По умолчанию контроллер внедряет следующие локальные объекты:
-
require
- Запросите другой контроллер и передайте его в функцию связывания текущей директивы. require требует передачи имени директивного контроллера. Если контроллер с таким именем не найден, будет выдана ошибка. Имя может иметь следующий префикс:
- • Не выбрасывать исключения. Это сделает эту зависимость необязательной
- ^ позволяет найти контроллер родительского элемента
- Запросите другой контроллер и передайте его в функцию связывания текущей директивы. require требует передачи имени директивного контроллера. Если контроллер с таким именем не найден, будет выдана ошибка. Имя может иметь следующий префикс:
-
restrict
- Строка, являющаяся подмножеством EACM, которое ограничивает директиву указанным методом объявления. Если опущено, директива будет разрешать объявления только через атрибуты.
- Имя элемента Е:
- Имя свойства:
- Имя класса C:
- М Примечания:
- Строка, являющаяся подмножеством EACM, которое ограничивает директиву указанным методом объявления. Если опущено, директива будет разрешать объявления только через атрибуты.
-
template
- Если replace имеет значение true, содержимое шаблона будет заменено текущим html-элементом, а атрибуты и класс исходного элемента будут переданы вместе; если replace равно false, элемент шаблона будет рассматриваться как дочерний элемент текущего элемента. .
-
templateUrl
- В основном то же самое, что и шаблон, но шаблон загружается по указанному URL-адресу. Поскольку загрузка шаблона является асинхронной, вся компиляция и компоновка будут приостановлены и выполнены после завершения загрузки.
-
replace
- Если установлено значение true, шаблон заменит текущий элемент, а не добавит его в качестве дочернего элемента. (При значении true шаблон должен иметь корневой узел)
-
transclude
- Скомпилируйте содержимое элемента, чтобы его можно было использовать в директиве. Его нужно использовать с ngTransclude в шаблоне. Преимущество включения состоит в том, что функция связывания может получить функцию включения, предварительно связанную с текущей областью действия. В общем, для создания виджета и создания независимой области включение является не дочерним элементом, а родственным элементом независимой области. Это заставит виджет иметь приватное состояние, а включение будет привязано к родительской области. (Я не понял приведенный выше абзац. Но в реальном эксперименте, если вы вызываете myDirective и для параметра transclude установлено значение true или строка, и она включена в шаблон, результат компиляции будет вставлен в содержимое некоторого тега. Если любой из Если содержимое не обернуто тегом, то результат sometag будет иметь дополнительный диапазон. Если есть что-то еще обернутое, оно останется как есть. Но если для transclude установлено значение «элемент», все содержимое any появится в каком-то теге и завернут в p)
-
true/false
Преобразуйте содержимое этой директивы. (В этом смысле контент напрямую компилируется и перемещается в указанное место) -
‘element’
Преобразование всего элемента, включая другие директивы с более низким приоритетом. (Например, скомпилировав весь контент, обработать его как единое целое (обернув p снаружи) и вставить в указанное место)
-
- Скомпилируйте содержимое элемента, чтобы его можно было использовать в директиве. Его нужно использовать с ngTransclude в шаблоне. Преимущество включения состоит в том, что функция связывания может получить функцию включения, предварительно связанную с текущей областью действия. В общем, для создания виджета и создания независимой области включение является не дочерним элементом, а родственным элементом независимой области. Это заставит виджет иметь приватное состояние, а включение будет привязано к родительской области. (Я не понял приведенный выше абзац. Но в реальном эксперименте, если вы вызываете myDirective и для параметра transclude установлено значение true или строка, и она включена в шаблон, результат компиляции будет вставлен в содержимое некоторого тега. Если любой из Если содержимое не обернуто тегом, то результат sometag будет иметь дополнительный диапазон. Если есть что-то еще обернутое, оно останется как есть. Но если для transclude установлено значение «элемент», все содержимое any появится в каком-то теге и завернут в p)
-
compile
- Вот функция компиляции, которая будет подробно объяснена в следующем примере.
-
link
- Вот функция ссылки, которая будет подробно объяснена в следующем примере. Это свойство используется только в том случае, если свойство компиляции не определено.
О сфере
这里关于directive的scope为一个object时,有更多的内容非常有必要说明一下。 См. код ниже:
scope: {
name: '=',
age: '=',
sex: '@',
say: '&'
}
В конфигурации различных свойств в этой области есть несколько странных префиксных символов, таких как =, @ и &, так что же конкретно означают эти символы? Посмотрите еще раз на следующий код:
- html
<div my-directive name="myName" age="myAge" sex="male" say="say()"></div>
- javascript
function Controller($scope) {
$scope.name = 'Pajjket';
$scope.age = 99;
$scope.sex = '我是男的';
$scope.say = function() {
alert('Hello,我是弹出消息');
};
}
Видно, что примерные значения нескольких префиксов-модификаторов:
-
=
: значением атрибута в инструкции является значение атрибута в соответствующем $scope в контроллере. -
@
: значение в инструкции является буквальным/прямым значением в html -
&
: значение в инструкции — это свойство соответствующей $scope в контроллере, но это свойство должно быть обратным вызовом функции. Вот более официальное объяснение: -
=
или=expression/attr
Настройте двустороннюю привязку между свойством локальной области и свойством родительской области. Если имя атрибута не указано, локальное имя будет соответствовать имени атрибута.
-
Например: , область действия, определенная виджетом: {localModel: '=myAttr'}, тогда localName в свойстве области виджета будет отображать parentModel родительской области. Если parentModel что-то меняет, то меняется и localModel, и наоборот. Это двусторонняя привязка.
-
@ или @attr Создайте привязку свойства локальной области к свойству DOM. Поскольку значение свойства всегда имеет тип String, это значение всегда возвращает строку. Если имя атрибута не указано через @attr, локальное имя будет соответствовать имени атрибута DOM. Например: , область виджета определяется как: {localName: '@myAttr'}. Затем localName свойства области виджета будет сопоставлено с преобразованным реальным значением «hello». При изменении значения атрибута name соответственно изменится и атрибут localName области действия виджета (только в одну сторону, в отличие от = выше). Затем свойство читается в родительской области (а не в области компонента)
-
&или&атрибут Предоставляет способ выполнения выражения в контексте родительской области. Если имя атрибута не указано, локальное имя будет таким же, как имя атрибута.
- Например:
<widget my-attr="count = count + value">
, область действия виджета определяется как: {localFn:'increment()'}, тогда свойство изоляции области видимости localFn будет указывать на функцию, обертывающую выражение increment().
Как правило, мы хотим передавать данные из изолированной области в родительскую область через выражение. Это можно сделать, передав карту ключ-значение локальной переменной в функцию-оболочку выражения. Например, если выражение представляет собой приращение (сумма), то мы можем вызвать localFn, чтобы указать значение суммы, вызвав localFn ({сумма: 22}).
Объяснение примера директивы
Следующие примеры разработаны на основе описаний параметров, сделанных выше.
- экземпляр объявления директивы
// 自定义directive
var myDirective = angular.modeule('directives', []);
myDirective.directive('myTest', function() {
return {
restrict: 'EMAC',
require: '^ngModel',
scope: {
ngModel: '='
},
template: '<div><h4>Weather for {{ngModel}}</h4</div>'
};
});
// 定义controller
var myControllers = angular.module('controllers', []);
myControllers.controller('testController', [
'$scope',
function($scope) {
$scope.name = 'this is directive1';
}
]);
var app = angular.module('testApp', [
'directives',
'controllers'
]);
<body ng-app="testApp">
<div ng-controller="testController">
<input type="text" ng-model="city" placeholder="Enter a city" />
<my-test ng-model="city" ></my-test>
<span my-test="exp" ng-model="city"></span>
<span ng-model="city"></span>
</div>
</body>
Разница и связь между шаблоном и templateUrl
На самом деле, templateUrl имеет ту же функцию, что и корневой шаблон, за исключением того, что templateUrl загружает html-файл. В приведенном выше примере мы также можем найти проблему. Корнем позади шаблона является тег html. Если тегов много, будет некомфортнее. Вы можете изменить шаблон в приведенном выше примере.
myDirective.directive('myTest', function() {
return {
restrict: 'EMAC',
require: '^ngModel',
scope: {
ngModel: '='
},
templateUrl:'../partials/tem1.html' //tem1.html中的内容就是上例中template的内容。
}
});
переопределение области действия
//directives.js中定义myAttr
myDirectives.directive('myAttr', function() {
return {
restrict: 'E',
scope: {
customerInfo: '=info'
},
template: 'Name: {{customerInfo.name}} Address: {{customerInfo.address}}<br>' +
'Name: {{vojta.name}} Address: {{vojta.address}}'
};
});
//controller.js中定义attrtest
myControllers.controller('attrtest',['$scope',
function($scope) {
$scope.naomi = {
name: 'Naomi',
address: '1600 Amphitheatre'
};
$scope.vojta = {
name: 'Vojta',
address: '3456 Somewhere Else'
};
}
]);
// html中
<body ng-app="testApp">
<div ng-controller="attrtest">
<my-attr info="naomi"></my-attr>
</div>
</body>
Результаты его работы следующие:
Name: Naomi Address: 1600 Amphitheatre //有值,因为customerInfo定义过的
Name: Address: //没值 ,因为scope重定义后,vojta是没有定义的
Мы просто меняем вышеуказанную директиву,
myDirectives.directive('myAttr', function() {
return {
restrict: 'E',
template: 'Name: {{customerInfo.name}} Address: {{customerInfo.address}}<br>' +
'Name: {{vojta.name}} Address: {{vojta.address}}'
};
});
- Результаты приведены ниже:
Name: Address:
Name: Vojta Address: 3456 Somewhere Else
Поскольку директива в настоящее время не определяет отдельную область, customerInfo не определено, поэтому результат прямо противоположен приведенному выше.
Использование слова трансклюд
- Использование transclude немного похоже на функцию $().html() в jquery.
myDirective.directive('myEvent', function() {
return {
restrict: 'E',
transclude: true,
scope: {
'close': '$onClick' //根html中的on-click="hideDialog()"有关联关系
},
templateUrl: '../partials/event_part.html'
};
});
myController.controller('eventTest', [
'$scope',
'$timeout',
function($scope, $timeout) {
$scope.name = 'Tobias';
$scope.hideDialog = function() {
$scope.dialogIsHidden = true;
$timeout(function() {
$scope.dialogIsHidden = false;
}, 2000);
};
}
]);
<body ng-app="phonecatApp">
<div ng-controller="eventtest">
<my-event ng-hide="dialogIsHidden" on-click="hideDialog()">
Check out the contents, {{name}}!
</my-event>
</div>
</body>
<!--event_part.html -->
<div>
<a href ng-click="close()">×</a>
<div ng-transclude></div>
</div>
- Описание: окончательная структура этого html должна быть следующей:
<body ng-app="phonecatApp">
<div ng-controller="eventtest">
<div ng-hide="dialogIsHidden" on-click="hideDialog()">
<span>Check out the contents, {{name}}!</span>
</div>
</div>
</body>
- Вставьте элементы в исходный элемент html. Проверьте содержимое, !, в шаблоне., ВдобавокЭтикетка.
controller
,link
,compile
Отношение между
myDirective.directive('exampleDirective', function() {
return {
restrict: 'E',
template: '<p>Hello {{number}}!</p>',
controller: function($scope, $element){
$scope.number = $scope.number + "22222 ";
},
link: function(scope, el, attr) {
scope.number = scope.number + "33333 ";
},
compile: function(element, attributes) {
return {
pre: function preLink(scope, element, attributes) {
scope.number = scope.number + "44444 ";
},
post: function postLink(scope, element, attributes) {
scope.number = scope.number + "55555 ";
}
};
}
}
});
//controller.js添加
myController.controller('directive2',[
'$scope',
function($scope) {
$scope.number = '1111 ';
}
]);
//html
<body ng-app="testApp">
<div ng-controller="directive2">
<example-directive></example-directive>
</div>
</body>
- Результат запуска приведенного выше небольшого примера выглядит следующим образом:
Hello 1111 22222 44444 5555 !
Из результатов видно, что сначала запускается контроллер, потом компилируется, а ссылка не запускается. Теперь, когда мы закомментировали свойство compile, мы получаем следующие результаты:
Hello 1111 22222 33333
!
Из результатов видно, что сначала запускается контроллер, потом запускается ссылка, а ссылка и компиляция несовместимы. Как правило, компиляция имеет более высокий приоритет, чем ссылка.
Ссылаться на
- blog
- Официальный сайт
- sf
- угловой курс