【问题标题】:angular - Adding a class to a DOM element when clickedangular - 单击时将类添加到 DOM 元素
【发布时间】:2017-03-15 12:08:58
【问题描述】:

我正在尝试将一个会改变其外观的类(例如汉堡到 x)添加到一个菜单触发 DOM 元素,该元素有自己的方法来显示覆盖菜单,但我不能不知道怎么做。

这是我目前所拥有的 - 这是为菜单本身调用一个外部方法:

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

import { LayoutService } from 'app/core/services/layout.service';

@Component({
    moduleId: module.id,
    selector: 'header-main',
    templateUrl: 'header-main.component.html',
})


export class HeaderMainComponent {

    @ViewChild('nav-trigger') el: ElementRef;

    constructor(private layoutService: LayoutService) { }

    menuToggle() {
        this.layoutService.mainMenuToggle();
        this.el.nativeElement.classList.add('opened');
    }
}

我是 Angular 2 的新手。这应该如何解决?我应该使用Renderer,为什么我应该使用Renderer?等等问题


编辑:绝对点击事件(选择孩子,而不是父母)的问题是我们必须使用 reference tag@ViewChild 装饰器配对:

@ViewChild('navTrigger') navTrigger: ElementRef; 与 HTML 模板中的 #navTrigger 引用相关。

因此:

export class HeaderMainComponent {
    logoAlt = 'We Craft beautiful websites'; // Logo alt and title texts

    @ViewChild('navTrigger') navTrigger: ElementRef;

    constructor(private layoutService: LayoutService, private renderer: Renderer) { }

    menuToggle(event: any) {
        this.layoutService.mainMenuToggle();
        this.renderer.setElementClass(this.navTrigger.nativeElement, 'opened', true);
    }
}

【问题讨论】:

标签: angular


【解决方案1】:

要完成你想要的,你需要使用渲染器(用private renderer: Renderer将它注入到构造函数中)。 Renderer 提供了对原生元素的抽象,并提供了一种与 DOM 交互的安全方式。

在您的模板中,您应该能够执行以下操作:

<div (click)="menuToggle($event)"></div>

这会捕获点击事件并将其传递给menuToggle 函数。

然后在你的组件中,你应该能够像这样使用渲染器与 DOM 交互:

menuToggle(event:any) {
    this.renderer.setElementClass(event.target,"opened",true);
}

setElementClass 的函数签名,根据docssetElementClass(renderElement: any, className: string, isAdd: boolean) : void

如需进一步了解渲染器,this is a good article on Medium。在谈到使用ViewChild 和通过nativeElement 访问DOM 与使用Renderer 相比时,它说:

这很好用(使用 ViewChild 中的 nativeElement)。我们在帮助下抓取输入元素 ViewChild 装饰器,然后访问本机 DOM 元素和 在输入上调用 focus() 方法。

这种方法的问题 是当我们直接访问原生元素时,我们放弃了 Angular 的 DOM 抽象和错失了能够实现的机会 也可以在非 DOM 环境中执行,例如:本机移动设备, 本机桌面、Web Worker 或服务器端渲染。

请记住 Angular 是一个平台,浏览器只是我们的一个选择 可以渲染我们的应用。

希望这会有所帮助。

【讨论】:

  • 答案的精确度令人难以置信。不过,我对此有一个小问题,在标记&lt;a (click)="menuToggle($event)" class="nav-trigger"&gt; &lt;i class="icon icon-menu opened"&gt;&lt;/i&gt; &lt;/a&gt; 中,它被添加到内部子元素,而不是类的直接所有者。我该如何解决这个问题?
  • 您可能需要查看target 是什么。点击事件可能会从&lt;i&gt; 传输到父&lt;a&gt;。在这种情况下,您可能需要使用 event.parent 之类的东西。我没有测试过。这只是一个猜测。您可以随时使用console.log(event) 对其进行调试并查看event 上存在哪些选项。
【解决方案2】:

自从 Tyler 回答后,情况发生了一些变化。 Renderer 已折旧并由Renderer2 替换。在Renderer 2 中,类setElementClassaddClass 替换。而addClass 的新函数签名,根据docs

addClass(el: any, name: string): void

所以更新后的menuToggle 函数应该是

menuToggle(event:any) {
    this.renderer.addClass(event.target,"opened");
}

【讨论】:

    【解决方案3】:

    在组件中创建一个支持字段,然后绑定到 ngClass 并使用 typescript 表达式有条件地将类添加到元素中。请注意,应使用单击事件来切换支持字段。例如。

    1. 在组件中:openedBool: boolean = false;
    2. 还有toggleOpenedBool() { openedBool = !openedBool; }
    3. 在模板中:&lt;div (click)="toggleOpenedBool()" [ngClass]="{'opened': openedBool}"&gt;&lt;/div&gt;

    【讨论】:

      猜你喜欢
      • 2016-02-21
      • 2014-06-28
      • 2012-05-31
      • 1970-01-01
      • 2015-11-19
      • 1970-01-01
      • 1970-01-01
      • 2022-12-14
      • 2014-04-11
      相关资源
      最近更新 更多