Angular에서 컴포넌트는 특별한 명령어이며, 고유한 템플릿(html)과 스타일(css)을 가지고 있다는 점이 특징입니다. 따라서 컴포넌트를 사용하면 코드를 매우 분리되고, 재사용이 가능하며, 쉽게 확장할 수 있습니다. 일반적인 구성 요소는 다음과 같이 정의됩니다:
demo.component.ts:
demo.component.html:
demo.component.scss:
컴포넌트를 참조하면, 그 컴포넌트의 파싱된 내용이 다음과 같이 렌더링됩니다:
만약 컴포넌트가 외부 투영된 콘텐츠를 받아들여야 한다고 가정해 봅시다. 즉, 컴포넌트가 정의한 것 이상의 것을 보여준다는 뜻입니다. 이 시점에서 이 글의 주인공을 초대합니다ng-콘텐츠。
단순 투영
가장 간단한 것부터 시작해 보겠습니다. 수정된 demo.component.html과 demo.component.scss를 demo.component.html에 다음과 같이 추가합니다:
demo.component.html:
demo.component.scss:
효과를 위해 용기의 배경색은 의도적으로 주황색으로 정의되어 있습니다.
이 시점에서 컴포넌트를 참조할 때 외부에서 콘텐츠를 캐스팅할 수 있으며, 외부 콘텐츠는 주황색 영역에 표시됩니다:
타겟 투영
여러 개가 동시에 존재한다면, 외부 콘텐츠는 어떻게 투영될까요?
먼저 예시를 살펴보겠습니다. 구분을 위해 파란색 영역, 수정된 demo.component.html, 그리고 demo.component.scss를 다음과 같이 추가했습니다:
demo.component.html:
demo.component.scss:
컴포넌트를 참조하자면:
이 시점에서 외부 콘텐츠가 파란색 영역에 투영되는 것을 볼 수 있습니다:
물론, 파란색 지역 번호 뒤에 주황색 지역번호를 넣으면 외부 콘텐츠가 주황색 영역에 투영됩니다:
위 예시에서 단순 가 있다면 외부 콘텐츠는 구성 요소 템플릿의 마지막 부분에 투영됩니다.
이 문제를 알게 된 후, 우리는 외부 콘텐츠를 타겟팅할 수 있을까 하는 의문을 가질 수 있습니다. 답은 분명히 그렇습니다.
이 문제를 해결하려면 한 명을 지원하세요고르다특정 콘텐츠가 특정 장소에 투사될 수 있게 해주는 속성들입니다. 이 속성은 CSS 셀렉터(태그 셀렉터, 클래스 셀렉터, 속성 셀렉터)를 지원합니다、... )당신이 원하는 것과 일치하도록 할 수 있습니다. ng-content에 select 속성이 설정되어 있지 않으면, 전체 콘텐츠 또는 다른 ng-content 요소와 일치하지 않는 콘텐츠를 받게 됩니다.
예제를 직접 보면, 수정된 demo.component.html와 demo.component.scss는 다음과 같습니다:
demo.component.html:
demo.component.scss:
위 코드에서 보시다시피, 파란색 영역은 태그 헤더의 일부를, 빨간색 영역은 "demo2" 클래스를 가진 div 부분을, 초록색 영역은 속성 이름이 "demo3"인 div 부분을, 주황색 영역은 나머지 외부 콘텐츠(start, i is the content of external embed, end)를 받습니다.
컴포넌트를 참조하자면:
이 시점에서 외부 콘텐츠가 지정된 에 투영되는 것을 볼 수 있습니다.
지식 확장
ngProjectAs
이제 ng-content의 select 속성은 외부 콘텐츠가 주어진 에 투영되도록 지정할 수 있게 해준다는 것을 알게 되었습니다.
select 속성을 기반으로 콘텐츠를 올바르게 투영하려면 제한이 있습니다 - 태그 헤더, "demo2" 클래스를 가진 div, 또는 속성 이름이 "demo3"인 div 등, 이 태그들은 모두 컴포넌트 태그의 직접 서브노드입니다.
만약 직접 서브노드가 아니었다면 어떻게 되었을까요? 단순히 demo-component 컴포넌트를 참조하는 코드를 수정하고, 태그 헤더를 div에 넣은 뒤 다음과 같이 수정해 봅시다:
이 시점에서 탭 헤더 부분이 더 이상 파란색 영역이 아니라 주황색 영역으로 투영된 것을 볼 수 있습니다. 그 이유는 <ng-content select="header"></ng-content>가 이전 태그 헤더와 일치하지 않기 때문에, 이 부분의 콘텐츠가 주황색 <ng-content></ng-content> 영역으로 투영되기 때문입니다.
이 문제를 해결하기 위해 ngProjectAs 속성을 사용해야 하며, 이 속성은 모든 요소에 적용할 수 있습니다. 자세한 내용은 다음과 같습니다:
ngProjectAs 속성을 설정하면, 태그 헤더가 위치한 div가 select="header"를 가리키고, 태그 헤더의 일부가 파란색 영역으로 투영됩니다:
<ng-content>콘텐츠를 '생성'하지 마세요 실험을 해보세요 실험을 수행하려면 먼저 데모-자식 컴포넌트 컴포넌트를 정의합니다:
demo-component to :
그 다음 demo-component cast demo-child-component에서:
이 시점에서 콘솔에서는 demo-child-컴포넌트 초기화가 완료된 것을 볼 수 있습니다! 이 말들. 하지만 연산 전환 버튼을 누르면 demo-child-component 초기화가 완료됩니다! 더 이상 인쇄되지 않기 때문에, 데모 자식 컴포넌트 구성요소는 한 번만 인스턴스화되며, 파괴되거나 재생성되지 않습니다.
왜 이런 일이 일어나는 걸까요?
발생 원인
콘텐츠를 <ng-content> '제작'하는 것이 아니라 기존 콘텐츠를 투사하는 것입니다. node.appendChild(el) 또는 jQuery의 $(node).append(el) 메서드와 동등하다고 생각할 수 있습니다: 이 메서드들로 노드는 복제되지 않고 단지 새 위치로 이동됩니다. 따라서 프로젝션 콘텐츠의 수명 주기는 선언된 위치에 묶이지, 제자리에 표시되지 않습니다.
이것이 원리에서 앞서 나온 질문도 설명해줍니다:여러 개가 동시에 존재한다면, 외부 콘텐츠는 어떻게 투영될까요?
이 동작은 두 가지 이유 때문에 이루어집니다: 일관성과 성능입니다. "원하는 일관성"이란 개발자가 코드만 보고 애플리케이션의 동작을 추측할 수 있다는 뜻입니다. 예를 들어 제가 다음과 같은 코드를 작성했다고 합시다:
분명히 demo-child-컴포넌트 컴포넌트는 한 번 인스턴스화되겠지만, 이제 서드파티 라이브러리의 컴포넌트를 사용한다면:
만약 서드파티 라이브러리가 데모-자식 컴포넌트 컴포넌트의 수명 주기를 통제한다면, 몇 번이나 인스턴스화되었는지 알 방법이 없을 것입니다. 이를 위해서는 서드파티 라이브러리의 코드를 살펴보고 내부 처리 로직을 이해하는 것이 유일한 방법입니다. 구성 요소의 수명 주기를 래퍼 대신 애플리케이션 구성 요소에 묶는 의미는, 개발자가 서드파티 라이브러리의 내부 코드를 알지 못한 채 카운터가 한 번만 인스턴스화되도록 제어할 수 있다는 점입니다.
성능 이유더 중요해. ng-콘텐츠는 단순히 이동 요소이기 때문에 런타임이 아닌 컴파일 시점에 처리할 수 있어 실제 애플리케이션의 작업 부담을 크게 줄여줍니다.
우회 방법
컴포넌트가 투영된 하위 컴포넌트의 인스턴스화를 제어하려면 두 가지 방법으로 할 수 있습니다: <ng-template> 콘텐츠 주변에 요소와 ngTemplateOutlet을 사용하는 방법, 또는 "*" 구문을 가진 구조 지시를 사용하는 방법입니다. 간단히 하기 위해 예시에서는 구문(Syntax)을 사용하겠습니다 <ng-template> .
demo-component to :
그다음 ng-template에 demo-child-component를 포함시킨다:
이 시점에서 전환 버튼을 누르면 콘솔이 출력됩니다demo-child-component 초기화 완료!이 말들.
|