Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Angular如何操作DOM? #9

Open
deepthan opened this issue Dec 21, 2017 · 0 comments
Open

Angular如何操作DOM? #9

deepthan opened this issue Dec 21, 2017 · 0 comments

Comments

@deepthan
Copy link
Owner

deepthan commented Dec 21, 2017

Angular不建议直接操作DOM元素,正如 ElementRef 函数的源码中介绍的一样:

export declare class ElementRef {
    /**
     * The underlying native element or `null` if direct access to native elements is not supported
     * (e.g. when the application runs in a web worker).
     *
     * <div class="callout is-critical">
     *   <header>Use with caution</header>
     *   <p>
     *    Use this API as the last resort when direct access to DOM is needed. Use templating and
     *    data-binding provided by Angular instead. Alternatively you take a look at {@link Renderer}
     *    which provides API that can safely be used even when direct access to native elements is not
     *    supported.
     *   </p>
     *   <p>
     *    Relying on direct DOM access creates tight coupling between your application and rendering
     *    layers which will make it impossible to separate the two and deploy your application into a
     *    web worker.
     *   </p>
     * </div>
     * @stable
     */
    nativeElement: any;
    constructor(nativeElement: any);
}
export declare class ElementRef {
    /**
     * 如果不支持原生元素直接访问底层的本地元素或`null`
     * (e.g. 当应用程序在一个网络工作者运行).
     *
     * <div class="callout is-critical">
     *   <header>请谨慎使用</header>
     *   <p>
     *  当需要直接访问DOM时,使用此API作为最后的手段。 使用模板和
 数据绑定由Angular提供。 或者,您可以查看{@link Renderer}
 它提供的API即使在直接访问本地元素时也可以安全地使用
支持的。
     *   </p>
     *   <p>
     *   依靠直接的DOM访问可以在应用程序和呈现之间建立紧密的耦合
     *  层将使它不可能分开两个和部署你的应用程序到一个
     *  网络工作者。
     *   </p>
     * </div>
     * @stable
     */
    nativeElement: any;
    constructor(nativeElement: any);
}

ElementRef 获取DOM (ref:参考)

在应用层直接操作 DOM,就会造成应用层与渲染层之间强耦合,导致我们的应用无法运行在不同环境,所以不能直接操作 DOM 元素。
在浏览器中,通过 ElementRef 我们就可以封装不同平台下视图层中的 DOM 元素,最后借助于 Angular 提供的强大的依赖注入特性,我们就可以轻松地访问到 DOM 元素。

// HTML
<div class='deep'>蛮子</div>
// TS 
import { Component, ElementRef, ngAfterViewInit } from '@angular/core';
export class AppComponent {
  constructor(private elementRef: ElementRef) { }
  ngAfterViewInit(){
    let divEle = this.elementRef.nativeElement.querySelector('deep');
    console.log(divEle); ->打印出 '<div class='deep'>蛮子</div>'
  }
}

内置属性装饰器 @ViewChild 改变其样式

// HTML
<div #deep>蛮子</div>
// TS 
import { Component, ElementRef, ViewChild,  ngAfterViewInit } from '@angular/core';
export class AppComponent {
  @ViewChild('deep')  willChangeDiv: ElementRef;
  constructor(private elementRef: ElementRef) {}
  ngAfterViewInit(){
    this.willChangeDiv.nativeElement.style.backgroundColor = 'red';
  }
}

renderer2 对象提供的 API 优雅改变样式

// HTML
<div #deep>蛮子</div>
// TS 
import { Component, ElementRef, ViewChild,  ngAfterViewInit, Renderer  } from '@angular/core';
export class AppComponent {
  @ViewChild('deep')  willChangeDiv: ElementRef;
  constructor(private elementRef: ElementRef) {}
  ngAfterViewInit(){
    this.renderer.setStyle(this.willChangeDiv.nativeElement, 'backgroundColor', 'red');
  }
}

renderer2 提供了哪些方法?


 export declare abstract class render2 { 
    /**
     * This field can be used to store arbitrary data on this renderer instance.
     * This is useful for renderers that delegate to other renderers.
     */
    readonly abstract data: {
        [key: string]: any;
    };
    abstract destroy(): void;
    abstract createElement(name: string, namespace?: string | null): any;
    abstract createComment(value: string): any;
    abstract createText(value: string): any;
    /**
     * This property is allowed to be null / undefined,
     * in which case the view engine won't call it.
     * This is used as a performance optimization for production mode.
     */
    destroyNode: ((node: any) => void) | null;
    abstract appendChild(parent: any, newChild: any): void;
    abstract insertBefore(parent: any, newChild: any, refChild: any): void;
    abstract removeChild(parent: any, oldChild: any): void;
    abstract selectRootElement(selectorOrNode: string | any): any;
    /**
     * Attention: On WebWorkers, this will always return a value,
     * as we are asking for a result synchronously. I.e.
     * the caller can't rely on checking whether this is null or not.
     */
    abstract parentNode(node: any): any;
    /**
     * Attention: On WebWorkers, this will always return a value,
     * as we are asking for a result synchronously. I.e.
     * the caller can't rely on checking whether this is null or not.
     */
    abstract nextSibling(node: any): any;
    abstract setAttribute(el: any, name: string, value: string, namespace?: string | null): void;
    abstract removeAttribute(el: any, name: string, namespace?: string | null): void;
    abstract addClass(el: any, name: string): void;
    abstract removeClass(el: any, name: string): void;
    abstract setStyle(el: any, style: string, value: any, flags?: RendererStyleFlags2): void;
    abstract removeStyle(el: any, style: string, flags?: RendererStyleFlags2): void;
    abstract setProperty(el: any, name: string, value: any): void;
    abstract setValue(node: any, value: string): void;
    abstract listen(target: 'window' | 'document' | 'body' | any, eventName: string, callback: (event: any) => boolean | void): () => void;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant