【问题标题】:Handle DOM events in Angular 4 [closed]在Angular 4中处理DOM事件[关闭]
【发布时间】:2018-02-09 20:41:03
【问题描述】:

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

<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>

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

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

我想知道 Angular 的实现方式。请指教。

【问题讨论】:

  • 你可以使用 Angular 的 'click' 事件
  • @Alex,如何在我的 .ts 文件中引用所有具有“filter-section”类的 DOM 元素?
  • 我不是刻薄之类的,但这是基本的 Angular。互联网上有数百万条结果。您所要做的就是搜索...您在发布此帖子并等待答案所花费的时间,您可以在 Google 上找到您的答案。
  • 例如:在你绑定了一个点击事件的函数中,你可以使用纯JS在DOM中搜索,寻找该类。如果它有它添加新类。无论是在 JS 中还是在 [ngClass] 内部还是什么的。 (这只是一个粗略的例子)
  • 我认为这个问题很清楚......实际上是一个很好的问题,因为答案并不明显。我不知道为什么它被否决或搁置??

标签: javascript jquery angular events


【解决方案1】:

您可以使用通常的 Angular 属性绑定来添加您的类,并像这样在您的 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 类。如果您有多个 filter-section 类,则可以遵循相同的绑定,并且其余部分的工作方式相同。

您也可以使用纯 JavaScript,只使用 DeborahK 提供的 querySelectorAll('.filter-section') 示例,但我建议您远离 DOM 角度操作。它缓慢、沉重,并且不能 100% 与其他技术(如 Angular Universal(服务器端渲染)等)一起使用。

希望对你有帮助,干杯

【讨论】:

  • 您的解决方案效果很好!
  • 很高兴我帮助了你。不要忘记将主题设置为已回答!编码愉快!
【解决方案2】:

这是我想出的:

  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);
    });
  }

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

【讨论】:

  • 在 Angular 代码中使用纯 jQuery DOM 操作有多好?我同意这行得通,但正如@John 在他的帖子中提到的那样,它又慢又重。
【解决方案3】:

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

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

<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

【讨论】:

  • 请注意,Renderer2 将(很快?)被 Ivy 取代:github.com/robwormald/ivy-code-size
  • @DeborahK,这是 Renderer3 的代号吗?有点像。他们必须避免在名字后面乱扔数字。 :) 感谢您的信息!
  • 当我开始使用 Angular 时,我会避免使用 Renderer2。可能当 ngIvy 出来时,我可以实现它:)
  • @R.Richards 这是 Ivy 的链接:github.com/angular/angular/issues/21706
  • @DeborahK,太棒了!谢谢!
【解决方案4】:

这些答案中没有一个完全符合角度的做事方式。

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

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

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

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

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

接下来我们需要有某种方式来广播和接收事件,这是一个角度服务的例子:

@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 相似的结果。这对于一些简单的东西来说可能看起来很多,但在像这样的基础设施中投入使用会在大型复杂应用程序中产生红利。

但是,对于看起来相当简单的事情来说,这仍然很麻烦。之所以出现这种情况,是因为您仍处于 jQuery 思维模式中,需要将您的思维和方法迁移到 Angular 样式。你想像这样使用类指令:

<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">

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-03-28
    • 1970-01-01
    • 2018-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-14
    相关资源
    最近更新 更多