GVKun编程网logo

Angular2:第二次避免使用DOM渲染(angular操作dom)

16

本文将为您提供关于Angular2:第二次避免使用DOM渲染的详细介绍,我们还将为您解释angular操作dom的相关知识,同时,我们还将为您提供关于angular2–Angular2:从父组件获取R

本文将为您提供关于Angular2:第二次避免使用DOM渲染的详细介绍,我们还将为您解释angular操作dom的相关知识,同时,我们还将为您提供关于angular2 – Angular 2:从父组件获取RouteParams、angular2 – Angular 2:如何使用/导入http模块?、angular2 – Angular 2:聚焦于新添加的输入元素、angular2 – 使用D3.js与Angular 2的实用信息。

本文目录一览:

Angular2:第二次避免使用DOM渲染(angular操作dom)

Angular2:第二次避免使用DOM渲染(angular操作dom)

我有一个Tab控件,其中有两个选项卡.我在不同的标签中放置了两个Kendo Grid / Any组件.

当我第一次打开/选择选项卡时,它会在DOM中呈现相关的组件/ html.为了提高性能,我在选项卡上放置了ngIf以仅显示活动选项卡html.所以现在Dom只显示​​活动标签html,但现在当我遍历其他标签并重新访问上一个标签时,它的组件/内容似乎再次渲染.我想停止第二次渲染.

注意:如果我用隐藏替换ngIf,那么它可以接受,但由于许多手表和DOM与之相关,因此性能成本很高.

实际上我的主要问题是,由于上述问题,当我导航到标签时,我的网格滚动位置每次都设置为顶部而不是它应保持在同一状态

下面是我所做的代码的一部分.

如果选项卡内容中的条件为html(仅渲染DOM中的选定选项卡)

<divhttps://www.jb51.cc/tag/heading/" target="_blank">heading-outer">
    <divhttps://www.jb51.cc/tag/heading/" target="_blank">heading">
        <ul id="ulOpenedTabs"role="tablist">
            <li>                 
                <span> {{tab.Header}} </span>
            </li>
        </ul>
    </div>
</div>

<div*ngIf="tab.IsSelected">
    <ng-content>
    <!--Html goes here-->
    </ng-content>
</div>
如果您真的不想从DOM中删除组件并在打开选项卡时重新呈现它,则另一种解决方案可能是:

>使用[隐藏]隐藏组件.
>当选项卡关闭时,使用ChangeDetectorRef.detach()从更改检测树中删除组件.
>打开选项卡以获取最新数据时,使用ChangeDetectorRef.reattach()将更改检测添加回组件.

根据组件的实现方式,这可以解决您的性能问题.特别是如果你非常依赖于Observables和异步管道(如你所愿),如果没有检查模板的变化,就不应该进行计算.

引用detach()的文档:

Imagine the data changes constantly,many times per second. For performance reasons,we want to check and update the list every five seconds. We can do that by detaching the component’s change detector and doing a local check every five seconds.

您可以这样做,但不是基于时间,而是基于选项卡是否打开.

您所要做的就是在组件构造函数中注入ChangeDetectorRef,并将更改检测挂钩到@input()属性:

constructor(private changeDetector: ChangeDetectorRef) {}

@input() set visible(visible: boolean) {
  if(!visible) {
    changeDetector.detach();
  } else {
    changeDetector.reattach();
  }
}

现在,您只需设置[visible] =“false”或[visible] =“true”即可控制组件是否获取新数据.

您可以在ChangeDetectorRef的官方文档中找到另一个full example.

angular2 – Angular 2:从父组件获取RouteParams

angular2 – Angular 2:从父组件获取RouteParams

如何从父组件获取RouteParams?

应用:

@Component({
  ...
})

@RouteConfig([
  {path: '/',component: HomeComponent,as: 'Home'},{path: '/:username/...',component: ParentComponent,as: 'Parent'}
])

export class HomeComponent {
  ...
}

然后,在ParentComponent中,我可以很容易地获取我的用户名参数并设置子路由。

父母:

@Component({
  ...
})

@RouteConfig([
  { path: '/child-1',component: ChildOneComponent,as: 'ChildOne' },{ path: '/child-2',component: ChildTwoComponent,as: 'ChildTwo' }
])

export class ParentComponent {

  public username: string;

  constructor(
    public params: RouteParams
  ) {
    this.username = params.get('username');
  }

  ...
}

但是,那么,我如何在这些子组件中获得相同的“username”参数?做与上面相同的技巧,不这样做。因为那些参数是在ProfileComponent或者是?? ??

@Component({
  ...
})

export class ChildOneComponent {

  public username: string;

  constructor(
    public params: RouteParams
  ) {
    this.username = params.get('username');
    // returns null
  }

  ...
}
更新:

