Я ищу некоторые рекомендации, которые можно использовать, чтобы помочь определить, какой тип области использовать при написании новой директивы. В идеале мне бы хотелось что-то похожее на блок-схему, которая проведет меня через кучу вопросов и выдаст правильный ответ - без новой новой области, новой дочерней области или новой изолированной области - но это, вероятно, требует слишком многого. Вот мой текущий мизерный набор рекомендаций:
- Не используйте изолированную область видимости, если элемент, который будет использовать директиву, использует ng-модель.
См. Можно ли использовать ng-модель с изолированной областью действия? и
почему форматеры не работают с изолированной областью? - Если директива не изменяет свойства области / модели, не создавайте новую область
- Области изолята, кажется, работают хорошо, если директива инкапсулирует набор элементов DOM ( документация говорит «сложная структура DOM»), и директива будет использоваться как элемент, или без каких-либо других директив для того же элемента.
Мне известно, что использование директивы с изолированной областью действия для элемента заставляет все другие директивы в том же элементе использовать одну и ту же (одну) изолированную область действия, так что, не может ли это серьезно ограничить возможность использования изолированной области действия?
Я надеюсь, что некоторые из команды Angular-UI (или другие, которые написали много директив) могут поделиться своим опытом.
Пожалуйста, не добавляйте ответ, который просто говорит: «используйте изолированную область для повторно используемых компонентов».
источник
scope: true
создаст дочернюю область$scope.new()
автоматически.scope: false
(по умолчанию, без новой области видимости),scope: true
(новая область видимости, которая наследуется по прототипу) иscope: { ... }
(новая область выделения).Ответы:
Какой замечательный вопрос! Я люблю , чтобы услышать то , что говорят другие, но вот принципы , которые я использую.
Высотная предпосылка: scope используется как «клей», который мы используем для связи между родительским контроллером, директивой и шаблоном директивы.
Родительская Область:
scope: false
так что никакой новой области вообще нетЯ использую это не очень часто, но, как сказал @MarkRajcok, если директива не обращается к каким-либо переменным области видимости (и, очевидно, не устанавливает их!), То, на мой взгляд, это нормально. Это также полезно для дочерних директив, которые используются только в контексте родительской директивы (хотя из этого всегда есть исключения) и у которых нет шаблона. По сути, все, что связано с шаблоном, не имеет общей области видимости, потому что вы по своей сути выставляете эту область для доступа и манипулирования (но я уверен, что есть исключения из этого правила).
В качестве примера я недавно создал директиву, которая рисует (статическую) векторную графику с использованием библиотеки SVG, которую я нахожусь в процессе написания. Он имеет
$observe
два атрибута (width
иheight
) и использует их в своих вычислениях, но не устанавливает и не читает никаких переменных области и не имеет шаблона. Это хороший вариант использования, чтобы не создавать другую область; нам не нужен, так зачем?Но в другой директиве SVG мне потребовался набор данных, который нужно было использовать, и, кроме того, я должен был хранить крошечную информацию о состоянии. В этом случае использование родительской области было бы безответственным (опять же, вообще говоря). Так что вместо ...
Детская сфера:
scope: true
Директивы с дочерней областью являются контекстно-зависимыми и предназначены для взаимодействия с текущей областью.
Очевидно, что ключевым преимуществом этого по сравнению с изолированной областью является то, что пользователь может свободно использовать интерполяцию для любых атрибутов, которые они хотят; Например, использование
class="item-type-{{item.type}}"
директивы с изолированной областью не будет работать по умолчанию, но прекрасно работает с директивой с дочерней областью, потому что все, что интерполируется, все еще может быть найдено по умолчанию в родительской области. Кроме того, сама директива может безопасно оценивать атрибуты и выражения в контексте своей собственной области, не беспокоясь о загрязнении или повреждении родительского объекта.Например, всплывающая подсказка - это то, что просто добавляется; Изолированная область не будет работать (по умолчанию, см. ниже), потому что ожидается, что здесь мы будем использовать другие директивы или интерполированные атрибуты. Подсказка - это просто улучшение. Но подсказка также должна установить некоторые вещи в области видимости, которые будут использоваться с под-директивой и / или шаблоном, и, очевидно, управлять своим собственным состоянием, так что было бы очень плохо использовать родительскую область видимости. Мы либо загрязняем его, либо повреждаем, и ни один не является буэно.
Я чаще использую детские прицелы, чем одиночные или родительские.
Изолировать область:
scope: {}
Это для многоразовых компонентов. :-)
А если серьезно, я думаю о «повторно используемых компонентах» как о «автономных компонентах». Намерение состоит в том, что они должны использоваться для определенной цели, поэтому объединение их с другими директивами или добавление других интерполированных атрибутов к узлу DOM по своей сути не имеет смысла.
Чтобы быть более конкретным, все, что необходимо для этой автономной функциональности, предоставляется через определенные атрибуты, оцениваемые в контексте родительской области; это либо односторонние строки ('@'), либо односторонние выражения ('&'), либо двусторонние привязки переменных ('=').
На автономных компонентах не имеет смысла применять другие директивы или атрибуты к нему, потому что он существует сам по себе. Его стиль регулируется собственным шаблоном (при необходимости) и может включать соответствующий контент (при необходимости). Он автономен, поэтому мы помещаем его в изолированную область также, чтобы сказать: «Не связывайтесь с этим. Я даю вам определенный API через эти несколько атрибутов».
Хорошей практикой является исключение как можно большего количества материалов на основе шаблонов из ссылки директивы и функций контроллера. Это обеспечивает другую «API-подобную» конфигурационную точку: пользователь директивы может просто заменить шаблон! Все функциональные возможности остались прежними, и его внутренний API никогда не затрагивался, но мы можем связываться со стилем и реализацией DOM столько, сколько нам нужно. UI / bootstrap - отличный пример того, как сделать это хорошо, потому что Peter & Pawel потрясающие.
Области применения изолята также отлично подходят для использования с включением. Взять вкладки; они представляют собой не только всю функциональность, но все, что находится внутри, может свободно оцениваться из родительской области, оставляя вкладки (и панели), чтобы делать все, что они хотят. Вкладки явно имеют свое собственное состояние , которое принадлежит области (для взаимодействия с шаблоном), но это состояние не имеет ничего общего с контекстом, в котором оно использовалось - оно полностью внутреннее того, что делает директиву tab директивой tab. Кроме того, нет смысла использовать какие-либо другие директивы с вкладками. Это вкладки - и мы уже получили эту функциональность!
Окружите его большей функциональностью или включите больше функциональности, но эта директива уже есть.
Из всего сказанного следует отметить, что существуют некоторые способы обойти некоторые ограничения (то есть функции) изолированной области видимости, как намекал @ProLoser в своем ответе. Например, в разделе дочерней области я упомянул интерполяцию при разрыве ненаправленных атрибутов при использовании изолированной области (по умолчанию). Но пользователь может, например, просто использовать,
class="item-type-{{$parent.item.type}}"
и это будет снова работать. Поэтому, если есть веская причина для использования изолированной области над дочерней областью, но вы беспокоитесь о некоторых из этих ограничений, знайте, что при необходимости вы можете обойти практически все из них.Резюме
Директивы без новой области видимости доступны только для чтения; им полностью доверяют (то есть, они встроены в приложение) и они не касаются гнезда. Директивы с дочерней областью добавляют функциональность, но они не единственные . Наконец, отдельные области предназначены для директив, которые являются всей целью; они автономны, так что все в порядке (и большинство «правильных»), позволяя им стать мошенниками.
Я хотел высказать свои первоначальные мысли, но, как я думаю о других вещах, я буду обновлять это. Но святое дерьмо - это долго для ТАКОГО ответа ...
PS: Абсолютно тангенциальный, но так как мы говорим о сферах, я предпочитаю говорить «прототип», тогда как другие предпочитают «прототип», который кажется более точным, но просто скатывается с языка совсем не хорошо. :-)
источник
ngInclude
. Или сделайте это как часть вашей сборки. Много вариантов!Моя личная политика и опыт:
Изолированный: частная песочница
Я хочу создать множество методов и переменных области видимости, которые используются ТОЛЬКО в моей директиве и никогда не видны и не доступны напрямую пользователю. Я хочу добавить в белый список данные о том, что мне доступно. Я могу использовать transclusion, чтобы позволить пользователю вернуться в родительскую область (без изменений) . Я НЕ хочу, чтобы мои переменные и методы были доступны для детей, прошедших заключение.
Ребенок: подраздел контента
Я хочу создать методы и области видимости переменных , которые МОГУТ быть доступны пользователю, но не имеют отношения к окружающим диапазонам (братьев , сестер и родителей) вне контекста моей директивы. Я также хотел бы, чтобы ВСЕ родительские данные области видимости просачивались прозрачно.
Нет: простые, доступные только для чтения директивы
Мне действительно не нужно связываться с методами или переменными области видимости. Я, вероятно, делаю что-то, что не связано с областями действия (например, отображение простых плагинов jQuery, проверка и т. Д.).
Ноты
ng-model=$parent.myVal
(ребенок) илиngModel: '='
(изолировать).require: '^ngModel'
можете посмотреть в родительских элементах.источник
После написания большого количества директив я решил использовать меньше
isolated
возможностей. Несмотря на то, что это круто, вы инкапсулируете данные и не пропускаете данные в родительскую область, но это сильно ограничивает количество директив, которые вы можете использовать вместе. Так,Если директива, которую вы собираетесь написать, будет вести себя совершенно сама по себе, и вы не собираетесь делиться ею с другими директивами, перейдите к изолированной области видимости . (как компонент, который вы можете просто подключить, без особых настроек для конечного разработчика) (становится очень хитрее, когда вы пытаетесь написать подэлементы, внутри которых есть директивы)
Если директива, которую вы собираетесь написать, будет просто делать доменные манипуляции, которые не нуждаются во внутреннем состоянии области видимости или явных изменениях области видимости (в основном очень простые вещи); не идти за новой областью . (таких , как
ngShow
,ngMouseHover
,ngClick
,ngRepeat
)Если директива, которую вы собираетесь написать, должна изменить некоторые элементы в родительской области, но также должна обрабатывать некоторое внутреннее состояние, перейдите к новой дочерней области . (такой как
ngController
)Обязательно ознакомьтесь с исходным кодом директив: https://github.com/angular/angular.js/tree/master/src/ng/directive.
Это очень помогает в том, как о них думать.
источник
require
, поэтому ваши директивы остаются разъединенными. Так как же это ограничивает возможности? Это еще более делает директивы более конкретными (поэтому объявляйте, от чего вы зависите). Поэтому я бы оставил только одно правило: если ваша директива имеет состояние или нуждается в каких-либо данных из области видимости, где она используется - используйте изолированную область. В противном случае не используйте область. И о «детских сферах» - я также написал довольно много директив и никогда не нуждался в этой функции. Если «необходимо изменить некоторые элементы в родительской области» - используйте привязки.$parent
хак). Так на самом деле «ребенок» прицелы для директив является то , что выглядит как следует использовать довольно сзади - какngRepeat
это создает новые дочерние прицелы для каждого элемента , чтобы повторить (но это также создает его с помощьюscope.$new();
и неscope: true
.ngClick
и т. Д.) Требование создает своего рода разделение, я согласен, но вам все равно нужно знать о родительской директиве. Если это не компонент , я против изоляции. Директивы (по крайней мере, большинство из них) предназначены для многократного использования, и изоляция нарушает это.Просто подумал, что я добавлю свое текущее понимание и как это связано с другими концепциями JS.
По умолчанию (например, не объявлено или область действия: false)
Это философски эквивалентно использованию глобальных переменных. Ваша директива может получить доступ ко всему в родительском контроллере, но она также влияет на них и затрагивается одновременно.
объем:{}
Это похоже на модуль, все, что он хочет использовать, должно быть передано явно. Если КАЖДАЯ директива, которую вы используете, является изолированной областью, это может быть эквивалентно созданию КАЖДОГО JS-файла, в котором вы пишете свой собственный модуль с большими затратами на внедрение всех зависимостей.
сфера: ребенок
Это золотая середина между глобальными переменными и явным проходом. Это похоже на цепочку прототипов javascript и просто расширяет копию родительской области видимости. Если вы создаете изолированную область и передаете каждый атрибут и функцию родительской области, это функционально эквивалентно этому.
Ключ в том, что ЛЮБУЮ директиву можно написать ЛЮБОМ способом. Различные декларации области видимости помогут вам в организации. Вы можете сделать все модулем или просто использовать все глобальные переменные и быть очень осторожным. Для простоты обслуживания предпочтительнее модулировать вашу логику на логически последовательные части. Существует баланс между открытым полем и закрытой тюрьмой. Причина, по которой это сложно, я считаю, что когда люди узнают об этом, они думают, что узнают о том, как работают директивы, но на самом деле они изучают организацию кода / логики.
Еще одна вещь, которая помогла мне понять, как работают директивы, это изучение ngInclude. ngInclude поможет вам включить html частички. Когда я впервые начал использовать директивы, я обнаружил, что вы можете использовать его опцию шаблона, чтобы уменьшить ваш код, но я на самом деле не прилагал никакой логики.
Конечно, между директивами angular и работой команды angular-ui мне еще не приходилось создавать свою собственную директиву, которая делает что-то существенное, поэтому мой взгляд на это может быть совершенно неверным.
источник
Я согласен с Умуром. Теоретически, отдельные области видимости звучат замечательно и «портативно», но при создании моего приложения с использованием нетривиальной функциональности я столкнулся с необходимостью включить несколько директив (некоторые вложенные в другие или добавление к ним атрибутов), чтобы полностью писать в моем собственный HTML, который является целью специфичного для домена языка.
В конце концов, это слишком странно - передавать каждое глобальное или разделяемое значение по цепочке с несколькими атрибутами при каждом вызове DOM директивы (как это требуется для изолированной области). Просто выглядит глупо многократно писать все это в DOM, и это кажется неэффективным, даже если это общие объекты. Это также излишне усложняет декларации директивы. Обходной путь использования $ parent для «достижения» и получения значений из директивы HTML выглядит как очень плохая форма.
Я также закончил тем, что изменил свое приложение, чтобы иметь в основном дочерние директивы области видимости с очень небольшим количеством изолятов - только те, которым не требуется доступ НИЧЕГО от родителя, кроме тех, которые они могут быть переданы через простые неповторяющиеся атрибуты.
Я десятилетиями мечтал о мечте о предметно-ориентированных языках до того, как это произошло, я воодушевлен тем, что AngularJS предоставляет эту опцию, и я знаю, что, поскольку в этой области будет работать больше разработчиков, мы увидим несколько очень интересных приложений, которые их архитекторам также легко писать, расширять и отлаживать.
- D
источник