建立自訂天氣元件 custom-component
瞭解如何建立要與AEM SPA編輯器搭配使用的自訂天氣元件。 瞭解如何開發作者對話方塊和Sling模型,以擴充JSON模型來填入自訂元件。 已使用Open Weather API和React Open Weather元件。
目標
- 瞭解Sling模型在操控AEM提供的JSON模型API方面的作用。
- 瞭解如何建立新的AEM元件對話方塊。
- 瞭解如何建立與SPA編輯器架構相容的 自訂 AEM元件。
您將建置的內容
建置簡單的天氣元件。 此元件可供內容作者新增至SPA。 利用AEM對話方塊,作者可以設定天氣的顯示位置。 此元件的實作說明建立與AEM SPA Editor架構相容的淨新AEM元件所需的步驟。
先決條件
檢閱設定本機開發環境所需的工具和指示。 本章是導覽及路由章節的延續,但您只需要將已啟用SPA的AEM專案部署到本機AEM執行個體即可。
開放氣象API金鑰
需要來自Open Weather的API金鑰以及教學課程。 免費註冊有限數量的API呼叫。
定義AEM元件
AEM元件定義為節點和屬性。 在專案中,這些節點和屬性在ui.apps
模組中表示為XML檔案。 接下來,在ui.apps
模組中建立AEM元件。
-
在您選擇的IDE中,開啟
ui.apps
資料夾。 -
瀏覽至
ui.apps/src/main/content/jcr_root/apps/wknd-spa-react/components
並建立名為open-weather
的新資料夾。 -
在
open-weather
資料夾下建立名為.content.xml
的新檔案。 以下列專案填入open-weather/.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="Open Weather" componentGroup="WKND SPA React - Content"/>
jcr:primaryType="cq:Component"
— 識別此節點是AEM元件。jcr:title
是顯示給內容作者的值,且componentGroup
會決定編寫UI中的元件分組。 -
在
custom-component
資料夾下,建立另一個名為_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="Open Weather" sling:resourceType="cq/gui/components/authoring/dialog"> <content jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/container"> <items jcr:primaryType="nt:unstructured"> <tabs jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/tabs" maximized="{Boolean}true"> <items jcr:primaryType="nt:unstructured"> <properties jcr:primaryType="nt:unstructured" jcr:title="Properties" 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"> <label jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/form/textfield" fieldDescription="The label to display for the component" fieldLabel="Label" name="./label"/> <lat jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/form/numberfield" fieldDescription="The latitude of the location." fieldLabel="Latitude" step="any" name="./lat" /> <lon jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/form/numberfield" fieldDescription="The longitude of the location." fieldLabel="Longitude" step="any" name="./lon"/> </items> </column> </items> </columns> </items> </properties> </items> </tabs> </items> </content> </jcr:root>
上述XML檔案為
Weather Component
產生非常簡單的對話方塊。 檔案的重要部分是內部<label>
、<lat>
和<lon>
節點。 此對話方塊包含兩個numberfield
和一個textfield
,可讓使用者設定要顯示的天氣。已建立Sling模型,以透過JSON模型公開
label
、lat
和long
屬性的值。note note NOTE 您可以檢視核心元件定義🔗,以檢視更多對話方塊範例。 您也可以檢視CRXDE-Lite中 /libs/granite/ui/components/coral/foundation/form
下方可用的其他表單欄位,例如select
、textarea
、pathfield
。使用傳統AEM元件時,通常需要HTL指令碼。 由於SPA將會轉譯元件,因此不需要HTL指令碼。
建立Sling模型
Sling模型是註釋驅動的Java「POJO」(純舊的Java物件),可方便將資料從JCR對應至Java變數。 Sling模型通常可封裝AEM元件的複雜伺服器端商業邏輯。
在SPA編輯器的內容中,Sling模型會使用Sling模型匯出工具,透過功能透過JSON模型公開元件的內容。
-
在您選擇的IDE中,開啟位於
aem-guides-wknd-spa.react/core
的core
模組。 -
在
core/src/main/java/com/adobe/aem/guides/wkndspa/react/core/models
的OpenWeatherModel.java
處建立名為的檔案。 -
以下列專案填入
OpenWeatherModel.java
:code language-java package com.adobe.aem.guides.wkndspa.react.core.models; import com.adobe.cq.export.json.ComponentExporter; // Sling Models intended to be used with SPA Editor must extend ComponentExporter interface public interface OpenWeatherModel extends ComponentExporter { public String getLabel(); public double getLat(); public double getLon(); }
這是元件的Java介面。 為了讓Sling模型與SPA Editor架構相容,它必須擴充
ComponentExporter
類別。 -
在
core/src/main/java/com/adobe/aem/guides/wkndspa/react/core/models
下建立名為impl
的資料夾。 -
在
impl
下建立名為OpenWeatherModelImpl.java
的檔案,並填入下列專案:code language-java package com.adobe.aem.guides.wkndspa.react.core.models.impl; import org.apache.sling.models.annotations.*; import org.apache.sling.models.annotations.injectorspecific.ValueMapValue; import com.adobe.cq.export.json.ComponentExporter; import com.adobe.cq.export.json.ExporterConstants; import org.apache.commons.lang3.StringUtils; import org.apache.sling.api.SlingHttpServletRequest; import com.adobe.aem.guides.wkndspa.react.core.models.OpenWeatherModel; // Sling Model annotation @Model( adaptables = SlingHttpServletRequest.class, adapters = { OpenWeatherModel.class, ComponentExporter.class }, resourceType = OpenWeatherModelImpl.RESOURCE_TYPE, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL ) @Exporter( //Exporter annotation that serializes the modoel as JSON name = ExporterConstants.SLING_MODEL_EXPORTER_NAME, extensions = ExporterConstants.SLING_MODEL_EXTENSION ) public class OpenWeatherModelImpl implements OpenWeatherModel { @ValueMapValue private String label; //maps variable to jcr property named "label" persisted by Dialog @ValueMapValue private double lat; //maps variable to jcr property named "lat" @ValueMapValue private double lon; //maps variable to jcr property named "lon" // points to AEM component definition in ui.apps static final String RESOURCE_TYPE = "wknd-spa-react/components/open-weather"; // public getter method to expose value of private variable `label` // adds additional logic to default the label to "(Default)" if not set. @Override public String getLabel() { return StringUtils.isNotBlank(label) ? label : "(Default)"; } // public getter method to expose value of private variable `lat` @Override public double getLat() { return lat; } // public getter method to expose value of private variable `lon` @Override public double getLon() { return lon; } // method required by `ComponentExporter` interface // exposes a JSON property named `:type` with a value of `wknd-spa-react/components/open-weather` // required to map the JSON export to the SPA component props via the `MapTo` @Override public String getExportedType() { return OpenWeatherModelImpl.RESOURCE_TYPE; } }
靜態變數
RESOURCE_TYPE
必須指向元件ui.apps
中的路徑。getExportedType()
是用來透過MapTo
將JSON屬性對應至SPA元件。@ValueMapValue
是讀取對話方塊儲存之jcr屬性的註解。
更新SPA
接下來,更新React程式碼以包含React Open Weather元件,並使其對應至在先前步驟中建立的AEM元件。
-
將React Open Weather元件安裝為 npm 相依性:
code language-shell $ cd aem-guides-wknd-spa.react/ui.frontend $ npm i react-open-weather
-
在
ui.frontend/src/components/OpenWeather
建立名為OpenWeather
的新資料夾。 -
新增名為
OpenWeather.js
的檔案,並填入下列內容:code language-js import React from 'react'; import {MapTo} from '@adobe/aem-react-editable-components'; import ReactWeather, { useOpenWeather } from 'react-open-weather'; // Open weather API Key // For simplicity it is hard coded in the file, ideally this is extracted in to an environment variable const API_KEY = 'YOUR_API_KEY'; // Logic to render placeholder or component const OpenWeatherEditConfig = { emptyLabel: 'Weather', isEmpty: function(props) { return !props || !props.lat || !props.lon || !props.label; } }; // Wrapper function that includes react-open-weather component function ReactWeatherWrapper(props) { const { data, isLoading, errorMessage } = useOpenWeather({ key: API_KEY, lat: props.lat, // passed in from AEM JSON lon: props.lon, // passed in from AEM JSON lang: 'en', unit: 'imperial', // values are (metric, standard, imperial) }); return ( <div className="cmp-open-weather"> <ReactWeather isLoading={isLoading} errorMessage={errorMessage} data={data} lang="en" locationLabel={props.label} // passed in from AEM JSON unitsLabels={{ temperature: 'F', windSpeed: 'mph' }} showForecast={false} /> </div> ); } export default function OpenWeather(props) { // render nothing if component not configured if (OpenWeatherEditConfig.isEmpty(props)) { return null; } // render ReactWeather component if component configured // pass props to ReactWeatherWrapper. These props include the mapped properties from AEM JSON return ReactWeatherWrapper(props); } // Map OpenWeather to AEM component MapTo('wknd-spa-react/components/open-weather')(OpenWeather, OpenWeatherEditConfig);
-
在
ui.frontend/src/components/import-components.js
更新import-components.js
以包含OpenWeather
元件:code language-diff // import-component.js import './Container/Container'; import './ExperienceFragment/ExperienceFragment'; + import './OpenWeather/OpenWeather';
-
使用您的Maven技能,從專案目錄的根將所有更新部署至本機AEM環境:
code language-shell $ cd aem-guides-wknd-spa.react $ mvn clean install -PautoInstallSinglePackage
更新範本原則
接下來,導覽至AEM以驗證更新,並允許將OpenWeather
元件新增至SPA。
-
請瀏覽至http://localhost:4502/system/console/status-slingmodels,以驗證新Sling模型的註冊。
code language-plain com.adobe.aem.guides.wkndspa.react.core.models.impl.OpenWeatherModelImpl - wknd-spa-react/components/open-weather com.adobe.aem.guides.wkndspa.react.core.models.impl.OpenWeatherModelImpl exports 'wknd-spa-react/components/open-weather' with selector 'model' and extension '[Ljava.lang.String;@2fd80fc5' with exporter 'jackson'
您應該會看到以上兩行,指出
OpenWeatherModelImpl
與wknd-spa-react/components/open-weather
元件相關聯,並已透過Sling模型匯出工具註冊。 -
更新配置容器的原則以將新的
Open Weather
新增為允許的元件:儲存原則的變更,並將
Open Weather
視為允許的元件:
編寫開啟的天氣元件
接下來,使用AEM SPA編輯器編寫Open Weather
元件。
-
導覽至http://localhost:4502/editor.html/content/wknd-spa-react/us/en/home.html。
-
在
Edit
模式中,將Open Weather
新增至Layout Container
: -
開啟元件的對話方塊並輸入 標籤、緯度 和 經度。 例如 聖地亞哥、32.7157 和 -117.1611。 西半球和南半球的數字會使用Open Weather API以負數表示
這是根據章節中先前的XML檔案建立的對話方塊。
-
儲存變更。 請注意,San Diego 的天氣現在已顯示:
-
導覽至http://localhost:4502/content/wknd-spa-react/us/en.model.json以檢視JSON模型。 搜尋
wknd-spa-react/components/open-weather
:code language-json "open_weather": { "label": "San Diego", "lat": 32.7157, "lon": -117.1611, ":type": "wknd-spa-react/components/open-weather" }
Sling模型會輸出JSON值。 這些JSON值會作為prop傳遞至React元件。
恭喜! congratulations
恭喜,您已瞭解如何建立要與AEM編輯器搭配使用的自訂SPA元件。 您也學習了對話方塊、JCR屬性和Sling模型如何互動以輸出JSON模型。
後續步驟 next-steps
擴充核心元件 — 瞭解如何擴充要與AEM SPA編輯器搭配使用的現有AEM核心元件。 瞭解如何將屬性和內容新增至現有元件,是擴充AEM SPA Editor實作功能的強大技術。