React: Wie ersetzt man Teile eines Strings durch eine Komponente?

Erstellt am 12. März 2015  ·  40Kommentare  ·  Quelle: facebook/react

Ich habe diesen Code, der offensichtlich nicht funktioniert:

    _.each(matches, (match) ->
      string = string.replace(match, ->
        <span className="match" key={i++}>{match}</span>
      )
    )

Denn das würde zu einer mit Objekten vermischten Schnur führen. Schlecht ich weiß. Aber wie kann ich React-Komponenten innerhalb eines Strings hinzufügen? Alles, was ich möchte, ist, Teile eines Strings mit einer Reaktionskomponente hervorzuheben. Ein schwer zu knackender Fall, denke ich.

Hilfreichster Kommentar

Sie können die Funktion split mit einer Regex verwenden und dann die erfassten Teile wie folgt ersetzen:

var parts = "I am a cow; cows say moo. MOOOOO.".split(/(\bmoo+\b)/gi);
for (var i = 1; i < parts.length; i += 2) {
  parts[i] = <span className="match" key={i}>{parts[i]}</span>;
}
return <div>{parts}</div>;

Lass es mich wissen, wenn das unklar ist.

Alle 40 Kommentare

sowas sollte funktionieren:

const escapeRE = new RegExp(/([.*+?^=!:$(){}|[\]\/\\])/g)
const safeRE = (string) => {
  return string.replace(escapeRE, "\\$1")
}

class Hightlight extends Component {
  static propTypes = {
    match : PropTypes.string,
    string : PropTypes.string,
  }

  render() {
    return (
      <span
        dangerouslySetInnerHTML={{
          __html : string.replace(safeRE(this.props.match), "<strong className\"match\">$1</strong>")
        }} />
    )
  }
}

Ja, ich habe darüber nachgedacht, dangerouslySetInnerHTML missbrauchen, aber ich mag diese Idee nicht. Diese Methode wird aus guten Gründen als gefährlich bezeichnet.

Gibt es keine Möglichkeit, React beizubringen, jsx innerhalb einer Zeichenfolge zu analysieren? Lassen Sie React analysieren iE

var example = "this one word <span className="match" key={i++}>hello</span> is highlighted"

und dies in einer Render-Methode zurückgeben?

@binarykitchen Sie können React-Elemente dynamisch konstruieren und das müssen Sie hier tun, Sie können dies einfach nicht nur mit dem Ersetzen von Zeichenfolgen tun.

@syranide Ja, das weiß ich schon. Mein Punkt ist: Wäre dies nicht eine nette JSX/React-Funktion? Analysieren Sie einen String und verwandeln Sie alle darin enthaltenen Tags in untergeordnete React-Komponenten.

Sie können die Funktion split mit einer Regex verwenden und dann die erfassten Teile wie folgt ersetzen:

var parts = "I am a cow; cows say moo. MOOOOO.".split(/(\bmoo+\b)/gi);
for (var i = 1; i < parts.length; i += 2) {
  parts[i] = <span className="match" key={i}>{parts[i]}</span>;
}
return <div>{parts}</div>;

Lass es mich wissen, wenn das unklar ist.

Das Parsen von JSX zur Laufzeit ist fehleranfällig und langsam und kann leicht Auswirkungen auf die Sicherheit haben – es wäre von Natur aus nicht sicherer als SetInnerHTML gefährlich ist.

das kann bei Schriftkasten ein kleines Problem sein

— mlb

Am 12. März 2015 um 21:37 Uhr schrieb Ben Alpert [email protected] :

Sie können die Split-Funktion mit einer Regex verwenden und dann die erfassten Teile wie folgt ersetzen:

var parts = "Ich bin eine Kuh; Kühe sagen Muh. MOOOOO.".split(/(\bmoo+\b)/gi);
für (var i = 1; i < Teilelänge; i += 2) {
Teile[i] = ;}Rückkehr

{Teile}
;
Lass es mich wissen, wenn das unklar ist.


Antworten Sie direkt auf diese E-Mail oder zeigen Sie sie auf GitHub an.

Ich bin auch auf dieses Problem gestoßen, als ich versuchte, Teile einer Zeichenfolge programmgesteuert hervorzuheben (dh durch <span> Tags zu ersetzen). Am Ende habe ich ein Modul erstellt, das auf der @spicyj basiert. Für alle Interessierten: iansinnott/react-string-replace

