Unlimited WordPress themes, graphics, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. Angular
Code

Освоение директив AngularJS

by
Difficulty:IntermediateLength:LongLanguages:

Russian (Pусский) translation by Ilya Nikov (you can also view the original English article)

Директивы являются одним из самых мощных компонентов AngularJS, помогая вам расширять основные элементы/атрибуты HTML и создавать многоразовые и тестируемые компоненты. В этом уроке я покажу вам, как использовать директивы AngularJS с лучшими практиками из реальной жизни.

То, что я имею в виду здесь во время учебника под директивам, - это в основном пользовательские директивы. Я не буду пытаться научить вас, как использовать встроенные директивы, такие как ng-repeat, ng-show и т.д. Я покажу вам, как использовать пользовательские директивы для создания ваших собственных компонентов.

План

  1. Простые директивы
  2. Ограничения директивы
  3. Изолированная область видимости
  4. Области видимости директив
  5. Наследование директивы
  6. Отладка директивы
  7. Тестирование директивы
  8. Тестирование области видимости
  9. Вывод

1. Простые директивы

Скажем, у вас есть приложение электронной коммерции о книгах, и вы показываете конкретные детали книги в нескольких областях, таких как комментарии, страницы профиля пользователя, статьи и т.д. Виджет вашей книги может выглядеть следующим образом:

Book Widget

В этом виджете есть изображение книги, название, описание, комментарии и рейтинг. Сбор этой информации и включение определенного элемента dom могут быть трудными в каждом месте, которое вы хотите использовать. Давайте превратим это представление в виджет, используя директиву AngularJS.

В приведенном выше примере функция directive была использована для создания директивы. Название директивы - book. Эта директива возвращает объект, и давайте немного поговорим об этом объекте. restrict - это определение типа директивы, и оно может быть A (Attribute), C (class), E (Element) и M (coMment). Вы можете видеть использование каждого из них соответственно ниже.

Тип Применение
A <div book> </ div>
С <div class="book"> </ div>
Е <book data="book_data"></book>
M <! - directive:book ->

scope предназначена для управления областью действия директивы. В приведенном выше случае данные книги передаются в шаблон директивы с использованием типа области «=». В следующих разделах я подробно расскажу о области применения. templateUrl используется для вызова представления для рендеринга определенного контента с использованием данных, переданных в область действия директивы. Вы также можете использовать template и предоставить HTML-код напрямую, например:

В нашем случае у нас сложная структура HTML, и именно поэтому я выбрал параметр templateUrl.

2. Ограничения директивы

Директивы определены в файле JavaScript вашего проекта AngularJS и используются на странице HTML. Можно использовать директивы AngularJS на HTML-страницах следующим образом:

A (Attribute)

В этом использовании имя директивы используется внутри стандартных элементов HTML. Скажем, у вас есть ролевое меню в вашем приложении электронной коммерции. Это меню сформировано в соответствии с вашей текущей ролью. Вы можете определить директиву, чтобы определить, должно ли отображаться текущее меню или нет. Ваше меню HTML может выглядеть следующим образом:

а директива следующим образом:

Если вы используете restricted директиву в элементе меню в качестве атрибута, вы можете выполнить проверку уровня доступа для каждого меню. Если текущий пользователь не авторизовался, это конкретное меню не будет отображаться.

Итак, что это за функция link? Все просто, функция link - это функция, которую вы можете использовать для выполнения операций, ориентированных на конкретные действия. Директива не только дает некоторый HTML-код, предоставляя некоторые входы. Вы также можете связывать функции с элементом директивы, вызывать службу и обновлять значение директивы, получать директивные атрибуты, если это директива типа E и т.д.

C (Class)

Вы можете использовать имя директивы внутри классов элемента HTML. Предполагая, что вы будете использовать указанную выше директиву как C, вы можете обновить restrict директивы как C и использовать ее следующим образом:

У каждого элемента уже есть класс для стилизации, и по мере добавления класса restricted он фактически является директивой.

E (Element)

Вам не нужно использовать директиву внутри элемента HTML. Вы можете создать свой собственный элемент, используя директиву AngularJS с ограничением E. Предположим, что у вас есть пользовательский виджет в вашем приложении, чтобы показывать в нескольких местах вашего приложения username, avatar и reputation. Вы можете использовать такую директиву:

Код HTML будет следующим:

В приведенном выше примере создается пользовательский элемент, и некоторые атрибуты предоставляются как username, avatar и reputation. Я хочу обратить внимание на тело функции link. Атрибуты элемента присваиваются области действия. Первым параметром функции связи является область действия текущей директивы. Третьим параметром директивы является объект атрибута директивы, а это означает, что вы можете прочитать любой атрибут из пользовательской директивы, используя attrs.attr_name. Значения атрибутов присваиваются области действия, поэтому они используются внутри шаблона.

Фактически, вы можете сделать эту операцию короче, и я расскажу об этом позже. Этот пример предназначен для понимания основной идеи использования.

M (coMment)

