Как nginx обрабатывает запросы
Как предотвратить обработку запросов без имени сервера Определение виртуального сервера по имени и IP-адресу Конфигурация простого сайта PHP |
Определение виртуального сервера по имени
nginx вначале решает, какой из серверов должен обработать запрос. Рассмотрим простую конфигурацию, где все три виртуальных сервера слушают на порту *:80:
server { listen 80; server_name example.org www.example.org; ... } server { listen 80; server_name example.net www.example.net; ... } server { listen 80; server_name example.com www.example.com; ... }
В этой конфигурации, чтобы определить, какому серверу следует направить
запрос, nginx проверяет только поле “Host” заголовка запроса.
Если его значение не соответствует ни одному из имён серверов
или в заголовке запроса нет этого поля вовсе,
nginx направит запрос в сервер по умолчанию для этого порта. В вышеприведённой конфигурации сервером по умолчанию будет первый сервер,
что соответствует стандартному поведению nginx по умолчанию.
Сервер по умолчанию можно задать явно с помощью параметра
default_server
в директиве
listen:server { listen 80 default_server; server_name example.net www.example.net; ... }
Параметрdefault_server
появился в версии 0.8.21. В более ранних версиях вместо него следует использовать параметрdefault
.
Следует иметь в виду, что сервер по умолчанию является свойством слушающего порта, а не имени сервера. Подробнее это обсуждается ниже.
Как предотвратить обработку запросов без имени сервера
Если запросы без поля “Host” в заголовке не должны обрабатываться, можно определить сервер, который будет их отклонять:
server { listen 80; server_name ""; return 444; }
Здесь в качестве имени сервера указана пустая строка, которая
соответствует запросам без поля “Host” в заголовке,
и возвращается специальный для nginx код 444, который закрывает
соединение.
Начиная с версии 0.8.48 настройка server_name ""
является стандартной и может явно не указываться.
В более ранних версиях в качестве стандартного имени сервера
выступало имя машины (hostname).
Определение виртуального сервера по имени и IP-адресу
Рассмотрим более сложную конфигурацию, в которой некоторые виртуальные серверы слушают на разных адресах:
server { listen 192.168.1.1:80; server_name example.org www.example.org; ... } server { listen 192.168.1.1:80; server_name example.net www.example.net; ... } server { listen 192.168.1.2:80; server_name example.com www.example.com; ... }
В этой конфигурации nginx вначале сопоставляет IP-адрес и порт
запроса с директивами
listen
в блоках
server.
Затем он сопоставляет значение поля “Host”
заголовка запроса с директивами
server_name
в блоках
server,
которые соответствуют IP-адресу и порту.
www.example.com
, пришедший на порт
192.168.1.1:80, будет обработан сервером по умолчанию для порта
192.168.1.1:80, т.е. первым сервером, т.к. для этого порта www.example.com
не указан в списке имён серверов.Как уже говорилось, сервер по умолчанию является свойством слушающего порта, поэтому у разных портов могут быть определены свои серверы по умолчанию:
server { listen 192.168.1.1:80; server_name example.org www.example.org; ... } server { listen 192.168.1.1:80 default_server; server_name example.net www.example.net; ... } server { listen 192.168.1.2:80 default_server; server_name example.com www.example.com; ... }
Конфигурация простого сайта PHP
Теперь посмотрим на то, как nginx выбирает location для обработки запроса на примере обычного простого PHP-сайта:
server { listen 80; server_name example.org www.example.org; root /data/www; location / { index index.html index.php; } location ~* \.(gif|jpg|png)$ { expires 30d; } location ~ \.php$ { fastcgi_pass localhost:9000; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } }
nginx вначале ищет среди всех префиксных location’ов, заданных строками,
максимально совпадающий.
В вышеприведённой конфигурации
указан только один префиксный location “/
”, и поскольку
он подходит под любой запрос, он и будет использован, если других
совпадений не будет найдено.
Затем nginx проверяет location’ы, заданные регулярными выражениями, в
порядке их следования в конфигурационном файле.
При первом же совпадении поиск прекращается и nginx использует
совпавший location.
Если запросу не соответствует ни одно из регулярных выражений,
nginx использует максимально совпавший префиксный location,
найденный ранее.
Следует иметь в виду, что location’ы всех типов сопоставляются только с URI-частью строки запроса без аргументов. Так делается потому, что аргументы в строке запроса могут быть заданы различными способами, например:
/index.php?user=john&page=1 /index.php?page=1&user=john
Кроме того, в строке запроса можно запросить что угодно:
/index.php?page=1&something+else&user=john
Теперь посмотрим, как бы обрабатывались запросы в вышеприведённой конфигурации:
- Запросу “
/logo.gif
” во-первых соответствует префиксный location “/
”, а во-вторых — регулярное выражение “\.(gif|jpg|png)$
”, поэтому он обрабатывается location’ом регулярного выражения. Согласно директиве “root /data/www
” запрос отображается в файл/data/www/logo.gif
, который и посылается клиенту. - Запросу “
/index.php
” также во-первых соответствует префиксный location “/
”, а во-вторых — регулярное выражение “\.
”. Следовательно, он обрабатывается location’ом регулярного выражения и запрос передаётся FastCGI-серверу, слушающему на localhost:9000. Директива fastcgi_param устанавливает FastCGI-параметр(php)$
SCRIPT_FILENAME
в “/data/www/index.php
”, и сервер FastCGI выполняет указанный файл. Переменная
равна значению директивы root, а переменная $document_root$fastcgi_script_name
равна URI запроса, т.е. “/index.php
”. - Запросу “
/about.html
” соответствует только префиксный location “/
”, поэтому запрос обрабатывается в нём. Согласно директиве “root /data/www
” запрос отображается в файл/data/www/about.html
, который и посылается клиенту. - Обработка запроса “
/
” более сложная. Ему соответствует только префиксный location “/
”, поэтому запрос обрабатывается в нём. Затем директива index проверяет существование индексных файлов согласно своих параметров и директиве “root /data/www
”.Если файл
/data/www/index.html
не существует, а файл/data/www/index.php
существует, то директива делает внутреннее перенаправление на “/index.php
” и nginx снова сопоставляет его с location’ами, как если бы такой запрос был послан клиентом. Как мы видели ранее, перенаправленный запрос будет в конечном итоге обработан сервером FastCGI.
автор: Игорь Сысоев редактор: Brian Mercer |
Имена сервера
Имена с масками Имена, заданные регулярными выражениями Прочие имена Интернационализованные имена Выбор виртуального сервера Оптимизация Совместимость |
Имена сервера задаются с помощью директивы server_name и определяют, в каком блоке server будет обрабатываться тот или иной запрос. См. также “Как nginx обрабатывает запросы”. Имена могут быть заданы точно, с помощью маски или регулярного выражения:
server { listen 80; server_name example.(www\.)?(
?<domain>.+)$; location / { root /sites/$domain; } }
Библиотека PCRE поддерживает именованные выделения, используя следующий синтаксис:
Если nginx отказывается запускаться и выдаёт сообщение об ошибке:
?<
name
>Совместимый с Perl 5.10 синтаксис, поддерживается начиная с PCRE-7.0 ?'
name
'Совместимый с Perl 5.10 синтаксис, поддерживается начиная с PCRE-7.0 ?P<
name
>Python-совместимый синтаксис, поддерживается начиная с PCRE-4.0
pcre_compile() failed: unrecognized character after (?< in ...
то это значит, что используется старая версия библиотеки PCRE и следует
вместо этого попробовать синтаксис
“?P<
”.name
>
Однако такое использование должно ограничиваться простыми случаями как в примере выше, поскольку нумерованные выделения легко могут быть перезаписаны.
Прочие имена
Некоторые имена имеют специальное значение.
Если необходимо обрабатывать запросы без поля “Host” в заголовке в блоке server, который не является сервером по умолчанию, следует указать пустое имя:
server { listen 80; server_name example.org www.example.org ""; ... }
Если директива server_name не задана в блоке server, то nginx будет использовать пустое имя в качестве имени сервера.
Версии nginx вплоть до 0.8.48 в этом случае использовали имя хоста (hostname) машины в качестве имени сервера.
Если имя сервера задано как “$hostname

Если в запросе вместо имени сервера указан IP-адрес, то поле “Host” заголовка запроса будет содержать IP-адрес, и запрос можно обработать, используя IP-адрес как имя сервера:
server { listen 80; server_name example.org www.example.org "" 192.168.1.1 ; ... }
В примерах конфигурации серверов, обрабатывающих все запросы, встречается
странное имя “_
”:
server { listen 80 default_server; server_name _; return 444; }
Оно не является каким-то особенным, это просто одно из множества
некорректных доменных имён, которые никогда не пересекутся ни с одним из
реальных имён.
С тем же успехом можно использовать имена типа “--
”
и “!@#
”.
Версии nginx вплоть до 0.6.25 поддерживали специальное имя
“*
”, которое многими неверно воспринималось как
имя сервера для обработки всех запросов. Оно никогда так не работало, и не работало как имя с маской.
Это имя действовало так же, как сейчас действует директива
server_name_in_redirect.
Специальное имя “
*
” объявлено устаревшим, а вместо него
следует использовать директиву
server_name_in_redirect.
Заметьте, что с помощью директивы
server_name
нельзя задать ни имя сервера для обработки всех запросов,
ни сервер по умолчанию.
Это является свойством директивы
listen,
а не
server_name.
См. также “Как nginx обрабатывает запросы”.
Можно настроить серверы, слушающие на портах *:80 и *:8080,
и указать, что один из них будет сервером по умолчанию для порта *:8080,
а другой — для порта *:80:
server { listen 80; listen 8080 default_server; server_name example.net; ... } server { listen 80 default_server; listen 8080; server_name example.org; ... }
Интернационализованные имена
Для указания интернационализированных доменных имён (IDNs) в директиве server_name следует указывать Punycode-представление имени:
server { listen 80; server_name xn--e1afmkfd.xn--80akhbyknj4f; # пример.испытание ... }
Выбор виртуального сервера
Сначала соединение создаётся в контесте сервера по умолчанию. Затем имя сервера может быть определено на следующих стадиях обработки запроса, каждая из которых участвует в выборе конфигурации:
предварительно во время операции SSL handshake согласно SNI
после обработки строки запроса
после обработки поля
Host
заголовка запросаесли после обработки строки запроса или поля
Host
заголовка запроса имя сервера не было выбрано, то nginx будет использовать пустое имя в качестве имени сервера.
На каждой из этих стадий могут применяться различные конфигурации сервера. Таким образом, некоторые директивы следует указывать с осторожностью:
- в случае использования
директивы ssl_protocols
список протоколов задаётся библиотекой OpenSSL
перед применением конфигурации сервера согласно имени,
запрашиваемого через SNI.
Таким образом, протоколы должны быть заданы только для сервера по умолчанию;
- директивы client_header_buffer_size и merge_slashes задействуются перед чтением строки запроса, таким образом они используют конфигурацию сервера по умолчанию или конфигурацию сервера, выбранного через SNI;
- в случае использования директив
ignore_invalid_headers,
large_client_header_buffers
и
underscores_in_headers,
которые участвуют в обработке полей заголовка запроса,
выбор сервера дополнительно зависит от того,
была ли обновлена конфигурация сервера
согласно строке запроса или полю заголовка
Host
; - ошибочный ответ будет обработан с помощью директивы error_page в том сервере, который в настоящий момент выполняет запрос.
Оптимизация
Точные имена, имена с масками, начинающиеся со звёздочки,
и имена с масками, заканчивающиеся на звёздочку, хранятся
в трёх хэш-таблицах, привязанных к слушающим портам.
Размеры хэш-таблиц оптимизируются на фазе конфигурации таким образом,
что имя может быть найдено с минимальным числом непопаданий в кэш процессора. Подробнее настройка хэш-таблиц обсуждается в отдельном
документе.
В первую очередь имя ищется в хэш-таблице точных имён. Если имя не было найдено, то имя ищется в хэш-таблице имён с масками, начинающихся со звёздочки. Если и там поиск не дал результата, то имя ищется в хэш-таблице имён с масками, оканчивающихся на звёздочку.
Поиск в хэш-таблице имён с масками медленнее, чем поиск в хэш-таблице точных
имён, поскольку имена сравниваются по доменным частям.
Заметьте, что специальное имя с маской вида “.example.org
”
хранится в хэш-таблице имён с масками, а не в хэш-таблице точных имён.
Регулярные выражения проверяются последовательно, а значит являются самым медленным и плохо масштабируемым методом.
По вышеизложенным причинам предпочтительнее использовать точные имена,
где это только возможно.
Например, если к серверу наиболее часто обращаются по именам example.org
и www.example.org
,
то эффективнее будет указать их явно:
server { listen 80; server_name example.org www.example.org *.example.org; ... }
нежели чем использовать упрощённую форму:
server { listen 80; server_name .example.org; ... }
Если задано большое число имён серверов, либо заданы необычно
длинные имена, возможно потребуется скорректировать значения директив
server_names_hash_max_size
и server_names_hash_bucket_size
на уровне http.
Значение по умолчанию директивы
server_names_hash_bucket_size
может быть равно 32, 64, либо другой величине,
в зависимости от размера строки кэша процессора.
Если значение по умолчанию равно 32 и имя сервера задано как
“too.long.server.name.example.org
”,
то nginx откажется запускаться и выдаст сообщение об ошибке:
could not build the server_names_hash, you should increase server_names_hash_bucket_size: 32
В этом случае следует увеличить значение директивы до следующей степени двойки:
http { server_names_hash_bucket_size 64; ...
Если задано большое число имён серверов, то будет выдано другое сообщение об ошибке:
could not build the server_names_hash, you should increase either server_names_hash_max_size: 512 or server_names_hash_bucket_size: 32
В таком случае сначала следует попробовать установить server_names_hash_max_size в величину, близкую к числу имён серверов, и только если это не поможет или время запуска nginx станет неприемлемо большим, следует попытаться увеличить server_names_hash_bucket_size.
Если сервер является единственным сервером для слушающего порта, то nginx не будет проверять имена сервера вообще (а также не будет строить хэш-таблицы для слушающего порта). За одним исключением: если имя сервера задано регулярным выражением с выделениями, то nginx’у придётся выполнить это выражение, чтобы получить значения выделений.
Совместимость
- Специальное имя сервера “
$hostname
” поддерживается начиная с версии 0.9.4.
- Имя сервера по умолчанию является пустой строкой “” начиная с версии 0.8.48.
- Именованные выделения в именах серверов, заданных с помощью регулярных выражений, поддерживаются начиная с версии 0.8.25.
- Выделения в именах серверов, заданных с помощью регулярных выражений, поддерживаются начиная с версии 0.7.40.
- Пустое имя сервера “” поддерживается начиная с версии 0.7.12.
- В качестве первого имени сервера можно задать маску или регулярное выражение начиная с версии 0.6.25.
- Регулярные выражения в имени сервера поддерживаются начиная с версии 0.6.7.
- Имена с маской вида
example.*
поддерживаются начиная с версии 0.6.0. - Специальная форма имени вида
.example.org
поддерживается начиная с версии 0.3.18. - Имена с маской вида
*.example.org
поддерживаются начиная с версии 0.1.13.
автор: Игорь Сысоев редактор: Brian Mercer |
angular — что такое host свойство в директивах и как узнать подробности
спросил
Изменено 3 года, 7 месяцев назад
Просмотрено 9к раз
Привет, я использую angular 8 с ng-bootstrap для добавления таблицы в свой проект
Я нашел этот код, который я не очень хорошо понял
@Директива({ селектор: 'th[сортируемый]', хозяин: { '[класс.asc]': 'направление === "asc"', '[class.desc]': 'direction === "desc"', '(щелкнуть)': 'повернуть()' } })
кто-нибудь может сказать мне, что говорит код?
и что означает «th» в селекторе.
также хост, могу ли я изменить его на что-то другое, потому что редактор сказал, что это старое свойство или что?
Всем спасибо
- угловой
- угловой8
Согласно документации Angular:
селектор
Селектор: Селектор CSS, который идентифицирует эту директиву в шаблоне и запускает создание экземпляра директивы.
Итак, в вашем коде селектор: 'th[sortable]' селектор
объявляет выбор по имени элемента th
с атрибутом [sortable]
. Вы должны найти что-то вроде ...
в вашем html-файле.
ОБНОВЛЕНИЕ для ответа на комментарий :
Согласно ссылке, опубликованной в комментарии, вот -й сортируемый
в html-коде:
хост
Хост: Сопоставляет свойства класса с привязками элементов хоста для свойств, атрибутов и событий, используя набор пар ключ-значение.
хост: { [ключ: строка]: строка; }
Предпочтительно использовать @HostBinding
и @HostListener
вместо host
в соответствии с руководством по стилю angular, перейдите по этой ссылке для получения более подробной информации.
Чтобы заменить хост
в вашем коде:
@HostBinding
позволяет установить свойства элемента или компонента, в котором размещена директива. Таким образом, он заменит ваш код [class.asc]
и [class.desc]
следующим внутри вашей директивы :
@HostBinding('class.asc') direction = 'asc'; @HostBinding('class.desc') direction = 'desc';
@HostListener
позволяет прослушивать события в элементе или компоненте хоста. Итак, ваш '(клик)' 9Код 0038 будет заменен следующим кодом внутри вашей директивы :
@HostListener('click') rotate() {
// делать:
}
1 Во-первых, вы должны понять, в чем разница между директивой и компонентом .
В отличие от компонентов директивы не требуют представления. Они должны отвечать за логику рендеринга: добавление
/ удаление
элементов и/или добавление пользовательского поведения к элементам или компонентам DOM.
th[sortable]
— думайте об этом как о обычном CSS-селекторе
. Это будет преобразовано в: Элемент th
с атрибутом sortable
:
.
Если бы селектор был разделен запятыми ( th,[sortable]
), это означало бы, что вы либо используете свою директиву как th
, либо
или <сортируемый>
.
Свойство хоста
, как указано в документации
Сопоставляет свойства класса с привязками элементов хоста для свойств, атрибутов и событий, используя набор пар ключ-значение.
, где хост-элемент
— это элемент/компонент, к которому вы прикрепили свою директиву.
Однако вы можете добиться тех же результатов, используя HostBinding
и HostListener
.
Имея это в виду, ваш код может выглядеть так:
@Directive({ ... })
класс экспорта YourAwesomeDirective {
@HostBinding('класс.asc')
получить ascClass () {
вернуть this.direction === 'asc';
}
@HostBinding('класс.desc')
получить descClass () {
вернуть this.direction === 'описание';
}
@HostListener('щелчок', '[$event]')
onClick (ev) { /* ... */ }
}
Зарегистрируйтесь или войдите в систему
Зарегистрируйтесь с помощью Google Зарегистрироваться через Facebook Зарегистрируйтесь, используя электронную почту и пароль Опубликовать как гость
Электронная почта Обязательно, но не отображается
Опубликовать как гость
Электронная почта Требуется, но не отображается
Нажимая «Опубликовать свой ответ», вы соглашаетесь с нашими условиями обслуживания и подтверждаете, что прочитали и поняли нашу политику конфиденциальности и кодекс поведения.
Состав директивы Angular — эксперты Angular
Angular 15 уже на горизонте, а вместе с ним и множество замечательных функций. Одна из них, которая меня невероятно волнует, — это директивная композиция.
И не только я. Состав директив был одним из самых популярных вопросов Angular на GitHub. Давайте посмотрим, что это такое.
Чтобы объяснить состав директив, мы рассмотрим реальный вариант использования в виде цифровой доски объявлений. Мы хотим реализовать пинборд, который отображает булавки. Каждый пин должен отображать информационный текст в виде всплывающей подсказки при наведении. Кроме того, каждый штифт можно перетаскивать и первоначально вращать.
Цифровая доска с контактами Код такого приложения может выглядеть примерно так.
<пинборд>
У нас есть PinboardComponent
, и мы проецируем на него кучу выводов.
На этом этапе наши выводы будут отображаться, как показано на рисунке вверху. Это означает, что они еще не повернуты изначально, их нельзя перетаскивать, и мы не будем отображать всплывающую подсказку. Все функции, упомянутые выше, отсутствуют.
Конечно, мы могли бы реализовать эти функции прямо в компоненте булавки. Но, к счастью, наша кодовая база уже содержит несколько удобных директив с желаемой функциональностью.
В нашем распоряжении есть DragableDirective
, RotateDirective
и TooltipDirective
. Давайте используем эти директивы атрибутов, чтобы добавить недостающие функции к нашим булавкам.
<пинборд #dragZone>
<булавка
повернуть = "45 градусов"
tooltip="Отправлять новые продукты"
перетаскиваемый
[dragzone]="пинборд"
изображение = "ракета"
>
<булавка
повернуть = "-20 градусов"
tooltip="Хорошее пиво после дня программирования"
перетаскиваемый
[dragzone]="пинборд"
изображение = "пиво"
>
<булавка
повернуть = "0 градусов"
tooltip="Моя любимая клавиатура, Moonlander"
перетаскиваемый
[dragzone]="пинборд"
изображение = "клавиатура"
>
<булавка
повернуть = "10 градусов"
tooltip="Создайте тесты для улучшения кода"
перетаскиваемый
[dragzone]="пинборд"
изображение = "тестирование"
>
<булавка
повернуть = "25 градусов"
tooltip="Нет кофе, нет кода"
перетаскиваемый
[dragzone]="пинборд"
изображение = "кофе"
>
Каждый штифт теперь применяет директиву атрибута rotate
и передает заданные начальные градусы поворота.
Затем есть директива атрибута tooltip
с текстом всплывающей подсказки и, что не менее важно, перетаскиваемый атрибут
с дополнительным вводом dragZone
.
Зона перетаскивания необходима, потому что вы хотите иметь возможность перетаскивать только контакты внутри доски.
Ницца. Это хороший подход, но он имеет некоторые недостатки.
Для завершения функции PinComponent
; разработчик должен помнить, какие директивы нужны, и применять все директивы самостоятельно.
Было бы здорово, если бы мы могли предоставить PinComponent
функции перетаскивания, всплывающей подсказки и поворота прямо из коробки и при этом повторно использовать наши директивы?
Зачем нужна композиция директив? До сих пор мы могли повторно использовать наши директивы в наших компонентах, используя наследование.
Например, чтобы получить возможность перетаскивания, мы могли бы расширить наши PinComponent
.
класс экспорта PinComponent расширяет реализацию DragableDirective OnInit {}
Приятно то, что, используя наследование, мы можем наследовать все функции Angular, такие как HostBinding
или HostListeners
и т. д.…. И это также очень хорошо работает с проверкой типов шаблонов и минификаторами.
Но у этого подхода есть свои ограничения. Как насчет всплывающей подсказки
и функции поворота
? Мы можем расширить только один класс, верно?
Кроме того, у нас нет возможности сузить общедоступный API PinComponent
. Публичный API директив просачивается в производные классы.
Это не оптимальное решение, поэтому сейчас мы получаем композицию директив.
Подпишитесь на меня в Твиттере, потому что вы будете получать уведомления о новых сообщениях в блоге Angular и интересных материалах внешнего интерфейса!😉
Состав директив
Новый API составления директив представляет hostDirectives
в декораторе компонентов и директив.
Значением свойства является массив объектов конфигурации. Каждый объект конфигурации содержит обязательный атрибут директивы и два необязательных свойства , ввод
и , вывод
.
hostDirectives?: (Тип <неизвестно> | {
директива: Тип<неизвестно>;
входы?: строка [];
выходы?: строка [];
})[];
Давайте продолжим и попробуем использовать это совершенно новое свойство в нашем PinComponent
, чтобы добавить всплывающую подсказку, поворот и функции перетаскивания.
@Компонент({
селектор: 'булавка',
шаблон: `
`,
директивы хоста: [
{директива: TooltipDirective},
{директива: DragableDirective},
{директива: RotateDirective},
],
})
класс экспорта PinComponent реализует OnInit {}
С помощью этого мы также можем удалить директиву атрибута draggable
из контактов в нашем HTML.
<штифт
повернуть = "25 градусов"
tooltip="Нет кофе, нет кода"
[dragzone]="пинборд"
изображение = "кофе"
>
Если бы нам не нужно было передавать всплывающую подсказку и вращать ввод , мы могли бы также удалить эти атрибуты, поскольку теперь они предоставляются hostDirectives
на PinComponent
. Но нам по-прежнему нужны эти атрибуты, а также атрибут dragzone
, потому что эти атрибуты являются входными данными.
Давайте запустим наше приложение. Вместо отличных фич получаем кучу ошибок компиляции:
ERROR
src/app/pin.component.ts:20:17 - ошибка NG2014:
Директива хоста TooltipDirective должна быть автономной 20
{директива: TooltipDirective}
Что ж, это понятное сообщение об ошибке, которое информирует нас об одном из ограничений директив хоста.
Директивы хоста можно использовать только с автономными директивами. Без проблем. Давайте продолжим и преобразуем наши директивы в автономные директивы.
Автономный режим, что это? Автономные компоненты были представлены в качестве предварительного просмотра для разработчиков в Angular 14. Если вы хотите узнать больше об этом, ознакомьтесь с моей статьей об автономных компонентах. Отдельные компоненты Angular
Чтобы преобразовать наши директивы в автономные директивы, мы должны добавить свойство standalone
со значением true
в декораторе директив и переместить их из массива объявлений в массив импортов в AppModule
.
Отлично, попробуем!
Состояние наведения PinComponent со сломанной всплывающей подсказкой. Директива всплывающей подсказки выполняется, но текст всплывающей подсказки не определен. Всплывающая подсказка ломается при наведении, значок не поворачивается, а булавку нельзя перетаскивать. Почему это? Похоже, что ввод директив больше не работает. Но почему? мы по-прежнему передаем их в HTML как атрибуты компонента булавки!
Всякий раз, когда вы используете hostDirectives, все входы и выходы по умолчанию скрыты. Мы явно должны предоставить общедоступный API для входов
и выходов
объектов конфигурации.
директивы хоста: [
{ директива: TooltipDirective, входы: ['tooltip'] },
{директива: DragableDirective, входы: ['dragzone'] },
{директива: RotateDirective, входы: ['rotate'] },
];
Это отличная функция, поскольку она дает нам полный контроль над общедоступным API нашего компонента.
Запустим наш код.
Повернутый и наведенный PinComponent отображает текст всплывающей подсказки и может быть изменен с помощью перетаскивания. Отлично, мы получаем всплывающую подсказку при наведении, мы получаем вращение, и, конечно же, пины можно перетаскивать. Все функции вроде работают. Как насчет выводит свойство
?
Точно так же, как мы настроили наши входы, мы также можем настроить наши выходы. Наш DragableDirective
, например, генерирует событие, которое уведомляет вас, когда вы захватываете пин. Мы можем использовать свойство outputs, чтобы включить событие pinGrabbed
в нашем общедоступном API.
директивы хоста: [
{ директива: TooltipDirective, входы: ['tooltip'] },
{
директива: DragableDirective,
входы: ['зона перетаскивания'],
выходы: ['pinGrabbed'],
},
{директива: RotateDirective, входы: ['rotate'] },
];
Довольно интересно, правда? Но это не все; есть даже больше.
Псевдонимы
Еще одна полезная функция композиции директив — псевдонимы входных и выходных данных. dragzone
— довольно общее название для нашего входа. В контексте пинов было бы точнее назвать Вход pinBoard
вместо dragzone
.
Воспользуемся синтаксисом псевдонима для переименования свойства dragzone
в DragableDirective
.
директивы хоста: [
// ...
{
директива: DragableDirective,
входы: ['dragzone: pinBoard'],
выходы: ['pinGrabbed'],
},
// ...
];
Отлично. После присвоения псевдонима мы можем использовать вход pinBoard
на выводе.
<штифт
повернуть = "0 градусов"
tooltip="Моя любимая клавиатура, Moonlander"
[pinBoard]="доска"
изображение = "клавиатура"
(pinGrabbed)="pinGrabbed()"
>
Псевдоним работает точно так же для выходов
.
Сводка Композиция директив — это уникальная и захватывающая функция, предлагающая следующие преимущества.
Мы можем применить к хосту столько директив, сколько захотим. Ограничений нет.
По умолчанию все Входы
и Выходы
скрыты. Мы можем использовать свойства inputs
и outputs
, чтобы включить их в наш общедоступный API и сделать их видимыми.
Состав директив работает с проверкой типа шаблона.
Все функции директив, такие как HostBinding
, маркеры внедрения и т.