it-swarm.com.ru

Как написать директиву в AngularJS, как мне решить, не нужна ли мне новая область, новая дочерняя область или новая изолированная область?

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

Мне известно, что использование директивы с изолированной областью действия для элемента заставляет все другие директивы в том же элементе использовать одну и ту же (одну) изолированную область действия, так что, не может ли это серьезно ограничить возможность использования изолированной области действия?

Я надеюсь, что некоторые из команды Angular-UI (или другие, которые написали много директив) могут поделиться своим опытом.

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

265
Mark Rajcok

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

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

Родительская область:scope: false, так что никакой новой области вообще нет

Я использую это не очень часто, но, как сказал @MarkRajcok, если директива не обращается к каким-либо переменным области видимости (и, очевидно, не устанавливает их!), То, на мой взгляд, это нормально. Это также полезно для дочерних директив, которые only используются в контексте родительской директивы (хотя из этого всегда есть исключения) и которые не имеют шаблона. По сути, все, что связано с шаблоном, не имеет общей области видимости, потому что вы по своей сути выставляете эту область для доступа и манипулирования (но я уверен, что есть исключения из этого правила).

В качестве примера я недавно создал директиву, которая рисует (статическую) векторную графику с использованием библиотеки SVG, которую я нахожусь в процессе написания. Он $observes два атрибута (width и height) и использует их в своих вычислениях, но он не устанавливает и не читает никакие переменные области и не имеет шаблона. Это хороший вариант использования, чтобы не создавать другую область; нам это не нужно, так зачем?

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

Child Scope:scope: true

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

Очевидно, что ключевым преимуществом этого по сравнению с изолированной областью является то, что пользователь может свободно использовать интерполяцию для любых атрибутов, которые они хотят; например использование class="item-type-{{item.type}}" в директиве с изолированной областью не будет работать по умолчанию, но прекрасно работает на директиве с дочерней областью, потому что все, что интерполировано, все еще по умолчанию можно найти в родительской области. Кроме того, сама директива может безопасно оценивать атрибуты и выражения в контексте своей собственной области, не беспокоясь о загрязнении или повреждении родительского объекта.

Например, всплывающая подсказка - это то, что просто добавляется; Изолированная область не будет работать (по умолчанию, см. ниже), потому что ожидается, что здесь мы будем использовать другие директивы или интерполированные атрибуты. Подсказка - это просто улучшение. Но всплывающая подсказка также должна установить некоторые вещи в области действия для использования с под-директивой и/или шаблоном и, очевидно, для управления своим собственным состоянием, так что было бы действительно плохо использовать родительскую область действия. Мы либо загрязняем его, либо наносим ущерб, и ни один не является буэно.

Я чаще использую детские прицелы, чем одиночные или родительские.

Изолировать область действия:scope: {}

Это для многоразовых компонентов. :-)

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

Чтобы быть более конкретным, все, что необходимо для этой автономной функциональности, предоставляется через определенные атрибуты, оцениваемые в контексте родительской области; это либо односторонние строки ('@'), либо односторонние выражения ('&'), либо двусторонние привязки переменных ('=').

На автономные компоненты не имеет смысла применять другие директивы или атрибуты, потому что он существует сам по себе. Его стиль регулируется собственным шаблоном (при необходимости) и может включать соответствующий контент (при необходимости). Он автономен, поэтому мы помещаем его в изолированную область также, чтобы сказать: "Не связывайтесь с этим. Я даю вам определенный API через эти несколько атрибутов".

Хорошей практикой является исключение как можно большего количества материалов на основе шаблонов из ссылки директивы и функций контроллера. Это обеспечивает другую "API-подобную" конфигурационную точку: пользователь директивы может просто заменить шаблон! Все функциональные возможности остались прежними, и его внутренний API никогда не затрагивался, но мы можем связываться со стилем и реализацией DOM столько, сколько нам нужно. ui/bootstrap - это отличный пример того, как сделать это хорошо, потому что Питер и Павел потрясающие.

Области применения изолятов также отлично подходят для использования с включением. Взять вкладки; они представляют собой не только всю функциональность, но все, что является внутри этой функцией, можно свободно оценить изнутри родительской области, оставляя вкладки (и панели), чтобы делать все, что они хотят. Вкладки явно имеют свой собственный state, который принадлежит области (для взаимодействия с шаблоном), но это состояние не имеет ничего общего с контекстом, в котором оно использовалось - оно полностью внутреннее для того, что делает директива табуляции директива табуляции. Кроме того, не имеет смысла использовать какие-либо другие директивы с вкладками. Это вкладки - и мы уже получили эту функциональность!

Окружите его большей функциональностью или включите больше функциональности, но эта директива уже есть.

Из всего сказанного следует отметить, что существуют некоторые способы обойти некоторые ограничения (то есть особенности) изолированной области видимости, как намекал @ProLoser в своем ответе. Например, в разделе дочерней области я упомянул интерполяцию при разрыве ненаправленных атрибутов при использовании изолированной области (по умолчанию). Но пользователь может, например, просто использовать class="item-type-{{$parent.item.type}}", и он снова будет работать. Поэтому, если есть веская причина использовать изолированную область над дочерней областью, но вы беспокоитесь о некоторых из этих ограничений, знайте, что при необходимости вы можете обойти практически все из них.

Summary