现在Angular2 final正式发布,正确的方法是这样做的:

export class ChildComponent {

    private sub: any;

    private parentRouteId: number;

    constructor(private route: ActivatedRoute) { }

    ngOnInit() {
        this.sub = this.route.parent.params.subscribe(params => {
            this.parentRouteId = +params["id"];
        });
    }

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

原版的:

这里是如何使用“@ angular / router”:“3.0.0-alpha.6”包:

export class ChildComponent {

    private sub: any;

    private parentRouteId: number;

    constructor(
        private router: Router,private route: ActivatedRoute) {
    }

    ngOnInit() {
        this.sub = this.router.routerState.parent(this.route).params.subscribe(params => {
            this.parentRouteId = +params["id"];
        });
    }

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

在此示例中,路由具有以下格式:/ parent /:id / child /:childid

export const routes: RouterConfig = [
    {
        path: '/parent/:id',children: [
            { path: '/child/:childid',component: ChildComponent }]
    }
];

angular2 – Angular 2:如何使用/导入http模块?

angular2 – Angular 2:如何使用/导入http模块?

我一直在玩 Angular 2 Quickstart.如何在Angular 2中使用/ import http模块?
我看了 Angular 2 Todo’s .js,但它不使用http模块。

我在package.json中添加了“ngHttp”:“angular / http”,因为我听说Angular 2有点模块化

在版本37你需要这样做:
///<reference path="typings/angular2/http.d.ts"/>    
import {Http} from "angular2/http";

并运行此tsd命令:

tsd install angular2/http

angular2 – Angular 2:聚焦于新添加的输入元素

angular2 – Angular 2:聚焦于新添加的输入元素

我有一个新的Angular 2应用程序与输入框列表。当用户点击返回键时,我在他们当前编辑的那个之后立即添加一个新的输入框。或者,我(异步地)向模型中的数组添加一个新条目,这将导致Angular 2在不久的将来自动生成一个新的输入框。

如何使输入焦点自动更改为新添加的元素?

或者,我获得对引起DOM生成的模型对象的引用。从组件代码,是否有一种方法来搜索表示特定模型对象的DOM元素?

这里是我的代码,只是使这项工作。希望这是冒犯足够一些Angular 2 devs鼓励回复:-)

app.WordComponent = ng.core
    .Component({
        selector: 'word-editor',template:'<input type="text" [value]="word.word" (input)="word.update($event.target.value)" (keydown)="keydown($event)"/>',styles:[
            ''
        ],properties:[
            'list:list','word:word'
        ]
    })
    .Class({
        constructor:[
            function() {
            }
        ],keydown:function(e) {
            if(e.which == 13) {
                var ul = e.target.parentNode.parentNode.parentNode;
                var childCount = ul.childNodes.length;

                this.list.addWord("").then(function(word) {
                    var interval = setInterval(function() {
                        if(childCount < ul.childNodes.length) {
                            ul.lastChild.querySelector('input').focus();
                            clearInterval(interval);
                        }
                    },1);
                });
            }
        }
    });
如果我允许这样做,我将参加@Sasxa答案,并修改它,使它更像你要找的。

几个变化

>我将使用ngFor,因此angular2添加新的输入,而不是自己做。主要目的是让angular2遍历它。
> Intead ViewChild我将使用ViewChildren返回一个QueryList属性的QueryList。此属性是一个Observable,它会在元素更改后返回。

因为在ES5中,我们没有装饰器,我们必须使用queries属性来使用ViewChildren

零件

Component({
    selector: 'cmp',template : `
        <div>
            // We use a variable so we can query the items with it
            <input #input (keydown)="add($event)" *ngFor="#input of inputs">
        </div>
    `,queries : {
        vc : new ng.core.ViewChildren('input')
    }
})

专注于最后一个元素。

ngAfterViewInit: function() {

    this.vc.changes.subscribe(elements => {
        elements.last.nativeElement.focus();
    });

}

像我之前说的,ViewChildren返回一个包含changes属性的QueryList。当我们订阅它每次它改变它将返回元素的列表。列表元素包含最后一个属性(在其他情况下),在这种情况下返回最后一个元素,我们使用nativeElement,最后focus()

添加输入元素这是为了纯粹的目的,输入数组没有真正的目的多于重绘ngFor。

add: function(key) {
    if(key.which == 13) {
        // See plnkr for "this.inputs" usage
        this.inputs.push(this.inputs.length+1);
    }
}

我们在数组上推一个虚项,以便重绘。

示例使用ES5:http://plnkr.co/edit/DvtkfiTjmACVhn5tHGex

示例使用ES6 / TS:http://plnkr.co/edit/93TgbzfPCTxwvgQru2d0?p=preview

更新29/03/2016

时间已经过去,事情已经澄清,总是有最好的做法来学习/教导。我已经通过改变一些东西简化了这个答案

>而不是使用@ViewChildren和订阅它,我做了一个指令,每当一个新的输入创建的instatiated
>我使用渲染器使其WebWorker安全。原始答案直接访问focus()直接对不鼓励的nativeElement。
>现在我听了keydown.enter这简化了key down事件,我不必检查哪个值。

到了点。组件看起来像(简化,在下面的plnkrs的完整代码)

@Component({
  template: `<input (keydown.enter)="add()" *ngFor="#input of inputs">`,})

add() {
    this.inputs.push(this.inputs.length+1);
}

和指令

@Directive({
  selector : 'input'
})
class MyInput {
  constructor(public renderer: Renderer,public elementRef: ElementRef) {}