Это использование не очень распространено, но я покажу, как его использовать. Допустим, вам нужна форма комментариев для вашего приложения для использования ее во многих местах. Вы можете сделать это, используя следующую директиву:

И в элементе HTML:

3. Изолированная область действия

Каждая директива имеет свою собственную область действия, но вам нужно быть осторожным с привязкой данных к объявлению директивы. Скажем, что вы реализуете часть basket своего приложения для электронной коммерции. На странице корзины у вас есть элементы, уже добавленные здесь раньше. Каждый предмет имеет поле количества, чтобы выбрать, сколько предметов вы хотите купить, например:

Simple Cart

Вот объявление директивы:

И для отображения трех элементов в HTML:

Проблема здесь в том, что всякий раз, когда вы выберете количество требуемого элемента, все разделы количества элементов будут обновлены. Почему? Потому что есть двусторонняя привязка данных с именем count, но область не изолирована. Чтобы выделить область действия, просто добавьте scope: {} в атрибут директивы в разделе return:

Это приведет к тому, что ваша директива будет иметь свою собственную изолированную область, поэтому двусторонняя привязка данных будет происходить внутри этой директивы отдельно. Я также расскажу об атрибуте scope чуть позже.

4. Области директив

Основным преимуществом директивы является то, что это многоразовый компонент, который можно использовать легко - вы даже можете предоставить некоторые дополнительные атрибуты этой директивы. Но как можно передать дополнительное значение, привязку или выражение в директиву, чтобы данные могли использоваться внутри директивы?

"@" Scope: этот тип области используется для передачи значения в область действия директивы. Предположим, что вы хотите создать виджет для уведомления:

И вы можете использовать:

В этом примере значение сообщения просто присваивается области действия директивы. Отображаемый HTML-контент будет выглядеть следующим образом:

"=" Scope: В этом типе области переменные области пропускаются вместо значений, что означает, что мы не будем передавать {{message}}, вместо этого мы передадим message. Причиной этой функции является создание двусторонней привязки данных между директивой и элементами страницы или контроллерами. Давайте посмотрим на это в действии.

В этой директиве мы пытаемся создать виджет для отображения ввода текста комментария, чтобы сделать комментарий для конкретной книги. Как вы можете видеть, эта директива требует, чтобы один атрибут text создавал двустороннюю привязку данных между другими элементами на страницах. Вы можете использовать это на странице:

Это просто покажет текстовое поле на странице, поэтому давайте добавим что-то большее, чтобы взаимодействовать с этой директивой:

Всякий раз, когда вы вводите текст в первом текстовом поле, он также вводится во втором текстовом поле. Вы можете сделать это наоборот. В директиве мы передали переменную scope commentText вместо значения, и эта переменная является ссылкой на привязку данных к первому текстовому полю.

"&" Scope: мы можем передать значение и ссылку. В этом виде области мы рассмотрим, как передать выражения в директиву. В реальных случаях вам может потребоваться передать определенную функцию (выражение) в директивы, чтобы предотвратить соединение. Иногда директивам не нужно много знать о идее, лежащей в основе выражений. Например, директива понравится вам, но она не знает, как это сделать. Для этого вы можете следовать такой структуре:

В этой директиве выражение будет передано кнопке директивы через атрибут like. Давайте определим функцию в контроллере и передадим ее в директиву внутри HTML.

Это будет внутри контроллера, и шаблон будет следующий:

likeFunction() поступает из контроллера и передается в директиву. Что делать, если вы хотите передать параметр в likeFunction()? Например, вам может потребоваться передать значение рейтинга для likeFunction(). Это очень просто: просто добавьте аргумент функции внутри контроллера и добавьте элемент ввода в директиву, чтобы потребовать начальный счет от пользователя. Вы можете сделать это, как показано ниже:

Как вы можете видеть, текстовое поле поступает из директивы. Значение текстового поля привязано к аргументу функции, как например like({star: starCount}). star - для функции контроллера, а starCount - для привязки значения текстового поля.

5. Наследование директивы

Иногда у вас может быть функция, которая существует в нескольких директивах. Они могут быть помещены в родительскую директиву, чтобы они были унаследованы дочерними директивами.

Позвольте мне привести пример из реальной жизни. Вы хотите отправлять статистические данные всякий раз, когда клиенты перемещают курсор мыши в начало конкретной книги. Вы можете реализовать событие щелчка мыши для директивы книги, но что, если она будет использоваться другой директивой? В этом случае вы можете использовать наследование директив, как показано ниже:

Это родительская директива, которая наследуется дочерними директивами. Как вы видите, есть атрибут контроллера директивы, использующий директиву «as». Давайте также определим этот контроллер:

В этом контроллере мы просто устанавливаем экземпляр контроллера переменной bookType с помощью дочерних директив. Всякий раз, когда вы нажимаете на книгу или журнал, тип элемента будет отправлен во внутреннюю службу (я использовал функцию alert только для отображения данных). Как дочерние директивы смогут использовать эту директиву?

