Sie sehen sich Hilfeinhalte der folgenden Version an:

Single Page Applications (SPAs) können ansprechende Erlebnisse für Website-Benutzer bieten. Entwickler möchten in der Lage sein, Websites mithilfe von SPA-Frameworks zu erstellen, und Autoren möchten Inhalte innerhalb von AEM für eine Website, die mit SPA-Frameworks erstellt wurde, nahtlos bearbeiten.

Die SPA-Erstellungsfunktion bietet eine umfassende Lösung zur Unterstützung von SPAs in AEM. Dieser Artikel beschreibt eine Beispiel-SPA, erläutert, wie sie zusammengestellt wird, und ermöglicht es Ihnen, schnell mit Ihrer eigenen SPA zu arbeiten.

Vorsicht:

Die Editor-Funktion für Single Page Applications (SPAs) wurde mit AEM 6.4 eingeführt und ist derzeit als Technologievorschau verfügbar. Der SPA-Editor wird separat zum AEM-Schnellstart im nächsten Service Pack für AEM 6.3 und 6.4 bereitgestellt.

  • Diese Funktion befindet sich noch in der Entwicklung und die Dokumentation kann jederzeit geändert werden.
  • Der SPA-Editor ist die empfohlene Lösung für Projekte, bei denen ein SPA-Framework basierend auf clientseitigem Rendering (z. B. React) erforderlich ist.

Einführung

Dieser Artikel fasst die grundlegenden Funktionen einer einfachen SPA und die Grundlagen zusammen, die Sie für deren Nutzung benötigen.

Weitere Details zur Funktionsweise von SPAs in AEM finden Sie in den folgenden Dokumenten:

Hinweis:

Um Inhalt in einer SPA zu erstellen, muss der Inhalt in AEM gespeichert und durch das Inhaltsmodell verfügbar gemacht werden.

Eine SPA, die außerhalb von AEM entwickelt wurde, wird nicht autorisiert, wenn der Content-Modell-Vertrag nicht eingehalten wird.

Dieses Dokument erläutert die Struktur dieser Beispiel-SPA und veranschaulicht ihre Funktionsweise, sodass Sie diese Informationen in Ihrer eigenen SPA anwenden können.

Abhängigkeiten, Konfiguration und Aufbau

Zusätzlich zur erwarteten React-Abhängigkeit kann die Beispiel-SPA zusätzliche Bibliotheken nutzen, um die Erstellung der SPA effizienter zu gestalten.

Abhängigkeiten

Die Datei package.json definiert die Anforderungen des gesamten SPA-Pakets und ist hier aufgelistet.

{
  "name": "react-app",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "start": "react-scripts start",
    "build": "webpack && clientlib --verbose"
  },
  "proxy": {
    "/content": {
      "target": "http://localhost:4502"
    }
  },
   "dependencies": {
    "@adobe/cq-react-editable-components": "^0.0.28",
    "react": "^16.2.0",
    "react-dom": "^16.2.0",
    "react-open-weather": "^0.3.0",
    "react-router-dom": "^4.2.2"
  },
}

Da dieses Beispiel auf dem React-Framework basiert, gibt es zwei reaktionsspezifische Abhängigkeiten, die in der Datei package.json obligatorisch sind:

"react": "^16.2.0",    
"react-dom": "^16.2.0",

Zusätzlich wird der aem-clientlib-generator genutzt, um die Erstellung von Client-Bibliotheken als Teil des Aufbauprozesses automatisch zu machen.

"aem-clientlib-generator": "^1.4.1",

Obwohl dies nicht obligatorisch ist, wird empfohlen, die Erstellung Ihrer App zu vereinfachen. Weitere Details dazu können hier auf GitHub gefunden werden.

Der aem-clientlib-generator wird in der Datei clientlib.config.js wie folgt konfiguriert.

module.exports = {
    // default working directory (can be changed per 'cwd' in every asset option)
    context: __dirname,

    // path to the clientlib root folder (output)
    clientLibRoot: "./../content/jcr_root/apps/we-retail-journal/react/clientlibs",

    libs: {
        name: "we-retail-journal-react",
        allowProxy: true,
        categories: ["we-retail-journal-react"],
        serializationFormat: "xml",
        assets: {
            js: [
                "dist/**/*.js"
            ],
            css: [
                "dist/**/*.css"
            ]
        }
    }
};

Erstellung

Bei der Erstellung der App wird neben dem aem-clientlib-generator zur automatischen Client-Bibliothekserstellung auch Webpack für die Übertragung verwendet. Daher ähnelt der Aufbaubefehl dem folgenden:

"build": "webpack && clientlib --verbose"

Sobald das Paket erstellt wurde, kann es in eine AEM-Instanz hochgeladen werden.

Beispielanwendungsstruktur

Wenn Sie die Abhängigkeiten einbeziehen und die Beispiel-SPA erstellen, erhalten Sie ein funktionierendes SPA-Paket, das Sie in Ihre AEM-Instanz hochladen können.

Im nächsten Abschnitt dieses Dokuments erfahren Sie, wie die SPA selbst strukturiert ist, welche wichtigen Dateien die Anwendung steuern und wie sie zusammenarbeiten.

Die Bildkomponente wird als Beispiel verwendet, aber alle Komponenten der Anwendung basieren auf dem gleichen Konzept.

index.js

Der Einstiegspunkt in die SPA ist natürlich die hier gezeigte Datei index.js, die sich auf den wichtigen Inhalt konzentriert.

import ReactDOM from 'react-dom';
import App from './App';

...

ReactDOM.render(<App/>, document.getElementById('page'));

...

Die Hauptfunktion von index.js ist die Verwendung der Funktion ReactDOM.render, um zu bestimmen, wo im DOM die Anwendung injiziert werden soll.

ReactDOM.render(<App/>, document.getElementById('page'));

Dies ist eine Standardnutzung dieser Funktion, die nicht nur für diese Beispielanwendung gilt.

App.js

Beim Rendern der App ruft index.js App.js auf, die hier in einer vereinfachten Version angezeigt wird, um die Erläuterung auf den wesentlichen Inhalt zu reduzieren.

import React, {Component} from 'react';
import Page from './components/Page';

...

class App extends Component {

    render() {
        return <Page/>
    }
}

export default App;

App.js dient hauptsächlich dazu, die Root-Komponenten einzuschließen, aus denen die App besteht.

Page.js

Beim Rendern der Seite ruft App.js die hier aufgelistete Page.js auf.

import React from 'react';
import { Container, withModel } from '@cq/cq-react-editable-components';

class Page extends Container {

    render() {
        let classNames = this.props.cq_model && this.props.cq_model.cssClassNames;

        return <div className={classNames}>{this.innerContent}</div>;
    }
}

export default withModel(Page);

Die Seitenklasse erweitert Container, der die internen Inhaltsmethoden enthält, die dann verwendet werden können.

Der Container nimmt die JSON-Repräsentation des Seitenmodells auf und verarbeitet den Inhalt, um jedes Element der Seite zu umhüllen/dekorieren. Weitere Details zum Container finden Sie im Dokument SPA-Blueprint.

let classNames = this.props.cq_model && this.props.cq_model.cssClassNames;

Das props-Objekt wird vom React-Framework bereitgestellt und ist in allen Komponenten verfügbar, die die API dieser Komponente darstellen.

Das cq_model-Objekt ist das Ergebnis der Umhüllung des Elements und enthält das Modell für die aktuelle Komponente.

Weitere Informationen zur Funktion withModel finden Sie im Abschnitt Beispiel-Anwendungsfälle in diesem Dokument.

Image.js

Mit der gerenderten Seite können die Komponenten wie Image.js wie hier dargestellt gerendert werden.

import React, {Component} from 'react';
import { MapTo } from '@cq/cq-react-editable-components';

require('./Image.css');

/**
 * Default Edit configuration for the Image component that interact with the Core Image component and sub-types
 *
 * @type EditConfig
 */
const ImageEditConfig = {

    dragDropName: 'image',

    emptyLabel: 'Image',

    isEmpty: function() {
        return !this.props || !this.props.cq_model || !this.props.cq_model.src || this.props.cq_model.src.trim().length < 1;
    }
};

/**
 * Expected usage of the Image Component.
 *
 * <Image
 *      cq_model='the whole Object holding information for the image from the model.json response' />
 *
 * Please see the package.json for the proxy settings.
 */
class Image extends Component {

    hasLink() {
        return this.props && this.props.cq_model && this.props.cq_model.link;
    }

    get content() {
        let alt;
        let displayPopupTitle;
        let src;
        let title;
        let id;

        if (this.props.cq_model) {
            alt = this.props.cq_model.alt;
            displayPopupTitle = this.props.cq_model.displayPopupTitle; // TODO: it is missing in the JSON
            src = this.props.cq_model.src;
            title = this.props.cq_model.title;
            id = this.props.cq_model.path.substr(this.props.cq_model.path.lastIndexOf('/')+1);
        }

        return <img id={id} src={src} alt={alt} title={displayPopupTitle && title}/>
    }

