假设我们有一个如下的 html 结构
<div [innerHTML]="contentFromAPI | safeHTML"></div>
现在来自 api 的内容将是由更多 HTML 元素组成的字符串。使结构像这样:
<div>
<p></p>
<p></p>
<p></p>
<p></p>
<p></p>
<p></p>
<p></p>
<p></p>
<p></p>
<p></p>
</div>
我想动态创建一个组件并将其插入到子节点的中间。在这种情况下,排在第五位。
为此,我正在做这样的事情:
html 文件:
<div [innerHTML]="contentFromAPI | safeHTML" #articleContent></div>
ts 文件:
@ViewChild('articleContent', { read: ViewContainerRef })
private articleContent!: ViewContainerRef;
ngOnChanges(){
if(ads){
this.addElementToTemplate();
}
}
private addElementToTemplate() {
setTimeout(() => {
const childrenLength =
this.articleContent.element.nativeElement.children.length;
this.articleContent.createComponent(DynamicElement,{index: Math.ceil(childrenLength/2)});
}, 3000);
}
但这会将该组件添加为内容元素的同级元素。像这样的东西:
<div>
<p></p>
<p></p>
<p></p>
<p></p>
<p></p>
<p></p>
<p></p>
<p></p>
<p></p>
<p></p>
</div>
<dynamic-element></dynamic-element>
可以在
innerHTML
内插入角度组件,但我们应该注意,以这种方式插入的元素位于角度上下文之外,并且更改检测将不起作用,因此它的行为就像普通的HTML元素一样。最好寻找替代方法而不是使用 innerHTML
,请查找下面的示例,强调我的观点,即更改检测在innerHTML 中不起作用
完整代码
import {
ApplicationRef,
Component,
Renderer2,
ViewChild,
ViewContainerRef,
createComponent,
} from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import 'zone.js';
import { SafeHtmlPipe } from './safe-html.pipe';
import { CommonModule } from '@angular/common';
import { DynamicComponent } from './app/dynamic/dynamic.component';
@Component({
selector: 'app-root',
standalone: true,
imports: [SafeHtmlPipe, CommonModule, DynamicComponent],
template: `
<div [innerHTML]="contentFromAPI | safeHtml" #articleContent></div>
`,
})
export class App {
@ViewChild('articleContent', { read: ViewContainerRef })
private articleContent!: ViewContainerRef;
name = 'Angular';
contentFromAPI = `
<p>1</p>
<p>2</p>
<p>3</p>
<p>4</p>
<p>5. insert here!</p>
<p>6</p>
<p>7</p>
<p>8</p>
<p>9</p>
<p>10</p>
`;
constructor(
private renderer2: Renderer2,
private applicationRef: ApplicationRef
) {}
ngAfterViewInit() {
this.addElementToTemplate();
}
private addElementToTemplate() {
const environmentInjector = this.applicationRef.injector;
const componentRef = createComponent(DynamicComponent, {
environmentInjector,
});
const insertElement = this.articleContent.element.nativeElement;
console.log(insertElement);
this.renderer2.appendChild(
insertElement.children[4],
componentRef.location.nativeElement
);
this.articleContent.createComponent(DynamicComponent, {
index: 0,
});
componentRef.hostView.detectChanges();
}
}
bootstrapApplication(App);
根据我对问题的理解,这是一个可以在 .ts 文件中制定的解决方案。
this.contentFromAPI = //your data from API here;
const parser = new DOMParser();
const doc = parser.parseFromString(this.contentFromAPI, 'text/html');
// Get the element at the 5th position
//add logic to find middle node here instead of 4
const targetElement = doc.body.childNodes[4];
const componentElement = document.createElement('your-dynamic-component');
targetElement.parentNode.insertBefore(componentElement, targetElement);
// Update the contentFromAPI with the modified HTML structure
this.contentFromAPI = doc.body.innerHTML;
希望这会有所帮助:)