gpt4 book ai didi

Angular 组件动态编译 - ng-content 与选择不工作

转载 作者:行者123 更新时间:2023-12-01 21:36:59 24 4
gpt4 key购买 nike

我有一些使用 resolveComponentFactory 动态编译的组件。

我是这样做的....

const embeddedComponentElements = this.hostElement.querySelectorAll( selector );

const element = embeddedComponentElements[ 0 ];

// convert NodeList into an array, since Angular doesn't like having a NodeList passed
const projectableNodes = [
Array.prototype.slice.call(element.childNodes),
];

const factory = componentFactoryResolver.resolveComponentFactory( Component );

const embeddedComponent = factory.create(
this.injector,
projectableNodes,
element,
);

但是我有一个问题正在努力解决......

这按预期工作

<div>
<ng-content></ng-content>
</div>

这没有按预期工作:

<div>
<!-- I get all the content here -->
<ng-content select="h1"></ng-content>
</div>
<div>
<!-- I don't get any content here -->
<ng-content></ng-content>
</div>

ng-content select 属性似乎不适用于动态编译的内容。

知道我做错了什么或者这是一个错误吗?

如果有帮助,我正在使用 Angular 8。

更新:我在 stackBlitz 中重现了这个问题:https://stackblitz.com/edit/angular-ivy-givxx6

最佳答案

我还没有真正弄清楚与 ng-select 相结合的可投影节点参数.

但是如果你检查我的stackblitz你可以看到它在工作......有点。

我发现发生了什么:

  1. ng-select颠倒处理(我认为)。这意味着它首先处理模板中的最后一个选择并检查二维投影节点数组中的最后一个数组
  2. 当你指定一个select查询时,它在相应的数组中找不到它,它只是显示数组中的所有项
  3. 第一个ng-select对应二维数组中的第一个数组。
  4. 如果您有一个节点在选择查询中,并且还将其添加到下一个数组中,则它不会在第一个选择中找到,并且由于某种原因被添加到下一个中​​。反之亦然。

因此,如果您将其作为动态 html:

<hello>
<span class="title">
Title
</span>
<span class="another-title">
Another title
</span>
The rest here of the content......
<div>Something else here</div>
</hello>

你应该让你的节点如下

const projectableNodes = [
[ nodes[1] ], // span class="title"
[ nodes[3] ], // span class="another-title"
[ nodes[0], nodes[2], nodes[4], nodes[5]]
];

要对应这样一个模板:

<h1 class="hello-title">
<ng-content select=".title"></ng-content>
</h1>
<h2 class="hello-title">
<ng-content select=".another-title"></ng-content>
</h2>
<div class="hello-content">
<ng-content></ng-content>
</div>

要解释第 4 点(也许还有第 1 点),如果您这样做:

const projectableNodes = [
[ nodes[1], nodes[3] ],
[ nodes[3] ],
[ nodes[0], nodes[2], nodes[4], nodes[5]]
];

没有问题。如果你反过来做:

const projectableNodes = [
[ nodes[1] ],
[ nodes[3], nodes[1] ],
[ nodes[0], nodes[2], nodes[4], nodes[5]]
];

它永远不会将节点 [1] 转换到正确的位置,但它会以某种方式附加到第二个 <ng-content>与“另一个标题”。我找到了这个 answer ,它有一些赞成票,但它并没有让我很清楚该机制是如何工作的,或者您将能够以何种方式使其动态化。

不过,我希望这能让您有所了解,也许您可​​以想出一个动态的解决方案并发布您自己的答案。或者这可能只是您需要的所有信息,我实际上帮助了您 :D 谁知道呢


仔细查看源代码,您可以找到 ng-content 的数量。你有你的元素。这是由 factory.ngContentSelectors 定义的.在我的 stackblitz 中,这是:

0: ".title"
1: ".another-title"
2: "*"

然后您可以使用 Element.matches() 方法来选择该内容,并将其余内容传递给通配符。然后,您可以使用以下逻辑使其动态化:

const nodes = Array.from(element.childNodes);
const selectors = this.factory.ngContentSelectors;
const projectableNodes = selectors.map(() => []);
const wildcardIdx = selectors.findIndex((selector) => selector === '*');

nodes.forEach((node) => {
if (node instanceof Element) {
// get element node that matches a select which is not the wildcard
const projectedToIdx = selectors.findIndex(
(selector, i) => i !== wildcardIdx && node.matches(selector)
);

if (projectedToIdx !== -1) {
// add it to the corresponding projectableNodes and return
projectableNodes[projectedToIdx].push(node);
return;
}
}

if (wildcardIdx > -1) {
// when there is a wildcard and it's not an Element or it cannot be,
// matched to the selection up, add it to the global ng-content
projectableNodes[wildcardIdx].push(node);
}
});

console.log('projectableNodes', projectableNodes);

const embeddedComponent = this.factory.create(
this.injector,
projectableNodes,
element
);

我想这可以优化,或者这里可能有一些错误,但我希望你能理解。使用这样的逻辑或类似的逻辑,您可以拥有具有动态 ng-content 的相对动态的组件。

关于 Angular 组件动态编译 - ng-content 与选择不工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61802119/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com