31
Июл
2019

Создание директив

Довольно часто при разработке Angular приложения приходится создавать пользовательские директивы (Angular custom directive).

Angular директивы атрибуты

Создание самой простой директивы атрибута ограничивается классом, обернутым декоратором @Directive() с заданием необходимой конфигурации.zoom.directive.ts (version 1)


    @Directive({
     selector: '[zoom]'
    })
    export class ZoomDirective{}
    

Квадратные скобки являются указателем того, что это именно директива атрибут.

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

Для манипуляции элементом используется класс ElementRef из модуля @angular/core. Его свойство nativeElement предоставляет доступ к элементу по ссылке.zoom.directive.ts (version 2)


    @Directive({
     selector: '[zoom]'
    })
    export class ZoomDirective{
     constructor(private el: ElementRef){
       el.nativeElement.style.fontSize = '20px';
     }
    }
    

Angular директива из примера предназначена в основном для тега <p>, исходя из условия, что размер шрифта по умолчанию равен 14px, она увеличивает это значение до 20px.(untitled)


    <p>This text is normal.</p>
    <p zoom>This text is larger.</p>
    

Сейчас zoom меняет только стилизацию элемента. Для того чтобы изменить поведение по умолчанию, используется декоратор @HostListener(). Теперь сделаем так, чтобы размер шрифта увеличивался только при наведении на элемент DOM-дерева курсора мыши. Иначе говоря, изменим стандартное поведение при возникновении пользовательского события.

@HostListener() также входит в состав @angular/core.zoom.directive.ts (version 3)


    @Directive({
     selector: '[zoom]'
    })
    export class ZoomDirective{
     constructor(private el: ElementRef){}
    
     @HostListener('mouseenter') onMouseEnter(){
       this.setFontSize(20);
     }
    
     @HostListener('mouseleave') onMouseLeave(){
       this.setFontSize(14);
     }
    
     setFontSize(size: number | string): void{
       this.el.nativeElement.style.fontSize = `${size}px`;
     }
    }
    

@HostListener() привязывает обработчики к событиям, возникающим по отношению к элементу с Angular директивой.

Но что, если поведение элемента, задаваемое ему директивой, зависит от значения внешнего фактора? Рассмотрим передачу внешних значений.

Делается это с использованием входных свойств.zoom.directive.ts (version 4)


    @Directive({
     selector: '[zoom]'
    })
    export class ZoomDirective{
     @Input('zoomSize') size;
    
     constructor(private el: ElementRef){}
    
     @HostListener('mouseenter') onMouseIn(){
       this.setFontSize(this.size);
     }
    
     @HostListener('mouseleave') onMouseOut(){
       this.setFontSize(14);
     }
    
     setFontSize(value: number | string): void{
       this.el.nativeElement.style.fontSize = `${value}px`;
     }
    }
    

Пример использования.(untitled)


    <p zoom [zoomSize]="20">Hover text to make it larger.</p>
    

Здесь размер шрифта, который будет установлен при наведении курсора мыши, задается через входное свойство zoomSize.

Чтобы не вводить лишнее свойство, можно сделать саму директиву zoom входным параметром.(untitled)


    ...
    export class ZoomDirective{
     @Input('zoom') size;
     ...
    }
    

(untitled)


    <p [zoom]="20">Hover text to make it larger.</p>
    

Структурные Angular директивы

Основное отличие структурных директив – они видоизменяют DOM-структуру страницы.

Отличительная их особенность – наличие перед ними символа *.

Префикс * лишь облегчает применение структурных директив, транслируя атрибут в <ng-template></ng-template>, служащий оберткой для элемента, к которому изначально была применена директива.

Например, запись(untitled)


    <p *ngIf="true">Some text</p>
    

транслируется в(untitled)


    <ng-template [ngIf] = "true">
     <p>Some text</p>
    </ng-template>
    

Создадим Angular директиву *duplicateContent для создания копии элемента в зависимости от истинности переданного выражения.duplicate-content.directive.ts


    @Directive({
       selector: '[duplicateContent]'
    })
    export class DuplicateContentDirective{
       @Input() set duplicateContent(condition: boolean){
         if(condition && !this.contentWasDuplicated) {
           this.vc.insert(this.tpl);
           this.contentWasDuplicated = true;
         }
       }
      
       private contentWasDuplicated: boolean = false;
      
       constructor(private tpl: TemplateRef<any>, private vc: ViewContainerRef){}
    }
    

Пример использования.(untitled)


    <div *duplicateContent="true">Content for duplication</div>
    

Создается структурная директива с применением декоратора @Directive(). Он принимает объект, в свойстве selector которого указывается наименование директивы в квадратных скобках.

Представление элемента, включая его самого, хранится в переменной templateRef, являющейся экземпляром класса TemplateRef. Контейнер представлений (элемент <ng-template/>) представлен переменной viewContainer. Подробно о представлениях.

Имея доступ к этим свойствам можно легко манипулировать DOM-элементом.

Обратите внимание, что приватное свойство contentWasDuplicated ограничивает создание более, чем одной копии содержимого.

Share

Тебе может это понравится...