angular之viewChild和viewChildren

angular之viewChild和viewChildren,第1张

格式:

用于查询指令类型或名字。

告诉viewChild返回什么类型的数据,取值可以是ElementRef,TemplateRef,Component,ViewContainerRef等。

默认为false,如果值为false,则是在变更检测之后解析查询结果,值为true,是在变更检测之前解析。

1:同一个组件,一般不直接使用原生方法 *** 作dom,可以借助viewChild:

2:父子组件,当我们需要获取子组件的值和方法的时候

有两种形式:一种是使用放置锚点的方法,一种是引入子组件。

2.1:放置锚点

2.2:引入子组件

3:问题

报ExpressionChangedAfterItHasBeenCheckedError错误,需要设置static:true

{ static: true } 其实就是静态查询,在ngOnInit中可用。

{ static:false } 其实就是动态查询,一般结合*ngIf使用。

返回一个QueryList集合。

父子组件的传值,是mvvm框架中必然绕不过去的话题,下面列举在angular中父子组件传值的各种方式。

即带有@Input装饰器,如下面两种方式:

父组件在引用子组件的标签的时候,通过 [ ] 符号将父组件的变量名赋值给该变量;

子组件通过在变量名前面加上@Input装饰器的方式,可以从父组件取值,实现父子组件的传值。

在第一种方案的基础上,使用一个输入属性setter,以拦截父组件中值的变化,并采取行动。

通过OnChanges生命周期钩子接口的ngOnChanges()方法来检测输入属性值的变化并做出回应。

子组件暴露一个EventEmitter属性,当事件发生时,子组件利用该属性emits(向上d射)事件,父组件绑定这个事件属性,并在事件发生时做出回应。

子组件的EventEmitter属性是一个输入属性,通常带有@Output装饰器。

子组件:

父组件绑定一个事件处理器,用来响应子组件的事件。d射出的事件,直接写在父组件引入子组件的位置上。

父组件不能使用数据绑定来读取子组件的属性或者调用子组件的方法。但可以在父组件模板里,新建一个本地变量来代表子组件,然后利用这个变量来读取子组件的属性和调用子组件的方法。

本地变量的写法是(# + 变量名)

在父组件中,把本地变量(#timer)放到子组件标签(<countdown-timer>)中,用来代表子组件,该父组件模板就得到子组件的引用,可以在父组件模板访问子组件的属性和方法。

上面那种本地变量的方式,有局限性,只能在父组件的模板中使用。如果在父组件的类中读取子组件的属性方法,就不能使用本地变量了。

当父组件类需要这种访问时,可以把子组件作为ViewChild,注入到父组件中。

首先,你必须导入对装饰器 ViewChild 以及生命周期钩子 AfterViewInit 的引用。

接着,通过 ViewChild 属性装饰器,将子组件 CountdownTimerComponent 注入到私有属性 timerComponent 里面。

ngAfterViewInit() 生命周期钩子是非常重要的一步。被注入的计时器组件只有在 Angular 显示了父组件视图之后才能访问.所以需要加上setTimeout()来等下一轮。

不会!rxjs看不懂!!!

不过可以通过redux存在统一的store树里面,增删改查都从这里取,变相实现传值。

因为在一个directive被link的时候,其内部的directive,是还没有被执行的。

对于ng-model这类的directive还好,那个元素是还在的。

而对于ng-repeat而言则不一样,为了优化,让ng-repeat只被compile一次,它会在compile阶段把这个节点摘除掉,单独compile一次,然后在发生数据绑定的时候对每个实例单独进行link。

用楼上同学的$timeout大法的确是可以的,不过个人不是很建议,因为这样就变成单次绑定了。

你这样获取子元素对于angular来说是非常不建议的,身为一个男人,你必须对ng-repeat的后果负责(雾),它是动态绑定的,意味着它里面的内容会变,如果你只获取一次,那它变了,你没响应,就是不负责任的表现。另一个,你的父directive里对其内容有依赖,这是非常糟糕的实践。

angular给你了一个监听变化的机会,是通过对数据变化的监听。其实是可行的,但是我也不建议这么用。一是在$watch当中你需要维护一个元素它是新的还是旧的,比如避免重复绑事件。二是这样对于$scope里的数据字段结构依然是耦合的,而且也没有解决DOM结构依赖的问题,你的父directive还是没有复用性可言。

所以个人建议如果一个directive是作为容器,那么它不应该对任何它的内容有依赖。如果是作为装饰者,应只作用于元素本身,而不作用于其子元素。

那么如果想实现一个轮播图slides怎么办?很明显slides的内容是很适合通过ng-repeat动态绑定的,我现在希望如果定义一个slides组件,它的内容就会被以轮播图的形式展现。这时候很明显是组件对其内容有依赖。

这里参考angular-ui-bootstrap当中的tabset实现举个例子:再定义一个名为slide-item的directive,在它的声明当中require: '^slides',这样变成了子组件依赖父组件。在slides当中定义add, remove, select等API,在slide-item被link的时候调用其父的add来修改数据,并且再通过转交transclude函数的方式把自己的内容交给slides来处理。这样做到了:

1、slides可以动态包含任意多的slide-item

2、slide-item可以transclude任意的内容

从依赖关系上看,slide-item依赖slides完全没问题,声明了require还能在compile阶段得到angular的保护。slides要求其子元素必须用slide-item进行一次(几乎是透明的)包装,换来的是完全的动态绑定,也可以接受。与此同时,每一个slide-item只会被link一次,还能避免$watch的重复绑定事件这类问题,在它被transclude的时候读取它的DOM内容也是可行的。

(不过我还是要吐槽一下ui-bootstrap的tabset实现,因为为了最终用户代码简洁,生成的最终DOM结构和组件树相差甚远,中间transclude来transclude去的,不过也是为了将就bootstrap)。

总之,对于构建一套组件而言:

子组件可以依赖父组件,父组件不要依赖子组件

宁愿依赖数据,不要依赖DOM

宁愿依赖结构,不要依赖内容


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/bake/11674562.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-17
下一篇 2023-05-17

发表评论

登录后才能评论

评论列表(0条)

保存