Как вы можете видеть, дочерние директивы используют ключевое слово require для использования родительской директивы. И еще один важный момент - это четвертый аргумент функции ссылки в дочерних директивах. Этот аргумент относится к атрибуту контроллера родительской директивы, который означает, что дочерняя директива может использовать функцию контроллера setBookType внутри контроллера. Если текущий элемент является eBook, вы можете использовать первую директиву, и если это журнал, вы можете использовать второй:

Дочерние директивы - это как свойство родительской директивы. Мы исключили использование события щелчка мыши для каждой дочерней директивы, поместив этот раздел в родительскую директиву.

6. Отладка директивы

Когда вы используете директивы внутри шаблона, то, что вы видите на странице, является скомпилированной версией директивы. Иногда вы хотите увидеть фактическое использование директивы для целей отладки. Чтобы увидеть несжатую версию текущего раздела, вы можете использовать ng-non-bindable. Например, допустим, у вас есть виджет, который печатает самые популярные книги, и вот код для этого:

Переменная области видимости книги исходит от контроллера, а вывод этого выглядит следующим образом:

Если вы хотите узнать использование директивы за этим скомпилированным выводом, вы можете использовать эту версию кода:

На этот раз вывод будет выглядеть следующим образом:

Это здорово, но что, если мы хотим увидеть как некомпилированные, так и скомпилированные версии виджета? Настало время написать настраиваемую директиву, которая будет выполнять расширенную операцию отладки.

В этой директиве мы клонируем элемент, который находится в режиме отладки, так что он не изменяется после некоторого набора операций. После клонирования удалите директиву custom-debug, чтобы не действовать как режим отладки, а затем скомпилируйте его с помощью $complile, который уже встроен в директиве. Мы выделили стиль для элемента режима отладки, чтобы подчеркнуть его. Окончательный результат будет следующим:

Sample Directive

Вы можете сэкономить время разработки, используя эту директиву отладки, чтобы обнаружить основную причину любой ошибки в вашем проекте.

7. Тестирование директив

Как вы уже знаете, модульное тестирование является очень важной частью разработки, чтобы полностью контролировать написанный код и предотвращать возможные ошибки. Я не буду глубоко погружаться в модульное тестирование, но расскажу вам о том, как тестировать директивы несколькими способами.

Я буду использовать Jasmine для модульного тестирования и Karma для тестировщика модулей. Чтобы использовать Karma, просто установите его глобально, запустив npm install -g karma karma-cli (на вашем компьютере должны быть установлены Node.js и npm). После установки откройте командную строку, перейдите в корневую папку проекта и введите karma init. Он задаст вам пару вопросов, как показано ниже, чтобы настроить свои тестовые требования.

Karma Test Initialization

Я использую Webstorm для разработки, и если вы также используете Webstorm, просто щелкните правой кнопкой мыши по karma.conf.js и выберите «Запустить karma.conf.js». Это выполнит все тесты, настроенные в конфиге karma. Вы также можете запускать тесты с помощью командной строки karma start в корневой папке проекта. Это все о настройке среды, поэтому давайте перейдем к тестовой части.

Предположим, что мы хотим проверить директиву книги. Когда мы передаем заголовок в директиву, он должен быть скомпилирован в детальное представление книги. Итак, давайте начнем.

В вышеприведенном тесте мы тестируем новую директиву booktest. Эта директива принимает аргумент title и создает div, используя этот заголовок. В тесте перед каждым тестовым разделом мы сначала вызываем наш модуль masteringAngularJsDirectives. Затем мы создаем директиву booktest. На каждом этапе тестирования будет протестирован вывод директивы. Этот тест предназначен только для проверки значения.

8. Тестирование области действия директивы

В этом разделе мы проверим область видимости директивы booktest. Эта директива генерирует подробное представление книги на странице, и когда вы нажимаете этот раздел сведений, переменная области видимости, называемая viewed, будет установлена как true. В нашем тесте мы проверим, установлено ли viewed в true, когда событие click активировано. Директива:

Чтобы установить событие в элемент в AngularJS внутри директивы, вы можете использовать атрибут link. Внутри этого атрибута у вас есть текущий элемент, непосредственно связанный с событием клика. Чтобы проверить эту директиву, вы можете использовать следующее:

В тестовом разделе событие click запускается с помощью element.triggerHandler("click"). Когда запускается событие клика, переменная viewed должна быть установлена как true. Это значение проверяется с помощью expect(element.isolateScope().viewed).toBe(true).

9. Заключение

Для разработки модульных и тестируемых веб-проектов AngularJS является лучшим выбором. Директивы являются одним из лучших компонентов AngularJS, и это означает, что чем больше вы знаете о директивах AngularJS, тем более модульные и тестируемые проекты вы можете разработать.

В этом уроке я попытался показать вам лучшие практические рекомендации в отношении директив, и имейте в виду, что вам нужно много практики, чтобы понять логику директив. Надеюсь, эта статья поможет вам хорошо понять директивы AngularJS.

Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.