Директивы без новой области видимости доступны только для чтения; им полностью доверяют (то есть внутри приложения) и они не касаются гнезда. Директивы с дочерней областью действия add, но они не являются единственной функциональностью. Наконец, отдельные области действия предназначены для директив, которые являются всей целью; они автономны, так что можно (и наиболее "правильно") отпустить их изгоев.

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


PS: Абсолютно тангенциальный, но поскольку мы говорим о сферах, я предпочитаю говорить "прототип", тогда как другие предпочитают "прототип", который кажется более точным, но просто скатывается с языка совсем не хорошо. :-)

289
Josh David Miller

Моя личная политика и опыт:

Изолированный: личная песочница

Я хочу создать множество методов и переменных области видимости, которые используются ТОЛЬКО в моей директиве и никогда не видны и не доступны напрямую пользователю. Я хочу добавить в белый список данные о том, что мне доступно. Я могу использовать transclusion, чтобы позволить пользователю вернуться в родительскую область (без изменений). Я НЕ хочу, чтобы мои переменные и методы были доступны для включенных детей.

Ребенок: подраздел контента

Я хочу создать методы и переменные области видимости, которые МОГУТ доступны для пользователя, но не имеют отношения к окружающим областям (родным братьям и родителям) вне контекста моей директивы. Я также хотел бы, чтобы ВСЕ родительские данные области видимости просачивались прозрачно.

Нет: простые директивы только для чтения

Мне действительно не нужно связываться с методами или переменными области видимости. Я, вероятно, делаю что-то, что не связано с областями действия (например, отображение простых плагинов jQuery, проверка и т.д.).

Заметки

  • Вы не должны позволять ngModel или другим вещам напрямую влиять на ваше решение. Вы можете обойти странное поведение, используя такие вещи, как ng-model=$parent.myVal (дочерний) или ngModel: '=' (изолировать).
  • Isolate + transclude восстановит все нормальное поведение в директивах одного уровня и вернет родительскую область видимости, поэтому не позволяйте этому влиять на ваше суждение.
  • Не связывайтесь с областью действия none, потому что это похоже на размещение данных в области видимости для нижней половины DOM, но не для верхней половины, что имеет смысл 0.
  • Обратите внимание на приоритеты директив (не приводите конкретных примеров того, как это может повлиять на ситуацию)
  • Внедрить сервисы или использовать контроллеры для связи через директивы с любым типом области Вы также можете сделать require: '^ngModel', чтобы посмотреть в родительских элементах.
52
ProLoser

После написания большого количества директив я решил использовать меньше isolated scope. Несмотря на то, что это круто, вы инкапсулируете данные и не пропускаете данные в родительскую область, но это серьезно ограничивает количество директив, которые вы можете использовать вместе. Так,

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

Если директива, которую вы собираетесь написать, собирается просто делать dom-манипуляции, для которых не требуется внутреннее состояние области видимости или явные изменения области видимости (в основном очень простые вещи); перейти на нет новой области . (например, ngShow, ngMouseHover, ngClick, ngRepeat)

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

Обязательно ознакомьтесь с исходным кодом директив: https://github.com/angular/angular.js/tree/master/src/ng/directive
Это очень помогает о том, как думать о них

18
Umur Kontacı

Просто подумал, что я добавлю свое текущее понимание и как это связано с другими концепциями JS.

По умолчанию (например, не объявлено или область действия: false)

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

Объем: {}

Это похоже на модуль, все, что он хочет использовать, должно быть передано явно. Если КАЖДАЯ директива, которую вы используете, является изолированной областью, это может быть эквивалентно созданию КАЖДОГО JS-файла, в котором вы пишете свой собственный модуль с большим количеством накладных расходов для внедрения всех зависимостей.

область действия: дочерний

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


Ключ в том, что ЛЮБУЮ директиву можно написать ЛЮБЫМ способом. Различные декларации области видимости помогут вам в организации. Вы можете сделать все модулем или просто использовать все глобальные переменные и быть очень осторожным. Для простоты обслуживания, хотя предпочтительно модулировать вашу логику на логически последовательные части. Существует баланс между открытым лугом и закрытой тюрьмой. Причина, по которой это сложно, я считаю, что когда люди узнают об этом, они думают, что узнают о том, как работают директивы, но на самом деле они изучают организацию кода/логики.

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

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

9
user2483724

Я согласен с Умуром. Теоретически, изолированные области видимости прекрасны и "переносимы", но при создании моего приложения для использования нетривиальной функциональности я столкнулся с необходимостью включить несколько директив (некоторые вложенные в другие или добавление к ним атрибутов), чтобы полностью писать в моем собственный HTML, который является целью специфичного для домена языка.

В конце концов, это слишком странно - передавать каждое глобальное или общее значение по цепочке с несколькими атрибутами при каждом вызове DOM директивы (как это требуется для изолированной области). Просто выглядит глупо многократно записывать все это в DOM, и это кажется неэффективным, даже если это общие объекты. Это также излишне усложняет декларации директивы. Обходной путь использования $ parent для "охвата" и получения значений из директивы HTML выглядит как очень плохая форма.

Я также закончил тем, что изменил свое приложение, чтобы иметь в основном дочерние директивы области видимости с очень небольшим количеством изолятов - только те, которым не требуется доступ НИЧЕГО от родителя, кроме того, что они могут быть переданы через простые неповторяющиеся атрибуты.

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

- D

2
Ungallery