Angular 如何使用@ViewChildren获取对未知子元素的引用
我正在使用第三方库来创建选项卡集。这是我用来创建一个简单选项卡集的代码Angular 如何使用@ViewChildren获取对未知子元素的引用,angular,viewchild,Angular,Viewchild,我正在使用第三方库来创建选项卡集。这是我用来创建一个简单选项卡集的代码 <clr-tabs (clrTabsCurrentTabContentChanged)="onTabContentActivated($event)" > <clr-tab-link>Firewall</clr-tab-link> <clr-tab-link>DHCP</clr-tab-link> <clr-tab-
<clr-tabs
(clrTabsCurrentTabContentChanged)="onTabContentActivated($event)" >
<clr-tab-link>Firewall</clr-tab-link>
<clr-tab-link>DHCP</clr-tab-link>
<clr-tab-content>
<vcd-firewall-tab></vcd-firewall-tab>
</clr-tab-content>
<clr-tab-content>
<vcd-dhcp-tab></vcd-dhcp-tab>
</clr-tab-content>
</clr-tabs>
我愿意接受任何建议,我想也许我可以将选项卡的索引与类似
@QueryChildren('clr-tab-content>*')
的内容相匹配,假设每个选项卡下只有一个子项。支持两种方式
- 传递组件或指令类型
- 传递模板变量的名称
对于其他需求,您可以插入
ElementRef
并使用ElementRef.nativeElement….
直接访问DOM,但这样您只能获得元素,而不是组件或指令。问题的真正答案是无法完成。除非提前知道类型,否则无法查询
我通过做两件事,找到了一个解决这个问题的方法,最大限度地减少了为每个选项卡添加的代码量
- 创建可添加到选项卡集的指令,该指令将在
的子元素上触发DOM事件 - 创建一个函数,用于连接DOM事件,并在激活选项卡时自动调用
loadData()
<!-- One piece of glue per tabset -->
<clr-tabs vcd-lazy-tab-loader>
<clr-tab-link>Firewall</clr-tab-link>
<clr-tab-link>DHCP</clr-tab-link>
<clr-tab-content>
<vcd-firewall-tab></vcd-firewall-tab>
</clr-tab-content>
<clr-tab-content>
<vcd-dhcp-tab></vcd-dhcp-tab>
</clr-tab-content>
</clr-tabs>
// lazy-tab-loader.directive.ts
@Directive({
selector: '[vcd-lazy-tab-loader]'
})
export class VcdLazyTabLoader {
constructor(@Inject(forwardRef(() => Tabs)) private tabSet: Tabs,
private el: ElementRef) {
tabSet.currentTabIndexChanged.subscribe((tabIndex) => {
// Not very pretty, we'll find a nicer way later
// It relies on the internal HTML structure of clr-tab-content
const element = this.el.nativeElement.querySelectorAll(`clr-tab-content`)[tabIndex]
.firstElementChild.firstElementChild;
element.dispatchEvent(new CustomEvent("vcd-activated", {}));
});
}
}
export interface CanLoadData {
loadData(): void;
}
export function setupLazyLoader(el: HTMLElement, dataLoader: CanLoadData) {
el.addEventListener('vcd-activated', () => {
dataLoader.loadData();
});
}
// firewall-tab.component.ts (AND dhcp-tab.components.ts)
@Component(...)
// First piece of glue (implement CanLoadData) for a tab
class FirewallTab implements CanLoadData {
constructor(private firewallService: FirewallService,
private el: ElementRef) {
// Second piece of glue, per tab
// Constructor is not the best place, it's here just to avoid extra code
setupLazyLoader(el.nativeElement, this);
}
loadData () {
this.service.getRules().subscribe((data)=> this.rules = rules);
}
}
防火墙
DHCP
//lazy-tab-loader.directive.ts
@指示({
选择器:“[vcd惰性选项卡加载程序]”
})
导出类VcdLazyTabLoader{
构造函数(@Inject(forwardRef(()=>Tabs))私有选项卡集:选项卡,
私人el:ElementRef){
tabSet.currentTabIndexChanged.subscribe((tabIndex)=>{
//不是很漂亮,我们以后会找到更好的方法
//它依赖于clr选项卡内容的内部HTML结构
const element=this.el.nativeElement.querySelectorAll(`clr tab content`)[tabIndex]
.firstElementChild.firstElementChild;
元素。dispatchEvent(新的CustomEvent(“vcd已激活”),{});
});
}
}
导出接口CanLoadData{
loadData():void;
}
导出函数setupLazyLoader(el:HtmleElement,dataLoader:CanLoadData){
el.addEventListener('vcd-激活',()=>{
loadData();
});
}
//firewall-tab.component.ts(和dhcp tab.components.ts)
@组件(…)
//标签的第一块胶水(实现CanLoadData)
类FirewallTab实现CanLoadData{
构造函数(私有防火墙服务:防火墙服务,
私人el:ElementRef){
//第二块胶水,每个标签
//构造函数不是最好的地方,它在这里只是为了避免额外的代码
setupLazyLoader(el.nativeElement,本);
}
加载数据(){
this.service.getRules().subscribe((数据)=>this.rules=rules);
}
}
谢谢,我可能会钻入DOM并触发一个DOM事件,角度组件可以像计划一样聆听声音:)我很想听听您对我的解决方案的反馈。我觉得很好。
<!-- One piece of glue per tabset -->
<clr-tabs vcd-lazy-tab-loader>
<clr-tab-link>Firewall</clr-tab-link>
<clr-tab-link>DHCP</clr-tab-link>
<clr-tab-content>
<vcd-firewall-tab></vcd-firewall-tab>
</clr-tab-content>
<clr-tab-content>
<vcd-dhcp-tab></vcd-dhcp-tab>
</clr-tab-content>
</clr-tabs>
// lazy-tab-loader.directive.ts
@Directive({
selector: '[vcd-lazy-tab-loader]'
})
export class VcdLazyTabLoader {
constructor(@Inject(forwardRef(() => Tabs)) private tabSet: Tabs,
private el: ElementRef) {
tabSet.currentTabIndexChanged.subscribe((tabIndex) => {
// Not very pretty, we'll find a nicer way later
// It relies on the internal HTML structure of clr-tab-content
const element = this.el.nativeElement.querySelectorAll(`clr-tab-content`)[tabIndex]
.firstElementChild.firstElementChild;
element.dispatchEvent(new CustomEvent("vcd-activated", {}));
});
}
}
export interface CanLoadData {
loadData(): void;
}
export function setupLazyLoader(el: HTMLElement, dataLoader: CanLoadData) {
el.addEventListener('vcd-activated', () => {
dataLoader.loadData();
});
}
// firewall-tab.component.ts (AND dhcp-tab.components.ts)
@Component(...)
// First piece of glue (implement CanLoadData) for a tab
class FirewallTab implements CanLoadData {
constructor(private firewallService: FirewallService,
private el: ElementRef) {
// Second piece of glue, per tab
// Constructor is not the best place, it's here just to avoid extra code
setupLazyLoader(el.nativeElement, this);
}
loadData () {
this.service.getRules().subscribe((data)=> this.rules = rules);
}
}