@iansinnott Danke, dass String.prototype.replace API brauche (benötigte Zugriff auf die einzelnen übereinstimmenden Gruppen für einen Regexp innerhalb der Ersetzungsfunktion). Mir wurde klar, dass die Änderung mehr als ein einfacher Patch sein wird (und eine API-Änderung erfordert), also habe ich ein neues Repo erstellt: https://github.com/oztune/string-replace-to-array

Wenn react-string-replace nicht Ihren Anforderungen entspricht:

https://github.com/EfogDev/react-process-string

Folgendes funktionierte für mich, um Schlüsselwörter innerhalb einer Textfolge hervorzuheben, ohne
gefährliches Setzen von HTML:

/**
 * Find and highlight relevant keywords within a block of text
 * <strong i="7">@param</strong>  {string} label - The text to parse
 * <strong i="8">@param</strong>  {string} value - The search keyword to highlight
 * <strong i="9">@return</strong> {object} A JSX object containing an array of alternating strings and JSX
 */
const formatLabel = (label, value) => {
  if (!value) {
    return label;
  }
  return (<span>
    { label.split(value)
      .reduce((prev, current, i) => {
        if (!i) {
          return [current];
        }
        return prev.concat(<b key={value + current}>{ value }</b>, current);
      }, [])
    }
  </span>);
};

formatLabel('Lorem ipsum dolor sit amet', 'dolor');
// <span>Lorem ipsum <b>dolor</b> sit amet</span>

Ich brauchte so etwas für Erwähnungen, die mit einem Muster übereinstimmen, damit mehrere Werte eingeschlossen werden können, und ich habe einige Änderungen an der

/**
 * Find and highlight mention given a matching pattern within a block of text
 * <strong i="7">@param</strong> {string} text - The text to parse
 * <strong i="8">@param</strong> {array} values - Values to highlight
 * <strong i="9">@param</strong> {RegExp} regex - The search pattern to highlight 
 * <strong i="10">@return</strong> {object} A JSX object containing an array of alternating strings and JSX
 */
const formatMentionText = (text, values, regex) => { 
    if (!values.length)
        return text;

    return (<div>
        {text.split(regex)
            .reduce((prev, current, i) => {
                if (!i)
                    return [current];

                return prev.concat(
                    values.includes(current)  ?
                        <mark key={i + current}>
                            {current}
                        </mark>
                        : current
                );
            }, [])}
    </div>);
};

const text = 'Lorem ipsum dolor sit amet [[Jonh Doe]] and [[Jane Doe]]';
const values = ['Jonh Doe', 'Jane Doe'];
const reg = new RegExp(/\[\[(.*?)\]\]/); // Match text inside two square brackets

formatMentionText(text, values, reg);
// Lorem ipsum dolor sit amet <mark>Jonh Doe</mark> and <mark>Jane Doe</mark>

Ich hatte ein ähnliches Problem und habe es mit Reaktionsportalen gelöst. Um den Knoten leicht zu finden, habe ich die Zeichenfolge durch ein div ersetzt und meine Reaktionskomponente mit createPortal in dieses Div gerendert.

@rmtngh Ich bin neugierig, warum Sie das tun müssen. Es scheint, als wäre es übertrieben. Verschachteln Sie nicht reagierenden Code?

