前端analysis | 3w & 1h

《angular8》- 你需要了解的Render2

2020-06-09

Render2

介绍

Render2 是angular中用于操作dom的,Angular做了封装,屏蔽底层差异,通用性更强。不仅仅可以用于浏览器端,还可以用于Server Side rendering, Web-Worker, mobile apps, and desktop apps等。

Render2之指令用法

  • setStyle、removeStyle

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    # 定义指令
    import { Directive, ElementRef, OnInit, Renderer2, HostListener } from '@angular/core';
    @Directive({
    selector: '[animate]'
    })
    export class Animate {
    constructor(private renderer: Renderer2, private el: ElementRef) {}

    @HostListener('click')
    performTask() {
    let randomColor = "#"+((1<<24)*Math.random()|0).toString(16);
    this.renderer.setStyle(this.el.nativeElement, 'color', randomColor);
    this.renderer.setStyle(this.el.nativeElement, 'background-color', 'black');
    this.renderer.removeStyle(this.el.nativeElement, 'color','red');
    }

    }
    1
    2
    # html
    <h2 animate>Click here to give me a random color</h2>
  • setAttribute、removeAttribute

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     @Directive({ 
    selector: '[defaultValue]'
    })
    export class DefaultInputValueDirective {
    constructor(private elRef: ElementRef, private renderer: Renderer2) {
    }
    @HostListener('mouseover')
    onMouseOver() {
    this.renderer.setAttribute(this.elRef.nativeElement, 'value', 'Enter a Value');
    }
    @HostListener('mouseleave')
    onMouseLeave() {
    this.renderer.removeAttribute(this.elRef.nativeElement, 'value');
    }
    }
  • addClass、removeClass

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     @Directive({ 
    selector: '[hlOnMouseOver]'
    })
    export class HlOnMouseOverDirective {
    constructor(private elRef: ElementRef, private renderer: Renderer2) {
    }
    @HostListener('mouseover')
    onMouseOver() {
    this.renderer.addClass(this.elRef.nativeElement, 'hl-text');
    }
    @HostListener('mouseleave')
    onMouseLeave() {
    this.renderer.removeClass(this.elRef.nativeElement, 'hl-text');
    }
    }
  • removeChild、appendChild

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     @Directive({ 
    selector: '[removeChild]'
    })
    export class RemoveChildDirective {
    constructor(private elRef: ElementRef, private renderer: Renderer2) {
    }
    p = this.renderer.createElement('p');
    text = this.renderer.createText('Hello World !');

    @HostListener('mouseover')
    onMouseOver() {
    this.renderer.appendChild(this.p, this.text);
    this.renderer.appendChild(this.elRef.nativeElement, this.p);
    }
    @HostListener('mouseleave')
    onMouseLeave() {
    this.renderer.removeChild(this.elRef.nativeElement, this.p);
    }
    }
  • setProperty

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     @Directive({ 
    selector: '[imgAlt]'
    })
    export class ImageAltdDirective {
    constructor(private renderer: Renderer2, private elRef: ElementRef) {}

    ngOnInit() {
    this.renderer.setProperty(this.elRef.nativeElement, 'alt', 'image description');
    }

    }

Render2之组件用法 - 大部分构造方法只有Renderer2

  • viewChild操作dom appendChild

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    import { Component, ElementRef, Renderer2, ViewChild } from '@angular/core';

    @Component({
    selector: 'app-component',
    template: `<ul class="col-md-2">
    <li (click)="addBtn()" #addButton>Click here to add new button</li>
    </ul>
    `
    })

    export class AppComponent {
    @ViewChild('addButton')
    private animateThis: ElementRef;
    constructor(private renderer: Renderer2) {}

    addBtn() {
    const button = this.renderer.createElement('button');
    const buttonText = this.renderer.createText('This is a button');
    this.renderer.appendChild(button, buttonText);
    this.renderer.appendChild(this.animateThis.nativeElement, button);
    }
    }
    1
    2
    3
    4
    # html
    <ul class="col-md-2">
    <li (click)="addBtn()" #addButton>Click here to add new button</li>
    </ul>
  • insertBefore 、createComment

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    import { Component, ElementRef, Renderer2, ViewChild } from '@angular/core';

    @Component({
    selector: 'app-component',
    template: `<ul class="col-md-2">
    <li (click)="addBtn()" #addButton>Click here to add new button</li>
    </ul>
    `
    })

    export class AppComponent {
    @ViewChild('addButton')
    private animateThis: ElementRef;
    constructor(private elRef: ElementRef, private renderer: Renderer2) {}

    addBtn() {
    const button = this.renderer.createElement('button');
    const buttonText = this.renderer.createText('This is a button');
    const comment = this.renderer.createComment('createComment? Comment Created!');
    const parent = this.elRef.nativeElement.parentNode;
    const reference = this.elRef.nativeElement;
    this.renderer.appendChild(button, buttonText);
    this.renderer.insertBefore(parent, comment, reference )
    this.renderer.appendChild(this.animateThis.nativeElement, button);
    }
    }
  • setStyle

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    import { Component, ViewChild, ElementRef, Renderer2  } from '@angular/core';

    @Component({
    selector: 'my-app',
    template: `
    Username:
    <input type="text" placeholder="type your name..." #changeStyle>
    `,
    })
    export class AppComponent {
    @ViewChild('changeStyle')
    private elRef: ElementRef;
    constructor(private renderer: Renderer2) {}

    ngOnInit() {
    this.renderer.setStyle(this.elRef.nativeElement, 'border', '1px solid red');
    }
    }
  • addClass

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    import { Component, ViewChild, ElementRef, Renderer2  } from '@angular/core';

    @Component({
    selector: 'my-app',
    template: `
    Username:
    <input type="text" placeholder="type your name..." #changeStyle>
    `,
    })
    export class AppComponent {
    @ViewChild('changeStyle')
    private elRef: ElementRef;
    constructor(private renderer: Renderer2) {}

    ngOnInit() {
    this.renderer.addClass(this.elRef.nativeElement, 'someClass');
    }

    //HTML output
    //<input placeholder="type your name..." type="text" class="someClass">
    }
  • setAttribute

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    import { Component, ViewChild, ElementRef, Renderer2  } from '@angular/core';

    @Component({
    selector: 'my-app',
    template: `
    Username:
    <input type="text" placeholder="type your name..." #changeStyle>
    `,
    })
    export class AppComponent {
    @ViewChild('changeStyle')
    private elRef: ElementRef;
    constructor(private renderer: Renderer2) {}

    ngOnInit() {
    this.renderer.setAttribute(this.elRef.nativeElement, 'value', 'Gokhan');
    }
    }
  • setProperty

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    import { Component, ViewChild, ElementRef, Renderer2  } from '@angular/core';

    @Component({
    selector: 'my-app',
    template: `
    Username:
    <input type="text" placeholder="type your name..." #changeStyle>
    `,
    })
    export class AppComponent {
    @ViewChild('changeStyle')
    private elRef: ElementRef;
    constructor(private renderer: Renderer2) {}

    ngOnInit() {
    this.renderer.setProperty(this.elRef.nativeElement, 'disabled', 'disabled');
    this.renderer.setProperty(this.elRef.nativeElement, 'innerHTML', change the inner html');
    }
    }
  • nextSibling

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    import { Component, Renderer2, ElementRef, ViewChild, OnInit } from '@angular/core';

    @Component({
    selector: 'my-app',
    template: `
    <p #next>First</p>
    <p>Second</p>
    <p>Third</p>
    `,
    styleUrls: [ './app.component.css' ]
    })
    export class AppComponent implements OnInit {
    @ViewChild('next')
    private elRef: ElementRef;
    constructor(private renderer: Renderer2) {}

    ngOnInit(){
    const currentElement = this.elRef.nativeElement;
    const nextEl = this.renderer.nextSibling(currentElement);
    this.renderer.addClass(nextEl, 'red');
    }

    }
  • parentNode

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    import { Component, Renderer2, ElementRef, ViewChild, OnInit } from '@angular/core';

    @Component({
    selector: 'my-app',
    template: `
    <div>
    <p #parent>First</p>
    <p>Second</p>
    <p>Third</p>
    </div>
    `,
    styleUrls: [ './app.component.css' ]
    })
    export class AppComponent implements OnInit {
    @ViewChild('parent')
    private elRef: ElementRef;
    constructor(private renderer: Renderer2) {}

    ngOnInit(){
    const currentElement = this.elRef.nativeElement;
    const parent = this.renderer.parentNode(currentElement);
    this.renderer.addClass(parent, 'red');
    }

    }
  • selectRootElement

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    # selectRootElement(selectorOrNode: any, preserveContent?: boolean) - 是否保留子内容

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

    @Component({
    selector: 'my-app',
    template: `
    <div #root>
    X or Y?
    </div>
    <button (click)="changeIt()">Click</button>
    `,
    styleUrls: [ './app.component.css' ]
    })
    export class AppComponent {
    switchText: boolean = false;
    @ViewChild('root')
    private elRef: ElementRef;
    constructor(private renderer: Renderer2) {}
    changeIt(){
    this.switchText = !this.switchText;
    const rootEl = this.elRef.nativeElement;
    const text = this.switchText ?
    this.renderer.createText('Hey X!') :
    this.renderer.createText('Hey Y!');
    this.renderer.selectRootElement(rootEl);
    this.renderer.appendChild(rootEl, text)
    }

    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    # 源码
    selectRootElement(selector: string): Element {
    var el = DOM.querySelector(this._rootRenderer.document, selector);
    if (isBlank(el)) {
    throw new BaseException(`The selector "${selector}" did not match any elements`);
    }
    DOM.clearNodes(el);
    return el;
    }
  • listen

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    import { Component, ViewChild, ElementRef, Renderer2 } from '@angular/core';

    @Component({
    selector: 'my-app',
    template: `
    <p #listen>
    Hover to see some magic!
    </p>
    {{count}}
    `,
    })
    export class AppComponent {
    @ViewChild('listen')
    private elRef: ElementRef;
    constructor(private renderer: Renderer2) {
    }
    toggle = false;
    count = 0;
    ngAfterViewInit() {
    this.renderer.listen(this.elRef.nativeElement, 'mouseover', () => {
    this.toggle = !this.toggle;
    this.count++;
    const currentElement = this.elRef.nativeElement;
    const firstText = this.renderer.createText('Hover to see new text! (Hover me)');
    const secondText = this.renderer.createText('Text changed! (Hover me)');
    const thirdText = this.renderer.createText('Reached maximum count!');

    this.renderer.selectRootElement(currentElement);
    if(this.count < 10){
    this.toggle ? this.renderer.appendChild(currentElement, secondText) :
    this.renderer.appendChild(currentElement, firstText);
    } else {
    this.renderer.appendChild(currentElement, thirdText);
    this.count = 10;
    }

    });
    }
    }

参考

Angular Render2

使用支付宝打赏
使用微信打赏

若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