Итак, после большого сеанса отладки, я думаю, я выяснил, в чем проблема.Единственная проблема заключается в том, что «решение» на самом деле не лучше, чем обходной путь создания компонента напрямую.
Предостережение: конечно, само собой разумеется, что мой анализ является предположением с моей стороны (основанным на эмпирических наблюдениях), и я не претендую на то, чтобы быть авторитетом в самом исходном коде a-frame.
TLDR;
appendChild , по-видимому, является основным зацепом a-frame для вставки себя в DOM и сцену.Тем не менее, a-frame мудро ограничивает расширенную (или «толстую») версию appendChild тегами, распознаваемыми a-frame (например, «a-cube», «a-scene», «a-бла».. и т.д.).Он не использует эту «толстую» версию appendChild для элементов без рамки.Любой элемент, введенный с помощью angular (например, «app-my-angular-tag»), будет не распознаваться a-frame и, таким образом, будет просто использовать «тонкую» или стандартную версию appendChild , таким образом вставляя в только DOM .
Detail
Похоже, что A-рамка имеет расширенные версии createElement , appendChild и, вероятно, getAttribute и setAttribute . createElement вставляет object3D в элементы, и кажется, что angular использует createElement для создания своих элементов, что объясняет, почему я видел неинициализированные object3D в партиалахЭлементы a-frame (каждый элемент должен быть создан индивидуально, таким образом, даже если родительский элемент не распознается a-frame, дочерние элементы, которые являются a-frame, будут обрабатываться как таковые).
Примечание:родительский компонент обернут в тег a-scene и, таким образом, распознается с помощью вставки символа a-frame и fat.Это объясняет, почему родительский компонент правильно создан .Частное всегда заключено в некоторый родительский элемент, созданный angular.Если часть была обернута в какой-то тег a-frame, такой как a-sub-scene , то я ожидала бы, что он будет правильно введен.
Однако, поскольку дерево созданных элементов вставляется как один фрагмент, a-frame будет смотреть только на тип родительского элемента, который будет не-a-frame в случае введенного углатег.Таким образом, как объяснено в TLDR, полная версия appendChild не вызывается , и среда object3D не настроена, и элемент не внедряется в сцену в виде кадра.
Решение (я)
1) После загрузки a-сцены вы должны зациклить элементы a-frame введенного углового элемента и повторно применить appendChild, который теперь будет использоватьтолстую версию и правильно вставьте в сцену (полный пример здесь )
Вот некоторые доказательства концепции кода:
Родительский компонент:
<body>
<a-scene debug="true">
<app-config-panel></app-config-panel> <-- ng inserts here
<a-circle radius="0" id="config-hook-circle"></a-circle> <--Note: reinsertion point
<a-box position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9" shadow></a-box>
<a-plane position="0 0 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4" shadow></a-plane>
<a-sky color="#ECECEC"></a-sky>
</a-scene>
</body>
Шаблон внедренного дочернего компонента (config-panel.component.html):
<a-entity id="acp">
<a-sphere color="yellow" radius=".2" position="0 0 -3.5"></a-sphere>
<a-cylinder color="red" height=".5" radius=".3" position="-1 2 -3.5"></a-cylinder>
</a-entity>
Повторный ввод вызова после загрузки компонента (в родительском компоненте):
ngOnInit() {
document.querySelector('a-scene')
.addEventListener('loaded', () => {
this.reinjectConfigPanel();
})
}
И коддля повторного введения (примечание: привязано к индивидуальной структуре шаблона, очень хрупкое и не общее решение):
reinjectConfigPanel(){
let acp=document.querySelector('app-config-panel');
let acpClone = (acp.cloneNode(true) as Element);
let hook = document.querySelector('#config-hook-circle');
let numChildren = acpClone.children[0].children.length;
for (let i=0; i < numChildren; i++) {
// Note: after you appendChild node 0, then the next node becomes 0, so we always
// use child 0
hook.appendChild(acpClone.children[0].children[0]) // uses fat version of appendChild
}
}
Как видите, к тому времени, когда все сделано, вы по существу повторно вводитевсе, так что вы могли бы просто ввести его, режв первую очередь.Тем не менее, этот работает , и я хотел показать, что это возможно (а также проверить мою теорию о толстом appendChild ).Там может быть много преимуществ, таких как привязка переменных, которые легче сделать в шаблоне, поэтому могут быть случаи, когда вам нужно сделать что-то вроде этого.
2) Получить A-Frame, чтобы распознать вашугловой тег как «официальный» тег a-frame.Я на самом деле не исследовал эту линию атаки, кроме как предположить, что вызов «registerPrimitive» может быть способом достижения этого:
AFRAME.registerPrimitive('app-config-panel', { defaultComponents: {}, mappings: {} })
Будем надеяться, что, делая это, вы обманываете a-frame, используя толстый appendChild, и, таким образом, добавляете свою часть к a-сцене.Однако это должно быть сделано до того, как a-frame создаст сцену, и единственный способ, которым я мог бы подумать, это изменить сам источник a-frame (?)