In Bezug auf Lösungen für dieses Problem möchte ich string-replace-to-array (ich bin der Autor) empfehlen. Es wurde in mehreren Umgebungen kampf- und zeiterprobt. Es ist auch ziemlich klein (die gesamte Bibliothek ist diese Datei https://github.com/oztune/string-replace-to-array/blob/master/string-replace-to-array.js).

Hier ist ein Anwendungsbeispiel mit Regex:

import replace from 'string-replace-to-array'

// The API is designed to match the native 'String.replace',
// except it can handle non-string replacements.
replace(
  'Hello Hermione Granger...',
  /(Hermione) (Granger)/g,
  function (fullName, firstName, lastName, offset, string) {
    return <Person firstName={ firstName } lastName={ lastName } key={ offset } />
  }
)

// output: ['Hello ', <Person firstName="Hermione" lastName="Granger" key={ 0 } />, ...]

@oztune Vielen Dank für Ihre Antwort. In diesem Fall habe ich einen HTML-Markup-String, der von einem Wysiwyg-Editor eines CMS stammt, und ich möchte Reaktionskomponenten an bestimmten Stellen in diesem Markup platzieren.
Glauben Sie, dass es besser wäre, eine Bibliothek zu verwenden, anstatt Portale zu verwenden? Ich denke, das Portal rendert die Komponente einfach in einem anderen Knoten anstelle des nächsten Knotens, was nicht teurer wäre als das Rendern einer normalen Komponente, und der einzige zusätzliche Schritt besteht darin, die Zeichenfolge zu ersetzen, die mit nativem js replace durchgeführt werden kann.
Verpasse ich etwas? Wird es Vorteile haben, stattdessen die Bibliothek zu verwenden?

@rmtngh Ich würde sagen, es hängt davon ab, was Sie versuchen. Wenn Sie nur versuchen, einige React-Komponenten in verschiedene Bereiche Ihres DOM-Baums zu streuen und der Baum noch nicht mit React gerendert wird, sind Portale der richtige Weg. Die von mir erwähnte Methode ist am nützlichsten, wenn die Teile, die Sie ersetzen möchten, bereits in einer React-Komponente gerendert sind.

Hier ist der Code, der ein Array von Knoten mit gegebenem Text und Muster zurückgibt:

const highlightPattern = (text, pattern) => {
  const splitText = text.split(pattern);

  if (splitText.length <= 1) {
    return text;
  }

  const matches = text.match(pattern);

  return splitText.reduce((arr, element, index) => (matches[index] ? [
    ...arr,
    element,
    <mark>
      {matches[index]}
    </mark>,
  ] : [...arr, element]), []);
};

Danke @wojtekmaj
Meine Version für Gruppen im Muster:

const replacePatternToComponent = (text, pattern, Component) => {
  const splitText = text.split(pattern);
  const matches = text.match(pattern);

  if (splitText.length <= 1) {
    return text;
  }

  return splitText.reduce((arr, element) => {
      if (!element) return arr;

      if(matches.includes(element)) {
        return [...arr, Component];
      }

      return [...arr, element];
    },
    []
  );
};

const string = 'Foo [first] Bar [second]';
const pattern = /(\[first\])|(\[second\])/g;

replacePatternToComponent(string, pattern, <Component />);

Ansatz mit Typoskript:

const formatString = (
  str: string,
  formatingFunction?: (value: number | string) => React.ReactNode,
  ...values: Array<number | string>
) => {
  const templateSplit = new RegExp(/{(\d)}/g);
  const isNumber = new RegExp(/^\d+$/);
  const splitedText = str.split(templateSplit);
  return splitedText.map(sentence => {
    if (isNumber.test(sentence)) {
      const value = values[Number(sentence)];
      return Boolean(formatingFunction) ? formatingFunction(value) : value;
    }
    return sentence;
  });
};

Anwendungsbeispiel:

const str = '{0} test {1} test';
formatString(str, value => <b>{value}</b>, value1, value2);

Ergebnis:
<b>value1</b> test <b>value2</b> test

@rmtngh könnten Sie ein Beispiel dafür bereitstellen, wie Sie die Markup-Anreicherung durch createportal erreicht haben? Ich suche das gleiche zu tun.

@Dashue Die Idee ist, einige Ziele für Ihre Reaktionskomponenten in Ihrem Markup zu erstellen, abhängig vom HTML-String und wie viel Kontrolle Sie darüber haben.
Wenn Sie es serverseitig ändern können, möchten Sie möglicherweise Ihren Elementen eine ID zuweisen. Etwas wie :
<div id="component_target_1"></div>
Und im Inneren reagiere, suche nach \id="(component_target_\d)"\g mit regexp, speichere die IDs (state.targets) und rendere deine Komponenten:

let mappedComponents
if(this.state.targets && this.state.targets.length){
            mappedComponents = this.state.targets.map((id,index)=><MyComponent id={id} key={id} />)
        }

Hier ist ein Beispiel von "MyComponent":

import React from 'react'
import ReactDOM from 'react-dom'

export default class MyComponent extends React.Component {
  constructor(props) {
    super(props)
  }
  getWrapper(){
    return document.getElementById(this.props.id)
  }
  render() {
    if(!this.getWrapper()) return null

    const content = <div>
        Hello there! I'm rendered with react.
      </div>

      return ReactDOM.createPortal(
        content,
        this.getWrapper(),
      );
  }
}

Wenn Sie nicht viel Kontrolle über den HTML-String haben, können Sie immer noch den gleichen Ansatz verwenden. Möglicherweise müssen Sie einige Elemente finden und ein Zielelement in den String einfügen.

Toller Thread Jungs!

Ich habe einen einfachen React Text Highlighter- Stift erstellt, der einige der Ideen in diesem Thread umsetzt (mit etwas zusätzlicher Magie ...), hoffentlich können zukünftige Besucher ihn nützlich finden.

Hier ist eine Lösung mit map ,
Forking @sophiebits Lösung hier:

const reg = new RegExp(/(\bmoo+\b)/, 'gi');
const parts = text.split(reg);
return <div>{parts.map(part => (part.match(reg) ? <b>{part}</b> : part))}</div>;

Schöne Lösung @rehat101

Folgendes hat in meinem Fall am besten funktioniert - das Aufteilen nach dem Leerzeichen und das Suchen nach bestimmten Wörtern.

Es ist ein bisschen unordentlich im HTML, aber wen interessiert das 😂

💗 RegExp und Karte machen das soooo sauber. 💗💗💗

image

const Speech = ({ speech, speeches, setSpeeches, i, text }) => {

const highlightRegExp = new RegExp(
    /you|can|do|it|puedes|hacerlo|pingüinos|son|bellos/,
    "gi"
  );
  const delineator = " ";
  const parts = text.split(delineator);

  return (
        <div>
          {parts.map(part =>
            part.match(highlightRegExp) ? <b>{part + " "}</b> : part + " "
          )}
        </div>
  );
};

Schön @rehat101

Wenn react-string-replace nicht Ihren Anforderungen entspricht:

https://github.com/EfogDev/react-process-string

Brillant! Ich finde es äußerst nützlich, da Sie meistens tatsächlich auf die ursprüngliche Zeichenfolge zugreifen müssen

Ich habe die Lösung von @nullhook ein wenig
js const highlightQueryText = (text: string, filterValue: string) => { const reg = new RegExp(`(${filterValue})`, 'gi'); const textParts = text.split(reg); return ( <span style={{ fontWeight: 600 }}> {textParts.map(part => (part.match(reg) ? <span style={{ fontWeight: 'normal' }}>{part}</span> : part))} </span> ); };

Also habe ich eine schöne Kombination aus der Implementierung von DOMPurify gefunden, um HTML-Strings mit html-react-parser zu bereinigen, um gezieltes Markup darin zu finden und in JSX-Komponenten zu konvertieren - ich verwende Rebass mit übergebenen Requisiten als Beispiel zwei Pakete werden Ihnen helfen, den Aufwand für das Rollen Ihres eigenen Parsers zu vermeiden, ich würde dieses Parser-Paket nur ohne Bereinigung empfehlen. Für diejenigen, die damit zu kämpfen haben, sollten Sie diesen Codepen vielleicht noch auf seinen Wert prüfen: https://codesandbox.io/s/eager-wiles-5hpff. Feedback zu Verbesserungen ist ebenfalls sehr willkommen.

Hey Jesse,
Das scheint eine wirklich schöne Kombination zu sein, um Text aufzunehmen und zu transformieren
Komponenten reagieren! Es wäre auf jeden Fall gut für den Austausch von Teilen eines
String mit einer Komponente.

Danke für das Teilen.

Könnte auch in einer JAMstack-Site nützlich sein, um Markdown in Komponenten umzuwandeln.

Mit freundlichen Grüßen,
Derek

Derek R. Austin, PT, DPT, MS, BCTMB, LMT, CSCS

Begleiten Sie mich auf LinkedIn: https://www.linkedin.com/in/derek-austin/

Am Mittwoch, 26. Februar 2020, 16:35 Uhr schrieb Jesse Lewis [email protected] :

Also habe ich eine schöne Kombination aus der Implementierung von DOMPurify gefunden, um HTML zu bereinigen
Strings mit html-react-parser, um gezieltes Markup darin zu finden und zu konvertieren
zu JSX-Komponenten - ich verwende Rebass mit übergebenen Requisiten als Beispiel
kam ganz gut heraus, die beiden Pakete werden Ihnen helfen, den Overhead zu vermeiden
einen eigenen Parser zu rollen, würde ich dieses Parser-Paket einfach nicht empfehlen
ohne Desinfektion. Für diejenigen, die damit zu kämpfen haben, ist es vielleicht noch möglich
dieser Codepen für seinen Wert:
https://codesandbox.io/s/eager-wiles-5hpff. Feedback zu Verbesserungen
auch sehr geschätzt.


Sie erhalten dies, weil Sie einen Kommentar abgegeben haben.
Antworten Sie direkt auf diese E-Mail und zeigen Sie sie auf GitHub an
https://github.com/facebook/react/issues/3386?email_source=notifications&email_token=AMV42QTV4FDXZIFXCGB3NZDRE3OATA5CNFSM4A5VRBI2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHLOKTPWSHQ65-5
oder abmelden
https://github.com/notifications/unsubscribe-auth/AMV42QXARIOKOYSJ4C5IFQLRE3OATANCNFSM4A5VRBIQ
.

Sie können die Funktion split mit einer Regex verwenden und dann die erfassten Teile wie folgt ersetzen:

var parts = "I am a cow; cows say moo. MOOOOO.".split(/(\bmoo+\b)/gi);
for (var i = 1; i < parts.length; i += 2) {
  parts[i] = <span className="match" key={i}>{parts[i]}</span>;
}
return <div>{parts}</div>;

Lass es mich wissen, wenn das unklar ist.

Das funktioniert super. Gibt es eine Möglichkeit, es in Angular zum Laufen zu bringen? Ich habe eine Frage dazu gestellt, mit Ihrem Code:
https://stackoverflow.com/questions/60889171/wrap-certain-words-with-a-component-in-a-contenteditable-div-in-angular

Hallo Freunde, ich brauche bitte Ihre Hilfe, ich verwende React Native und was ich tun muss, ist aus einem Text, den ich aus der DB extrahiere, um ein Format (Schriftfarbe, Link) anzuwenden , um ich in der Suche Text findet 1 einzelne Übereinstimmung macht das Ersetzen alles gut, aber! Wenn der Text mehrere @Erwähnungen enthält , wird ein Fehler

/////Textbeispiel: _hey was ist passiert @-id:1- alles ok ??
//// listusers sein Array auf, Beispiel: [idusuario: "1", usuario: "@luigbren", format: "@-id:1-"....]

const PatternToComponent = (text, usuarios,) => {
    let mentionsRegex = new RegExp(/@-(id:[0-9]+)-/, 'gim');
    let matches = text.match(mentionsRegex);
    if (matches && matches.length) {
        matches = matches.map(function (match, idx) {
            let usrTofind = matches[idx]
            //////////////////////////////////////////////////////////////////
            const mentFormat = listusers.filter(function (item) { 
                const itemData = item.format;
                return itemData.indexOf(usrTofind) > -1;
            });
            if (mentFormat.length > 0) {
                let idusuario = mentFormat[0].idusuario
                let replc = mentFormat[0].usuario

                console.log(usrTofind) //// here find @-id:1-
                console.log(replc)   //// here is <strong i="12">@luigbren</strong> for replace

                ////////// now here replace part of the string, @-id:1- with a <Text> component 
                ///////// with <strong i="13">@luigbren</strong> and the link, this is repeated for every <strong i="14">@mention</strong> found

                parts = text.split(usrTofind);
                for (var i = 1; i < parts.length; i += 2) {
                  parts[i] = <Text key={i} style={{ color: '#00F' }} onPress={() => { alert('but this is'); }}>{replc}</Text>;
                }
                return text = parts;
                /////////////////////////////////////////////////////////////////////
            } else {
                return text
            }
        });
    } else {
        return text
    }
    return text
};

Auf diese Weise funktioniert der Code für mich nur dann gut, wenn im Text nur eine Erwähnung vorhanden ist, z , Beispiel: '_hey was ist passiert @-id:1- alles ok ?? @-id:2- @-id:3-_' ... Fehler: TypeError: text.split ist keine Funktion und wenn statt _parts = text.split(usrTofind);_ platziere ich _parts = text.toString ().split(usrTofind);_ es gibt mir einen [Object Object]-Fehler

Sie können html-react-parser , um die Zeichenfolge zu analysieren und dann durch den Knotennamen durch jsx-Komponenten zu ersetzen. Diese Art des Ersetzens ermöglicht es Ihnen, Reaktionselemente dynamisch zu verwenden, indem Sie Zeichenfolgen ersetzen.

      parse(body, {
        replace: domNode => {
          if (domNode.name === 'select') { // or
            return React.createElement(
              Select, // your react component
              { },
              domToReact(domNode.children)
            );
          }
        }

Jemand sagt mir, wie man react-router-dom in einer Zeichenfolge ersetzen kann?

Beispiel:

var text = "Are You okay <strong i="9">@sara</strong> ?";

var href= <Link to={{
  pathname: '/user/sara',
}}> <strong i="10">@sara</strong> </Link>;

var replace = text.replace("@sara", href);

//output : Are You okey [Object Object] ?

Ich weiß wirklich nicht, wer [Objektobjekt] ist? Ich sage "Bist du okay @sara", aber dieser Code hat jemand anderen angerufen!

Ich habe fast die gleiche Frage in react-native , ich freue mich, wenn mir jemand helfen kann

meine Frage

Bei mir hat nichts funktioniert außer diesem Paket https://www.npmjs.com/package/regexify-string

Ich verwende diese Funktion:

export const replaceWithHtml = (
  text: string,
  textToReplace: string,
  replaceValue: any,
): any[] => {
  const delimiter = '|||||'
  return text && text.includes(textToReplace)
    ? text
        .replace(textToReplace, `${delimiter}${textToReplace}${delimiter}`)
        .split(delimiter)
        .map((i) => {
          if (i === textToReplace) {
            return replaceValue
          } else {
            return i || null
          }
        })
    : text
}

So wie das:

const text = 'This is an [icon]'
replaceWithHtml(
      text,
      '[icon]',
      <i className="icon-cogs" />,
)

Ich wollte nur ein einfaches Interpolationstool, um bestimmte Schlüsselwörter durch bestimmte Elemente zu ersetzen.

Um die Anzahl der Elemente in meiner Ausgabe zu reduzieren, verwende ich ein React.Fragment .

const interpolate = (text, values) => {
  const pattern = /([$0-9]+)/g
  const matches = text.match(pattern)
  const parts = text.split(pattern)

  if (!matches) {
    return text
  }

  return parts.map((part, index) => (
    <Fragment key={part + index}>{matches.includes(part) ? values[part] : part}</Fragment>
  ))
}

// ...

<p>
  {interpolate('$1 with $2 is fun!', {
    $1: <em>Playing</em>,
    $2: <strong>JavaScript</strong>,
  })}
</p>

// <p><em>Playing</em> with <strong>JavaScript</strong> is fun!</p>

Danke @sophiebits für die Idee zu split() 🙏

Basierend auf der Lösung von @pedrodurek ist hier etwas für meine spezifischen Bedürfnisse (Übersetzungen mit lesbaren Schlüsseln statt nur Zahlen):

export const insertComponentsIntoText = (
    str: string,
    replacements: {
        [key: string]: React.ReactNode
    }
) => {
    const splitRegex = new RegExp(/\[\[(\w*)\]\]/g);
    const parts = str.split(splitRegex);
    return parts.map(part => {
        if (replacements.hasOwnProperty(part)) {
            return replacements[part];
        }
        return part;
    });
};

Beispiel:

insertComponentsIntoText(`"Please accept our [[privacyPolicyLink]] and [[termsLink].", {
    "privacyPolicyLink": <a key="privacyPolicyLink" href="/privacy">Privacy Policy</a>,
    "termsLink": <a key="termsLink" href="/terms">Terms and Conditions</a>
})

...wird...

Please accept our <a key="privacyPolicyLink" href="/privacy">Privacy Policy</a> and <a key="termsLink" href="/terms">Terms and Conditions</a>.

(Die Schlüssel sind notwendig, weil es tatsächlich zu einem Array wird, und React mag keine Array-Elemente ohne Schlüssel.)

Bei mir hat nichts funktioniert außer diesem Paket https://www.npmjs.com/package/regexify-string

Mich auch. Alle ausprobiert, nur dieses Paket funktioniert. Danke schön!

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen