핵심 구성 요소 확장 extend-component
AEM SPA 편집기에서 사용할 기존 핵심 구성 요소를 확장하는 방법을 알아봅니다. 기존 구성 요소를 확장하는 방법을 이해하는 것은 AEM SPA Editor 구현의 기능을 사용자 정의하고 확장하는 강력한 기술입니다.
목표
- 추가 속성 및 콘텐츠를 사용하여 기존 핵심 구성 요소를 확장합니다.
- 을 사용하여 구성 요소 상속의 기본 사항 이해
sling:resourceSuperType
. - 을(를) 활용하는 방법 알아보기 전달 패턴 기존 논리 및 기능을 재사용하는 슬링 모델용
빌드할 내용
이 장에서는 표준에 추가 속성을 추가하는 데 필요한 추가 코드를 보여 줍니다 Image
새 제품에 대한 요구 사항을 충족시키기 위한 구성 요소 Banner
구성 요소. 다음 Banner
구성 요소에 표준과 동일한 속성이 모두 포함됩니다 Image
구성 요소이지만 사용자가 을 채울 추가 속성을 포함합니다. 배너 텍스트.
사전 요구 사항
설정에 필요한 도구 및 지침 검토 로컬 개발 환경. 이 시점에서 자습서에서는 사용자가 AEM SPA Editor 기능을 확실히 이해하고 있다고 가정합니다.
Sling 리소스 슈퍼 유형을 통한 상속 sling-resource-super-type
기존 구성 요소를 확장하려면 다음 이름의 속성을 설정합니다. sling:resourceSuperType
구성 요소 정의에 따라 달라집니다. sling:resourceSuperType
다음 값: 속성 다른 구성 요소를 가리키는 AEM 구성 요소의 정의에 설정할 수 있습니다. 이렇게 하면 구성 요소가 로 식별된 구성 요소의 모든 기능을 상속하도록 명시적으로 설정됩니다. sling:resourceSuperType
.
를 연장하려면 Image
구성 요소 wknd-spa-react/components/image
의 코드를 업데이트해야 합니다. ui.apps
모듈.
-
아래에 새 폴더 만들기
ui.apps
모듈banner
위치:ui.apps/src/main/content/jcr_root/apps/wknd-spa-react/components/banner
. -
아래에
banner
구성 요소 정의 만들기(.content.xml
)을 클릭하여 제품에서 사용할 수 있습니다.code language-xml <?xml version="1.0" encoding="UTF-8"?> <jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" jcr:primaryType="cq:Component" jcr:title="Banner" sling:resourceSuperType="wknd-spa-react/components/image" componentGroup="WKND SPA React - Content"/>
다음을 설정합니다.
wknd-spa-react/components/banner
의 모든 기능을 상속하려면wknd-spa-react/components/image
.
cq:editConfig cq-edit-config
다음 _cq_editConfig.xml
파일은 AEM 작성 UI의 드래그 앤 드롭 동작을 지시합니다. 이미지 구성 요소를 확장할 때 리소스 유형이 구성 요소 자체와 일치해야 합니다.
-
다음에서
ui.apps
모듈 아래에 다른 파일 만들기banner
명명된_cq_editConfig.xml
. -
채우기
_cq_editConfig.xml
다음 XML을 사용하여code language-xml <?xml version="1.0" encoding="UTF-8"?> <jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0" jcr:primaryType="cq:EditConfig"> <cq:dropTargets jcr:primaryType="nt:unstructured"> <image jcr:primaryType="cq:DropTargetConfig" accept="[image/gif,image/jpeg,image/png,image/webp,image/tiff,image/svg\+xml]" groups="[media]" propertyName="./fileReference"> <parameters jcr:primaryType="nt:unstructured" sling:resourceType="wknd-spa-react/components/banner" imageCrop="" imageMap="" imageRotate=""/> </image> </cq:dropTargets> <cq:inplaceEditing jcr:primaryType="cq:InplaceEditingConfig" active="{Boolean}true" editorType="image"> <inplaceEditingConfig jcr:primaryType="nt:unstructured"> <plugins jcr:primaryType="nt:unstructured"> <crop jcr:primaryType="nt:unstructured" supportedMimeTypes="[image/jpeg,image/png,image/webp,image/tiff]" features="*"> <aspectRatios jcr:primaryType="nt:unstructured"> <wideLandscape jcr:primaryType="nt:unstructured" name="Wide Landscape" ratio="0.6180"/> <landscape jcr:primaryType="nt:unstructured" name="Landscape" ratio="0.8284"/> <square jcr:primaryType="nt:unstructured" name="Square" ratio="1"/> <portrait jcr:primaryType="nt:unstructured" name="Portrait" ratio="1.6180"/> </aspectRatios> </crop> <flip jcr:primaryType="nt:unstructured" supportedMimeTypes="[image/jpeg,image/png,image/webp,image/tiff]" features="-"/> <map jcr:primaryType="nt:unstructured" supportedMimeTypes="[image/jpeg,image/png,image/webp,image/tiff,image/svg+xml]" features="*"/> <rotate jcr:primaryType="nt:unstructured" supportedMimeTypes="[image/jpeg,image/png,image/webp,image/tiff]" features="*"/> <zoom jcr:primaryType="nt:unstructured" supportedMimeTypes="[image/jpeg,image/png,image/webp,image/tiff]" features="*"/> </plugins> <ui jcr:primaryType="nt:unstructured"> <inline jcr:primaryType="nt:unstructured" toolbar="[crop#launch,rotate#right,history#undo,history#redo,fullscreen#fullscreen,control#close,control#finish]"> <replacementToolbars jcr:primaryType="nt:unstructured" crop="[crop#identifier,crop#unlaunch,crop#confirm]"/> </inline> <fullscreen jcr:primaryType="nt:unstructured"> <toolbar jcr:primaryType="nt:unstructured" left="[crop#launchwithratio,rotate#right,flip#horizontal,flip#vertical,zoom#reset100,zoom#popupslider]" right="[history#undo,history#redo,fullscreen#fullscreenexit]"/> <replacementToolbars jcr:primaryType="nt:unstructured"> <crop jcr:primaryType="nt:unstructured" left="[crop#identifier]" right="[crop#unlaunch,crop#confirm]"/> <map jcr:primaryType="nt:unstructured" left="[map#rectangle,map#circle,map#polygon]" right="[map#unlaunch,map#confirm]"/> </replacementToolbars> </fullscreen> </ui> </inplaceEditingConfig> </cq:inplaceEditing> </jcr:root>
-
파일의 고유한 측면은
<parameters>
resourceType을 로 설정하는 노드wknd-spa-react/components/banner
.code language-xml <parameters jcr:primaryType="nt:unstructured" sling:resourceType="wknd-spa-react/components/banner" imageCrop="" imageMap="" imageRotate=""/>
대부분의 구성 요소에는
_cq_editConfig
. 이미지 구성 요소와 하위 항목은 예외입니다.
대화 상자 확장 extend-dialog
당사 Banner
구성 요소를 캡처하려면 대화 상자에 추가 텍스트 필드가 필요합니다. bannerText
. Sling 상속을 사용하고 있으므로 의 기능을 사용할 수 있습니다. Sling 리소스 병합 를 클릭하여 대화 상자의 일부를 재정의하거나 확장합니다. 이 샘플에서는 작성자의 추가 데이터를 캡처하여 카드 구성 요소를 채우기 위한 새 탭이 대화 상자에 추가되었습니다.
-
다음에서
ui.apps
모듈, 아래banner
폴더, 다음 이름의 폴더 만들기_cq_dialog
. -
아래에
_cq_dialog
대화 상자 정의 파일 만들기.content.xml
. 다음을 사용하여 채웁니다.code language-xml <?xml version="1.0" encoding="UTF-8"?> <jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:granite="http://www.adobe.com/jcr/granite/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0" jcr:primaryType="nt:unstructured" jcr:title="Banner" sling:resourceType="cq/gui/components/authoring/dialog"> <content jcr:primaryType="nt:unstructured"> <items jcr:primaryType="nt:unstructured"> <tabs jcr:primaryType="nt:unstructured"> <items jcr:primaryType="nt:unstructured"> <text jcr:primaryType="nt:unstructured" jcr:title="Text" sling:orderBefore="asset" sling:resourceType="granite/ui/components/coral/foundation/container" margin="{Boolean}true"> <items jcr:primaryType="nt:unstructured"> <columns jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/fixedcolumns" margin="{Boolean}true"> <items jcr:primaryType="nt:unstructured"> <column jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/container"> <items jcr:primaryType="nt:unstructured"> <textGroup granite:hide="${cqDesign.titleHidden}" jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/well"> <items jcr:primaryType="nt:unstructured"> <bannerText jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/form/textfield" fieldDescription="Text to display on top of the banner." fieldLabel="Banner Text" name="./bannerText"/> </items> </textGroup> </items> </column> </items> </columns> </items> </text> </items> </tabs> </items> </content> </jcr:root>
위의 XML 정의에서는 이름이 인 새 탭을 만듭니다. 텍스트 주문하기 다음 이전 기존 자산 탭. 단일 필드가 포함됩니다. 배너 텍스트.
-
대화 상자는 다음과 같이 표시됩니다.
에 대한 탭을 정의할 필요가 없었는지 확인합니다. 자산 또는 메타데이터. 다음을 통해 상속됩니다.
sling:resourceSuperType
속성.대화 상자를 미리 보려면 먼저 SPA 구성 요소 및
MapTo
함수.
SPA 구성 요소 구현 implement-spa-component
SPA 편집기와 함께 배너 구성 요소를 사용하려면 매핑할 새 SPA 구성 요소를 만들어야 합니다 wknd-spa-react/components/banner
. 이 작업은 다음에서 수행됩니다. ui.frontend
모듈.
-
다음에서
ui.frontend
모듈 새 폴더 만들기Banner
위치:ui.frontend/src/components/Banner
. -
이름이 인 새 파일 만들기
Banner.js
아래에Banner
폴더를 삭제합니다. 다음을 사용하여 채웁니다.code language-js import React, {Component} from 'react'; import {MapTo} from '@adobe/aem-react-editable-components'; export const BannerEditConfig = { emptyLabel: 'Banner', isEmpty: function(props) { return !props || !props.src || props.src.trim().length < 1; } }; export default class Banner extends Component { get content() { return <img className="Image-src" src={this.props.src} alt={this.props.alt} title={this.props.title ? this.props.title : this.props.alt} />; } // display our custom bannerText property! get bannerText() { if(this.props.bannerText) { return <h4>{this.props.bannerText}</h4>; } return null; } render() { if (BannerEditConfig.isEmpty(this.props)) { return null; } return ( <div className="Banner"> {this.bannerText} <div className="BannerImage">{this.content}</div> </div> ); } } MapTo('wknd-spa-react/components/banner')(Banner, BannerEditConfig);
이 SPA 구성 요소는 AEM 구성 요소에 매핑됩니다.
wknd-spa-react/components/banner
이(가) 이전에 만들어졌습니다. -
업데이트
import-components.js
위치:ui.frontend/src/components/import-components.js
새 항목 포함Banner
SPA 구성 요소:code language-diff import './ExperienceFragment/ExperienceFragment'; import './OpenWeather/OpenWeather'; + import './Banner/Banner';
-
이 시점에서 프로젝트를 AEM에 배포하고 대화 상자를 테스트할 수 있습니다. Maven 기술을 사용하여 프로젝트를 배포합니다.
code language-shell $ cd aem-guides-wknd-spa.react $ mvn clean install -PautoInstallSinglePackage
-
SPA 템플릿의 정책을 업데이트하여 추가
Banner
구성 요소를 로 허용된 구성 요소. -
SPA 페이지로 이동하고
Banner
구성 요소를 SPA 페이지 중 하나로 만듭니다.note note NOTE 대화 상자에서에 대한 값을 저장할 수 있습니다. 배너 텍스트 그러나 이 값은 SPA 구성 요소에 반영되지 않습니다. 활성화하려면 구성 요소에 대한 슬링 모델 을 확장해야 합니다.
Java 인터페이스 추가 java-interface
궁극적으로 구성 요소 대화 상자의 값을 React 구성 요소에 노출하려면 의 JSON을 채우는 Sling 모델을 업데이트해야 합니다. Banner
구성 요소. 이 작업은 다음에서 수행됩니다. core
SPA 프로젝트에 대한 모든 Java 코드를 포함하는 모듈입니다.
먼저 용 새 Java 인터페이스를 만듭니다. Banner
를 확장합니다. Image
Java 인터페이스.
-
다음에서
core
모듈 이름이 인 새 파일 만들기BannerModel.java
위치:core/src/main/java/com/adobe/aem/guides/wkndspa/react/core/models
. -
채우기
BannerModel.java
다음을 사용하여:code language-java package com.adobe.aem.guides.wkndspa.react.core.models; import com.adobe.cq.wcm.core.components.models.Image; import org.osgi.annotation.versioning.ProviderType; @ProviderType public interface BannerModel extends Image { public String getBannerText(); }
핵심 구성 요소에서 모든 메서드를 상속합니다.
Image
인터페이스 및 새 메서드 추가getBannerText()
.
Sling 모델 구현 sling-model
그런 다음 Sling 모델 을 BannerModel
인터페이스.
-
다음에서
core
모듈 이름이 인 새 파일 만들기BannerModelImpl.java
위치:core/src/main/java/com/adobe/aem/guides/wkndspa/react/core/models/impl
. -
채우기
BannerModelImpl.java
다음을 사용하여:code language-java package com.adobe.aem.guides.wkndspa.react.core.models.impl; import com.adobe.aem.guides.wkndspa.react.core.models.BannerModel; import com.adobe.cq.export.json.ComponentExporter; import com.adobe.cq.export.json.ExporterConstants; import com.adobe.cq.wcm.core.components.models.Image; import org.apache.sling.models.annotations.*; import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.models.annotations.Model; import org.apache.sling.models.annotations.injectorspecific.Self; import org.apache.sling.models.annotations.injectorspecific.ValueMapValue; import org.apache.sling.models.annotations.via.ResourceSuperType; @Model( adaptables = SlingHttpServletRequest.class, adapters = { BannerModel.class,ComponentExporter.class}, resourceType = BannerModelImpl.RESOURCE_TYPE, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL ) @Exporter(name = ExporterConstants.SLING_MODEL_EXPORTER_NAME, extensions = ExporterConstants.SLING_MODEL_EXTENSION) public class BannerModelImpl implements BannerModel { // points to the the component resource path in ui.apps static final String RESOURCE_TYPE = "wknd-spa-react/components/banner"; @Self private SlingHttpServletRequest request; // With sling inheritance (sling:resourceSuperType) we can adapt the current resource to the Image class // this allows us to re-use all of the functionality of the Image class, without having to implement it ourself // see https://github.com/adobe/aem-core-wcm-components/wiki/Delegation-Pattern-for-Sling-Models @Self @Via(type = ResourceSuperType.class) private Image image; // map the property saved by the dialog to a variable named `bannerText` @ValueMapValue private String bannerText; // public getter to expose the value of `bannerText` via the Sling Model and JSON output @Override public String getBannerText() { return bannerText; } // Re-use the Image class for all other methods: @Override public String getSrc() { return null != image ? image.getSrc() : null; } @Override public String getAlt() { return null != image ? image.getAlt() : null; } @Override public String getTitle() { return null != image ? image.getTitle() : null; } // method required by `ComponentExporter` interface // exposes a JSON property named `:type` with a value of `wknd-spa-react/components/banner` // required to map the JSON export to the SPA component props via the `MapTo` @Override public String getExportedType() { return BannerModelImpl.RESOURCE_TYPE; } }
의 사용에 주목하십시오.
@Model
및@Exporter
슬링 모델 익스포터를 통해 슬링 모델을 JSON으로 일련화할 수 있도록 하는 주석입니다.BannerModelImpl.java
를 사용합니다. Sling 모델의 전달 패턴 이미지 핵심 구성 요소에서 모든 논리를 다시 작성하지 않도록 합니다. -
다음 행을 검토하십시오.
code language-java @Self @Via(type = ResourceSuperType.class) private Image image;
위의 주석은 이라는 이미지 개체를 인스턴스화합니다.
image
를 기반으로 함sling:resourceSuperType
상속Banner
구성 요소.code language-java @Override public String getSrc() { return null != image ? image.getSrc() : null; }
그런 다음 를 간단하게 사용할 수 있습니다.
image
로 정의된 메서드를 구현할 개체Image
직접 논리를 작성하지 않고도 인터페이스를 사용할 수 있습니다. 이 기법은 다음 용도로 사용됩니다.getSrc()
,getAlt()
및getTitle()
. -
터미널 창을 열고 업데이트에 대한
core
Maven을 사용한 모듈autoInstallBundle
프로필의core
디렉토리.code language-shell $ cd core/ $ mvn clean install -PautoInstallBundle
결합하기 put-together
-
AEMSPA 으로 돌아가서
Banner
구성 요소. -
업데이트
Banner
포함할 구성 요소 배너 텍스트: -
구성 요소를 이미지로 채웁니다.
대화 상자 업데이트를 저장합니다.
-
이제 의 렌더링된 값이 표시됩니다. 배너 텍스트:
-
다음 위치에서 JSON 모델 응답을 봅니다. http://localhost:4502/content/wknd-spa-react/us/en.model.json 및 검색
wknd-spa-react/components/card
:code language-json "banner": { "bannerText": "My Banner Text", "src": "/content/wknd-spa-react/us/en/home/_jcr_content/root/responsivegrid/banner.coreimg.jpeg/1622167884688/sport-climbing.jpeg", "alt": "alt banner rock climber", ":type": "wknd-spa-react/components/banner" },
JSON 모델은에서 Sling 모델을 구현한 후 추가 키/값 쌍으로 업데이트됩니다
BannerModelImpl.java
.
축하합니다! congratulations
축하합니다. 를 사용하여 AEM 구성 요소를 확장하는 방법과 Sling 모델 및 대화 상자가 JSON 모델과 함께 작동하는 방법을 배웠습니다.