【问题标题】:Angular2 trigger directive from component on click单击时来自组件的Angular2触发指令
【发布时间】:2017-05-11 21:41:52
【问题描述】:

我有一个指令可以为页面上的任何悬停元素添加框阴影,但我需要它在单击按钮后开始应用阴影。我遇到的问题是它只适用于单个元素。

Here is an image of the box shadow

它只适用于我悬停后的标题。我需要将它应用于任何悬停的元素。

我的 app.component:

@Component({
  moduleId: module.id,
  selector: 'my-app',
  template: `
    <h1 myHighlight="orange">{{title}} {{clickedElement | async}}</h1>
    <nav>
      <a routerLink="/dashboard" routerLinkActive="active">Dashboard</a>
      <a routerLink="/heroes" routerLinkActive="active">Heroes</a>
      <a routerLink="/secret-heroes" *ngIf="authService.loggedIn()" routerLinkActive="active">Secret Heroes</a>
      <a (click)=authService.login() *ngIf="!authService.loggedIn()">Log In</a>
      <a (click)=authService.logout() *ngIf="authService.loggedIn()">Log Out</a>
      <a (click)=giveFeedback()>Give Feedback</a>
      <a (click)="listening = !listening" >Give Feedback2</a>

      <button id="modalButton" type="button" (click)="feedbackModal.show()">test</button>
      <my-feedback-modal>
      </my-feedback-modal>

    </nav>
    <router-outlet></router-outlet>
  `,
  styleUrls: ['app.component.css']
})
export class AppComponent {
  //@Input() highlight: boolean = false;
  title = 'Tour of Heroes';

  @ViewChild(ModalComponent) modal: ModalComponent;
  @ViewChild(HighlightDirective) highlightDir: HighlightDirective;

  @ViewChild(FeedbackModalComponent) feedbackModal: FeedbackModalComponent;

  constructor(private authService: AuthService, private el: ElementRef, private cdr: ChangeDetectorRef) {
    this.cdr = cdr;
  }

  clickedElement:BehaviorSubject<ElementRef> = new BehaviorSubject(this.el);

  ngAfterViewInit() {
    //this.clickedElement.next(this.highlightDir.getElement().nativeElement.nodeName);
  }

  ngDoCheck() {

  }

  giveFeedback(): void {

        this.highlightDir.startFeedback();
        this.cdr.detectChanges();
        //this.highlight = true;
  }
}

我的 highlight.directive:

@Directive({
  selector: 'a, abbr, address, article, body, br, button, div, h1, h2, h3, h4, h5, h6, header, hr, i, iframe, img, ' +
  'input, label, li, link, meta, nav, object, ol, option, output, p, param, pre, section, select, small, source, span,' +
  'summary, table, tbody, td, textarea, tfoot, th, thead, time, title, tr, u, ul, video'
})
export class HighlightDirective {
    elementsArray: string[];
    listening: boolean = false;

    constructor(private el: ElementRef, private cdr: ChangeDetectorRef) {
        this.cdr = cdr;
        this.elementsArray = ["a", 'abbr', 'address', 'article', 'body', 'br', 'button', 'div', 'h1', 'h2', 'h3', 'h4', 'h5'
        , 'h6', 'header', 'hr', 'i', 'iframe', 'img', 'input', 'label', 'li', 'link', 'meta', 'nav', 'object', 'ol', 'option'
        , 'output', 'p', 'param', 'pre', 'section', 'select', 'small', 'source', 'span', 'summary', 'table', 'tbody', 'td'
        , 'textarea', 'tfoot', 'th', 'thead', 'time', 'title', 'tr', 'u', 'ul', 'video'];
    }

    //@Input() defaultColor: string;
    //@Input() listening: boolean = false;
    //check: boolean = false;

    public getElement(): ElementRef {
        return this.el;
    }

    public startFeedback(): boolean {
        this.listening = true;
        this.cdr.detectChanges();

        return true;
    }

    @HostListener('click') onClick() {
        if(this.listening) {

            document.getElementById('modalButton').click();

            this.listening = false;
        }
    }

    @HostListener('mouseenter') onMouseEnter() {
        if(this.listening) {

            this.el.nativeElement.style.boxShadow = '0 0 0 5px yellow';
            this.el.nativeElement.parentNode.style.boxShadow = null;
        }
    }

    @HostListener('mouseleave') onMouseLeave() {
        if(this.listening) {

            this.el.nativeElement.style.boxShadow = null;
            this.el.nativeElement.parentNode.style.boxShadow = '0 0 0 5px yellow';

            let check = false;

            for (let entry of this.elementsArray) {
                if (this.el.nativeElement.parentNode.nodeName == entry.toUpperCase()) {
                    check = true;
                    break;
                }
            }

          if (!check)
            this.el.nativeElement.parentNode.style.boxShadow = null;
        }
    }
}

任何帮助将不胜感激。

【问题讨论】:

    标签: angular triggers components element directive


    【解决方案1】:

    问题是您使用@ViewChild 而不是@ViewChildren。对于 ViewChild,它只处理可以在模板中找到的 HighlightDirective 的第一个实例。

    除了您在这里做出的其他一些晦涩的选择之外,我想说您必须更改为这样的内容:

    @ViewChildren(HighlightDirective) highlightDirs: QueryList<HighlightDirective>;
    

    然后您必须将 giveFeedback 函数更改为:

    giveFeedback(): void {
        this.highlightDirs.forEach((highlightDir: HightlightDirective) => {
           highlightDir.startFeedback();
        });
    }
    

    在您的任何代码中都不需要 changeDetectionRef。仅当您将 changeDetection: ChangeDetectionStrategy.OnPush 放在组件/指令上时才需要这样做

    【讨论】:

    • 谢谢,其他元素现在已经应用了阴影,但不幸的是它有问题,并且某些阴影在悬停后会卡住。我猜我的 Host 监听器的设置不是最好的。
    • 我刚刚意识到它并没有完全解决我的问题,因为它不适用于我的 中的其他元素。知道如何解决这个问题吗?
    • 是的,通过使用服务。创建一个服务,当您使用 giveFeedback 按钮时会在该服务上发出事件。让您的 HighlightDirective 注入此服务并监听此事件
    • 难道没有更简单的方法可以做到这一点吗?或者在我的指令中复制我想要完成的事情?
    • 嗯,有一种更简单的方法来完成你想要的,是的......使用 css。和服务的组合。你似乎在使用nativeElementdocument.getElementById,以及直接的组件间通信,这些在 angular2 中都是不受欢迎的,并且总是会导致意大利面条代码......就像现在一样。我建议您多看一下 angular.io 网站上显示的示例。数据下降,事件上升
    猜你喜欢
    • 2016-08-09
    • 1970-01-01
    • 2013-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-15
    • 1970-01-01
    • 2017-11-05
    相关资源
    最近更新 更多