  ngOnInit() {
    this.renderer.invokeElementMethod(
      this.elementRef.nativeElement,'focus',[]);
  }
}

正如你可以看到,我调用invokeElementMethod触发焦点在元素,而不是直接访问它。

这个版本比原来更干净,更安全。

plnkrs更新到beta 12

示例使用ES5:http://plnkr.co/edit/EpoJvff8KtwXRnXZJ4Rr

示例使用ES6 / TS:http://plnkr.co/edit/em18uMUxD84Z3CK53RRe

angular2 – 使用D3.js与Angular 2

angular2 – 使用D3.js与Angular 2

我已经成功地集成Angular 2(阿尔法44)与D3.js:
<html>
<head>
<title>Angular 2 QuickStart</title>
<script src="../node_modules/systemjs/dist/system.src.js"></script>
<script src="../node_modules/angular2/bundles/angular2.dev.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js" charset="utf-8"></script>
<script>
  System.config({packages: {'app': {defaultExtension: 'js'}}});
  System.import('app/app');
</script>
</head>
<body>
<my-app>Loading...</my-app>
</body>
</html>

app.js:

/// <reference path="./../../typings/tsd.d.ts" />

import {Component,bootstrap,ElementRef} from 'angular2/angular2';

@Component({
  selector: 'my-app',template: '<h1>D3.js Integrated if background is yellow</h1>',providers: [ElementRef]
})
class AppComponent { 
  elementRef: ElementRef;

  constructor(elementRef: ElementRef) {
   this.elementRef = elementRef;
  }

afterViewInit(){
    console.log("afterViewInit() called");
    d3.select(this.elementRef.nativeElement).select("h1").style("background-color","yellow");
  }
}
bootstrap(AppComponent);

一切工作正常。但是ElementRef的Angular 2文档说明了以下内容:

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

现在的问题出现如何集成D3.js与Renderer API的?

要使用Renderer,您需要原始HTML元素(也称为nativeElement)。所以基本上你必须使用你的库,得到raw元素,并将其传递给Renderer。

例如

// h3[0][0] contains the raw element
var h3 = d3.select(this.el.nativeElement).select('h3');
this.renderer.setElementStyle(h3[0][0],'background-color','blue');

关于ElementRef的警告是关于直接使用它。这意味着这是不鼓励的

elementRef.nativeElement.style.backgroundColor = 'blue';

但这是好的

renderer.setElementStyle(elementRef.nativeElement,'blue');

为了展示的目的,你可以使用它与jQuery

// h2[0] contains the raw element
var h2 = jQuery(this.el.nativeElement).find('h2');
this.renderer.setElementStyle(h2[0],'blue');

我的建议虽然是坚持使用angular2提供你这样做很容易,而不依赖于另一个库。

有了纯angular2,你有两个简单的方法

>使用指令

// This directive would style all the H3 elements inside MyComp
@Directive({
    selector : 'h3',host : {
        '[style.background-color]' : "'blue'"
    }
})
class H3 {}

@Component({
    selector : 'my-comp',template : '<h3>some text</h3>',directives : [H3]
})
class MyComp {}

>使用带有局部变量的ViewChild

@Component({
    selector : 'my-comp',template : '<h3 #myH3>some text</h3>',})
class MyComp {
    @ViewChild('myH3') myH3;
    ngAfterViewInit() {
        this.renderer.setElementStyle(this.myH3.nativeElement,'blue');
    }
}

这是一个plnkr与我在这个答案中提到的所有情况。你的要求可能不同,当然,但尝试使用angular2,只要你可以。

关于Angular2:第二次避免使用DOM渲染angular操作dom的问题我们已经讲解完毕,感谢您的阅读,如果还想了解更多关于angular2 – Angular 2:从父组件获取RouteParams、angular2 – Angular 2:如何使用/导入http模块?、angular2 – Angular 2:聚焦于新添加的输入元素、angular2 – 使用D3.js与Angular 2等相关内容,可以在本站寻找。

本文标签: