处理Angular 4中的DOM事件

时间:2018-02-09 20:41:03

标签: javascript jquery angular events

我是Angular的新手,并试图了解在Angular中处理DOM事件的最佳方法是什么,类似于我们在jQuery中使用的方法。例如,在下面的HTML代码中,我想在点击open按钮时向类filter-section的所有部分添加一个名为btnfilter的新CSS类 -



<aside class="filter ng-scope" id="search-filters">
                    <button class="btn btn-filter in" id="btnfilter">
                        <i class="ico ico-collapsed"></i>
                        <i class="ico ico-expand none"></i>
                    </button>
                    <section class="refine filter-section">
                        <span class="sub-title" title="Filter">
                            <i class="ico ico-gr-filter"></i>
                            <span class="title none">FILTERS</span>
                        </span>
                    </section>
<section class="refine filter-section">
                        <span class="sub-title" title="Filter">
                            <i class="ico ico-gr-filter"></i>
                            <span class="title none">FILTERS</span>
                        </span>
                    </section>
 </aside>
&#13;
&#13;
&#13;

在jQuery中,我们可以做类似下面的事情 -

  $('#btnfilter').click(function () {
      $(this).find('.filter-section').addClass('new-class');
  });

我想知道Angular实现同样的方法。请指教。

4 个答案:

答案 0 :(得分:2)

您可以使用常用的Angular Property Binding来添加您的类,并在您的Typescript文件中提供 flag 变量。

export class YourComponent {

  isBtnToggled: boolean = false;

  constructor() {}

  toggleClass() {
    this.isBtnToggled = !this.isBtnToggled;
  }
}

您的Html模板应如下所示:

<aside class="filter ng-scope" id="search-filters">
    <button class="btn btn-filter in" id="btnfilter" (click)="toggleClass()">
        <i class="ico ico-collapsed"></i>
        <i class="ico ico-expand none"></i>
    </button>
    <section class="refine filter-section" [class.css-class-here]="isBtnToggled">
        <span class="sub-title" title="Filter">
            <i class="ico ico-gr-filter"></i>
            <span class="title none">FILTERS</span>
        </span>
    </section>
</aside>

所以我们在这里做的是,我们在您的Typescript文件中创建了一个函数 toggleClass(),用于切换变量 isBtnToggled 的值。当您单击按钮时,您的值将发生变化, Angular Property Binding [class.your-css-class] 将触发并在您的元素上添加CSS类。如果您有多个过滤器部分类,则可以使用相同的绑定,对其余部分它们的工作方式也相同。

您也可以使用纯JavaScript,只使用DeborahK提供的querySelectorAll('.filter-section')示例,但我建议您远离DOM操作角度。它的速度很慢,很重,并且不会像Angular Universal(服务器端渲染)等其他技术那样100%工作。

我希望我能帮助你,干杯

答案 1 :(得分:1)

以下是我提出的建议:

  constructor(private elRef:ElementRef) { }

  ngAfterViewInit(): void {
    let elementList = this.elRef.nativeElement.querySelectorAll('.filter-section');
    elementList.forEach(element => {
      // element.className += ' new-class';
      element.classList.add('new-class');
      console.log(element);
    });
  }

这将找到具有已定义查询选择器的所有元素,并为每个元素添加所请求的类。

答案 2 :(得分:1)

这是我使用Renderer2对此的看法。这应该是服务器端呈现(SSR)安全,并避免任何与DOM的耦合。

首先,我在下面的#filterSection添加了一个模板(section)。

<aside class="filter ng-scope" id="search-filters">
<button class="btn btn-filter in" id="btnfilter" (click)="getFunky()">
    <i class="ico ico-collapsed"></i>
    <i class="ico ico-expand none"></i>
</button>
<section class="refine filter-section" #filterSection>
    <span class="sub-title" title="Filter">
        <i class="ico ico-gr-filter"></i>
        <span class="title none">FILTERS</span>
    </span>
</section>
</aside>

这是我放在一起的组件代码:

import { Component, Renderer2, AfterViewInit,
    ViewChild, ElementRef } from '@angular/core';

@Component({
    selector: 'app-filter-section',
    templateUrl: './filter-section.component.html',
    styleUrls: ['./filter-section.component.css']
})
export class FilterSectionComponent implements AfterViewInit {
    @ViewChild('filterSection') filterSection: ElementRef;
    private filterElement: HTMLElement;

    constructor(private renTwo: Renderer2) { }

    ngAfterViewInit() {
        if (this.filterSection && this.filterSection.nativeElement) {
            this.filterElement = this.filterSection.nativeElement;
        }
    }

    getFunky() {
      this.renTwo.addClass(this.filterElement, 'new-class');
    }
}

这通过构造函数注入获取Renderer2。在ngAfterViewInit生命周期方法中,我检查filterSection ElementRef以确保它是真实的,并且有一个nativeElement。如果是,请将nativeElement分配给本地私有变量以在组件中使用。在单击函数(getFunky)中,使用Renderer2,我添加了一个带有addClass函数的类,传入私有filterElement和我要添加的类。

Renderer2可用于执行各种DOM操作。见下文。

Renderer2 reference

答案 3 :(得分:1)

这些答案中没有一个能够完全采用棱角分明的方式。

您已经声明目标是在点击按钮时让页面上具有特定类的所有元素添加类。

我想稍微概括一下,并说,您希望某种类型的所有元素以某种方式对事件作出反应。

第1步是你似乎熟悉的绑定:

<button (click)="broadcastEvent()">My Event Button</button>

这是一个简单的点击事件绑定,每个阅读角度教程的人都应该知道。

接下来我们需要有一些广播和接收事件的方式,这是角度服务的一种情况:

@Injectable()
export class EventBroadcastService {
    private eventSource = new Subject();
    event$ = this.eventSource.asObservable();
    broadcastEvent() {
        this.eventSource.next();
    }
}

这是一个简单的服务,具有rxjs主题和可观察性。该服务公开了一个API,允许消费者发送事件并收听它们。回到包含我们按钮的原始组件,我们将注入服务并将我们的按钮点击到此功能:

@Component({
  selector: 'event-button',
  template: `<button (click)="broadcastEvent()">My Event Button</button>`
})
export class EventButtonComponent {
    constructor(private eventBroadcastService: EventBroadcastService) {}

    broadcastEvent() {
      this.eventBroadcastService.broadcastEvent();
    }
}

现在,最后我们需要定义此事件的使用者以对其作出反应:

@Directive({
  selector: '[eventConsumer]'
})
export class EventConsumerComponent implements OnInit, OnDestroy {
    constructor(private eventBroadcastService: EventBroadcastService) {}
    @HostBinding(‘class’) addClass = '';
    private eventSub;
    ngOnInit() {
       this.eventSub = this.eventBroadcastService.event$.subscribe(e => this.addClass = 'new-class');
    }

    ngOnDestroy() {
      this.eventSub.unsubscribe();
    }
}

此指令可以应用于任意元素,并允许您操作该类。

最后我们把它放在一起:

@Component({
   template: `
       <event-button></event-button>
       <section class="filter-section" eventConsumer>
          CONTENT
       </section>
    `,
    providers: [EventBroadcastService]
})
export class MainComponent {

}

这个例子是相当有意思的,但希望能够更好地理解如何使用混合的组件,指令和服务来以更加可控的方式实现与jquery类似的结果。对于一些简单的东西来说,这看起来似乎很多,但是在这样的基础设施中,puttnig会在大型复杂的应用程序中产生红利。

然而,对于看似相当简单的事情来说,这仍然非常麻烦。之所以这样,是因为你仍然处于jQuery心态,需要将你的思维和方法转移到角度风格。你想使用这样的类指令:

<button class="btn btn-filter in" id="btnfilter" (click)="applyClass = true">
    <i class="ico ico-collapsed"></i>
    <i class="ico ico-expand none"></i>
</button>
<section class="refine filter-section" [class.new-class]="applyClass">