    get linkedContent() {
        let alt;
        let fileReference;
        let link;
        let title;

        if (this.props.cq_model) {
            alt = this.props.cq_model.alt;
            fileReference = this.props.cq_model.fileReference; // TODO: it is missing in the JSON
            link = this.props.cq_model.link;
            title = this.props.cq_model.title;
        }

        return <a href={link} data-title={title || alt} data-asset={fileReference}>
                {this.content}
            </a>
    }

    render() {
        let innerContent;

        if (this.hasLink()) {
            innerContent = this.linkedContent;
        } else {
            innerContent = this.content
        }

        return (<div className="cmp-image">
                {innerContent}
            </div>);
    }
}

MapTo('weretail/components/content/image')(Image, ImageEditConfig);

Die zentrale Idee von SPAs in AEM ist die Idee, SPA-Komponenten auf AEM-Komponenten abzubilden und die Komponente zu aktualisieren, wenn der Inhalt geändert wird (und umgekehrt). Sehen Sie das Dokument SPA Authoring-Einführung, um einen Überblick über dieses Kommunikationsmodell zu erhalten.

MapTo(‘weretail/components/content/image')(Image, ImageEditConfig);

Die MapTo-Methode ordnet die SPA-Komponente der AEM-Komponente zu. Es unterstützt die Verwendung einer einzelnen Zeichenfolge oder eines Arrays von Zeichenfolgen.

ImageEditConfig ist ein Konfigurationsobjekt, das dazu beiträgt, die Authoring-Funktionen einer Komponente zu aktivieren, indem die erforderlichen Metadaten bereitgestellt werden, damit der Editor Platzhalter generieren kann

Wenn kein Inhalt vorhanden ist, werden Etiketten als Platzhalter bereitgestellt, um den leeren Inhalt darzustellen.

Beispiel-Anwendungsfälle

Rendering von Teilen der Seite (statische Referenzen)

Wenn Sie die Eigenschaft path übergeben, können Sie bestimmte Teile der Seite darstellen. Dies wäre notwendig, wenn untergeordnete Elemente des Seitenmodells gezielt angesprochen werden müssen, beispielsweise wenn der Inhalt, den Sie erstellen möchten, sich zwischen anderen Inhalten befindet.

index.js wird wie folgt aussehen:

import ReactDOM from 'react-dom';
import App from './App';
import { PageModelManager } from '@cq/cq-react-editable-components';

...

PageModelManager.init().then(function() {
    ReactDOM.render(<App/>, document.getElementById('page'));
});
...

App.js wird wie folgt aussehen:

import React, {Component} from 'react';
import Page from './components/Page';
import Text from './components/Text';

...

class App extends Component {

    render() {
        return <Page cq_model_path="path/to/page1"/>
            <Text cq_model_path="path/to/text1"/>
    }
}

export default App;

Exportieren bearbeitbarer Komponenten

Sie können eine Komponente exportieren und bearbeitbar halten.

import React, { Component } from 'react';
import { MapTo } from '@cq/cq-react-editable-components';

...

const EditConfig = {...}

class PageClass extends Component {...};

...

export default MapTo('we-retail-journal/react/components/structure/page')(PageClass, EditConfig);

Die Funktion MapTo gibt eine Komponente zurück, die das Ergebnis einer Komposition ist, die die bereitgestellte PageClass mit den Klassennamen und Attributen erweitert, die das Authoring ermöglichen. Diese Komponente kann exportiert werden, um später im Markup Ihrer Anwendung instanziiert zu werden.

Beim Exportieren mithilfe der Funktionen MapTo oder withModel wird die Komponente Page mit einer ModelProvider-Komponente umschlossen, die Standardkomponenten Zugriff auf die neueste Version des Seitenmodells oder eine genaue Position in diesem Seitenmodell bietet.

Weitere Informationen finden Sie im Dokument SPA-Blueprint.

Hinweis:

Standardmäßig erhalten Sie das gesamte Modell der Komponente, wenn Sie die Funktion withModel verwenden.

Dieses Werk unterliegt den Bedingungen der Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License.  Twitter™- und Facebook-Beiträge fallen nicht unter die Bedingungen der Creative Commons-Lizenz.

Rechtliche Hinweise   |   Online-Datenschutzrichtlinie