Heim > Web-Frontend > js-Tutorial > Einführung. zum WebBuilding eines Cardano Wallet Checkers mit JavaScript.

Einführung. zum WebBuilding eines Cardano Wallet Checkers mit JavaScript.

DDD
Freigeben: 2025-01-08 08:29:43
Original
763 Leute haben es durchsucht

Dieses Projekt ist meine allererste Web3-Anwendung und stellt über das Yoroi-Wallet eine Verbindung zur Cardano-Blockchain her. Es ist eigentlich ziemlich einfach, nur eine Möglichkeit, den Kontostand Ihres Geldbeutels zu überprüfen, aber es markiert den Beginn vieler spannender Projekte, die noch kommen werden. Ich möchte meinen Lernprozess mit Ihnen teilen, während wir dieses Tutorial durcharbeiten.

? Was bauen wir?

Bevor wir beginnen, machen wir uns klar darüber, was wir schaffen. Dies ist ein einfaches, einfaches Tool, mit dem Sie:

  • Werfen Sie einen Blick auf das Guthaben eines beliebigen Cardano-Wallets (natürlich legal! ?)
  • Verbinden Sie sich mit Ihrem Yoroi-Wallet
  • Salden in ADA anzeigen

Intro. to WebBuilding a Cardano Wallet Checker with JavaScript.

? Was Sie brauchen

Grundlegende JavaScript-Kenntnisse (wenn Sie console.log("hello world") können, sind Sie gut!)

  1. - Ein Texteditor (VS Code, Sublime oder sogar Notepad, wenn Sie abenteuerlustig sind)
  2. - Die Yoroi-Wallet-Erweiterung ist installiert (wir benötigen diese zum Testen)
  3. - Ein Blockfrost-API-Schlüssel (keine Sorge, ich zeige Ihnen, wie Sie einen bekommen) Machen wir uns an die Arbeit!

Schritt 1: Richten Sie das Projekt ein

Erstellen Sie auf Ihrem Computer einen neuen Ordner mit dem Namen CardanoWalletExplorer (oder Junky Justyk, wenn Sie möchten, der Name spielt keine Rolle). Öffnen Sie den Ordner in Ihrem Code-Editor (ich verwende Visual Studio Code).
Erstellen Sie im Ordner zwei Dateien:
index.html und style.css
Öffnen Sie nun index.html und fügen Sie Folgendes ein:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Cardano Wallet Explorer</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div>



<p>Let's add some style to our creation. Inside the style.css file paste this in:<br>
</p>

<pre class="brush:php;toolbar:false">:root {
    --primary-color: #0033ad;
    --secondary-color: #2a71d4;
    --accent-color: #17d1aa;
    --background-color: #f8faff;
    --card-background: #ffffff;
    --text-primary: #1a202c;
    --text-secondary: #4a5568;
    --border-color: #e2e8f0;
    --shadow: 0 4px 6px rgba(0,0,0,0.1);
}

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: 'Inter', system-ui, sans-serif;
    background: var(--background-color);
    color: var(--text-primary);
    line-height: 1.5;
    min-height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 2rem;
}

.container {
    background: var(--card-background);
    border-radius: 1.5rem;
    box-shadow: var(--shadow);
    width: 100%;
    max-width: 800px;
    overflow: hidden;
}

.app-header {
    background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
    color: white;
    padding: 2rem;
    text-align: center;
}

.logo {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 1rem;
    margin-bottom: 0.5rem;
}

.logo i { font-size: 2rem; }
h1 { font-size: 1.8rem; font-weight: 600; }
.subtitle { opacity: 0.9; }

.content { padding: 2rem; }

.search-section {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1.5rem;
    margin-bottom: 2rem;
}

.search-box {
    display: flex;
    gap: 1rem;
    width: 100%;
    max-width: 600px;
}

#wallet-search {
    flex: 1;
    padding: 0.875rem 1rem;
    border: 2px solid var(--border-color);
    border-radius: 12px;
    font-size: 0.95rem;
    transition: 0.3s ease;
}

#wallet-search:focus {
    outline: none;
    border-color: var(--accent-color);
    box-shadow: 0 0 0 3px rgba(23, 209, 170, 0.1);
}

button {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.875rem 1.5rem;
    border: none;
    border-radius: 12px;
    font-size: 0.95rem;
    font-weight: 500;
    cursor: pointer;
    transition: 0.3s ease;
}

#search-button {
    background: var(--accent-color);
    color: white;
}

#search-button:hover {
    background: #15bea0;
    transform: translateY(-2px);
}

.divider {
    width: 100%;
    max-width: 600px;
    text-align: center;
    position: relative;
    color: var(--text-secondary);
}

.divider::before,
.divider::after {
    content: '';
    position: absolute;
    top: 50%;
    width: calc(50% - 2rem);
    height: 1px;
    background: var(--border-color);
}

.divider::before { left: 0; }
.divider::after { right: 0; }

.connect-button {
    background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
    color: white;
    padding: 1rem 2rem;
}

.connect-button:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow);
}

.wallet-info {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: 1.5rem;
    margin-top: 2rem;
}

.info-card {
    background: var(--card-background);
    border: 1px solid var(--border-color);
    border-radius: 1rem;
    padding: 1.5rem;
    transition: 0.3s ease;
}

.info-card:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow);
}

.card-header {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 1rem;
    color: var(--text-secondary);
}

.card-header i {
    font-size: 1.25rem;
    color: var(--primary-color);
}

.card-content {
    font-size: 0.95rem;
    color: var(--text-primary);
    word-break: break-all;
}

.app-footer {
    text-align: center;
    padding: 1.5rem;
    background: var(--background-color);
    color: var(--text-secondary);
    font-size: 0.9rem;
}

.app-footer a {
    color: var(--primary-color);
    text-decoration: none;
}

.app-footer a:hover {
    text-decoration: underline;
}

@media (max-width: 640px) {
    body {
        padding: 1rem;
    }

    .container {
        border-radius: 1.5rem;
    }

    .app-header {
        padding: 1.5rem;
    }

    .content {
        padding: 1.5rem;
    }

    .search-box {
        flex-direction: column;
    }

    button {
        width: 100%;
        justify-content: center;
    }

    .wallet-info {
        grid-template-columns: 1fr;
    }
}

Nach dem Login kopieren
Nach dem Login kopieren

Schritt 2: Wie erhalten Sie Ihren Blockfrost-API-Schlüssel?

Um Wallet-Guthaben abzurufen, benötigen wir Blockfrost, das uns die Interaktion mit der Cardano-Blockchain ermöglicht. So erhalten Sie Ihren API-Schlüssel:

  • Gehen Sie zu Blockfrost.io und melden Sie sich an.
  • Sobald Sie angemeldet sind, klicken Sie auf „Neues Projekt erstellen“.
  • Wählen Sie Mainnet für echtes ADA oder Testnet zum Testen.
  • Nachdem das Projekt erstellt wurde, erhalten Sie einen API-Schlüssel.

Schritt 3: Das Gehirn der Operation?

Jetzt kommt der spaßige Teil: alles zum Laufen zu bringen! Erstellen Sie eine Datei mit dem Namen script.js in dem von uns erstellten Ordner.

function checkYoroiInstalled() {
    return window.cardano && window.cardano.yoroi;
}
Nach dem Login kopieren
Nach dem Login kopieren

? Diese Funktion prüft, ob die Yoroi-Wallet-Erweiterung in Ihrem Browser installiert ist. Window.cardano ist das Objekt, das von Cardano-Wallets wie Yoroi offengelegt wird. Wir prüfen, ob dies vorhanden ist und ob window.cardano.yoroi verfügbar ist, um zu bestätigen, dass das Yoroi-Wallet installiert ist.
Wenn beide wahr sind, gibt die Funktion wahr zurück; andernfalls wird false zurückgegeben.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Cardano Wallet Explorer</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div>



<p>Let's add some style to our creation. Inside the style.css file paste this in:<br>
</p>

<pre class="brush:php;toolbar:false">:root {
    --primary-color: #0033ad;
    --secondary-color: #2a71d4;
    --accent-color: #17d1aa;
    --background-color: #f8faff;
    --card-background: #ffffff;
    --text-primary: #1a202c;
    --text-secondary: #4a5568;
    --border-color: #e2e8f0;
    --shadow: 0 4px 6px rgba(0,0,0,0.1);
}

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: 'Inter', system-ui, sans-serif;
    background: var(--background-color);
    color: var(--text-primary);
    line-height: 1.5;
    min-height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 2rem;
}

.container {
    background: var(--card-background);
    border-radius: 1.5rem;
    box-shadow: var(--shadow);
    width: 100%;
    max-width: 800px;
    overflow: hidden;
}

.app-header {
    background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
    color: white;
    padding: 2rem;
    text-align: center;
}

.logo {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 1rem;
    margin-bottom: 0.5rem;
}

.logo i { font-size: 2rem; }
h1 { font-size: 1.8rem; font-weight: 600; }
.subtitle { opacity: 0.9; }

.content { padding: 2rem; }

.search-section {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1.5rem;
    margin-bottom: 2rem;
}

.search-box {
    display: flex;
    gap: 1rem;
    width: 100%;
    max-width: 600px;
}

#wallet-search {
    flex: 1;
    padding: 0.875rem 1rem;
    border: 2px solid var(--border-color);
    border-radius: 12px;
    font-size: 0.95rem;
    transition: 0.3s ease;
}

#wallet-search:focus {
    outline: none;
    border-color: var(--accent-color);
    box-shadow: 0 0 0 3px rgba(23, 209, 170, 0.1);
}

button {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.875rem 1.5rem;
    border: none;
    border-radius: 12px;
    font-size: 0.95rem;
    font-weight: 500;
    cursor: pointer;
    transition: 0.3s ease;
}

#search-button {
    background: var(--accent-color);
    color: white;
}

#search-button:hover {
    background: #15bea0;
    transform: translateY(-2px);
}

.divider {
    width: 100%;
    max-width: 600px;
    text-align: center;
    position: relative;
    color: var(--text-secondary);
}

.divider::before,
.divider::after {
    content: '';
    position: absolute;
    top: 50%;
    width: calc(50% - 2rem);
    height: 1px;
    background: var(--border-color);
}

.divider::before { left: 0; }
.divider::after { right: 0; }

.connect-button {
    background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
    color: white;
    padding: 1rem 2rem;
}

.connect-button:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow);
}

.wallet-info {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: 1.5rem;
    margin-top: 2rem;
}

.info-card {
    background: var(--card-background);
    border: 1px solid var(--border-color);
    border-radius: 1rem;
    padding: 1.5rem;
    transition: 0.3s ease;
}

.info-card:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow);
}

.card-header {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 1rem;
    color: var(--text-secondary);
}

.card-header i {
    font-size: 1.25rem;
    color: var(--primary-color);
}

.card-content {
    font-size: 0.95rem;
    color: var(--text-primary);
    word-break: break-all;
}

.app-footer {
    text-align: center;
    padding: 1.5rem;
    background: var(--background-color);
    color: var(--text-secondary);
    font-size: 0.9rem;
}

.app-footer a {
    color: var(--primary-color);
    text-decoration: none;
}

.app-footer a:hover {
    text-decoration: underline;
}

@media (max-width: 640px) {
    body {
        padding: 1rem;
    }

    .container {
        border-radius: 1.5rem;
    }

    .app-header {
        padding: 1.5rem;
    }

    .content {
        padding: 1.5rem;
    }

    .search-box {
        flex-direction: column;
    }

    button {
        width: 100%;
        justify-content: center;
    }

    .wallet-info {
        grid-template-columns: 1fr;
    }
}

Nach dem Login kopieren
Nach dem Login kopieren

Diese Funktion formatiert den Kontostand von ADA auf benutzerfreundliche Weise.
Cardano verwendet Lovelace als kleinste Einheit (1 ADA = 1.000.000 Lovelace), daher müssen wir es durch Division durch 1.000.000 in ADA umrechnen.
Es stellt außerdem sicher, dass der Kontostand mit 6 Dezimalstellen angezeigt wird (z. B. 1,234567 ADA) oder gibt „0,000000“ zurück, wenn der Kontostand ungültig oder leer ist.

function checkYoroiInstalled() {
    return window.cardano && window.cardano.yoroi;
}
Nach dem Login kopieren
Nach dem Login kopieren

Wir verwenden die Fetch-API, um eine GET-Anfrage an Blockfrost zu stellen. Blockfrost bietet eine API zur Interaktion mit der Cardano-Blockchain. Wir senden eine GET-Anfrage an den Endpunkt für die spezifische Wallet-Adresse und verwenden dabei einen API-Schlüssel zur Autorisierung. Diese Funktion ruft den Kontostand einer bestimmten Wallet-Adresse ab, indem sie eine Anfrage an die Blockfrost-API stellt.

Wenn die Antwort erfolgreich ist, analysieren wir die JSON-Daten und geben die Menge an ADA in dieser Adresse zurück.
Wenn ein Fehler auftritt (z. B. ungültige Adresse oder API-Probleme), wird ein Fehler ausgegeben und in der Konsole protokolliert. Die Endpunkt-URL enthält die Wallet-Adresse, die wir überprüfen möchten. Stellen Sie sicher, dass Sie den Platzhalter YOUR_API_KEY in der checkWalletBalance-Funktion durch Ihren API-Schlüssel ersetzen.

function formatBalance(lovelaceBalance) {
    if (!lovelaceBalance || isNaN(lovelaceBalance)) {
        return "0.000000";
    }
    const adaBalance = parseFloat(lovelaceBalance) / 1_000_000;
    return adaBalance.toFixed(6);
}

Nach dem Login kopieren
  • Diese UI-Aktualisierungsfunktion aktualisiert die Benutzeroberfläche (UI) mit der Wallet-Adresse und dem Guthaben.
  • Die Adresse wird gekürzt, um die ersten 8 und letzten 8 Zeichen anzuzeigen (um sie besser lesbar zu machen) und in der Karte „Wallet-Adresse“ angezeigt.
  • Es formatiert den Kontostand mithilfe der formatBalance-Funktion und zeigt ihn auf der Karte „Wallet-Kontostand“ an.
  • Es wird außerdem ein Tooltip mit der vollständigen Adresse angezeigt, wenn Sie mit der Maus über den Adresstext fahren.
**Fetching Wallet Balance Using Blockfrost API
async function checkWalletBalance(address) {
    try {
        const API_KEY = 'YOUR_API_KEY';
        const response = await fetch(`https://cardano-mainnet.blockfrost.io/api/v0/addresses/${address}`, {
            headers: {
                'project_id': API_KEY
            }
        });

        if (!response.ok) {
            throw new Error('Invalid address or API error');
        }

        const data = await response.json();
        return data.amount[0].quantity;
    } catch (error) {
        console.error('Error fetching balance:', error);
        throw error;
    }
}

Nach dem Login kopieren

Dieser Code fügt Ereignis-Listener an die HTML-Elemente an:
Wenn auf die Schaltfläche „Yoroi Wallet verbinden“ geklickt wird, wird die connectWallet-Funktion aufgerufen.
Wenn auf die Schaltfläche „Guthaben prüfen“ geklickt wird, wird die handleWalletSearch-Funktion aufgerufen.
Drückt der Nutzer im Eingabefeld der Wallet-Adresse die „Enter“-Taste, wird auch die Kontostandprüfung ausgelöst.

Herzlichen Glückwunsch, Sie haben es geschafft! ?

Sie sind der Beherrschung von Web3 jetzt einen Schritt näher gekommen! „Dieses Projekt war nicht nur eine technische Errungenschaft, sondern auch ein aufregender Schritt in die weite Welt der Blockchain-Entwicklung!“ ?
Jetzt können Sie sich nahtlos mit der Yoroi-Wallet verbinden, Guthaben überprüfen und die Leistungsfähigkeit der Blockchain immer zur Hand haben.

? Testzeit!

  1. Installieren Sie die Liveserver-Erweiterung auf vs Code und stellen Sie sicher, dass sie ausgeführt wird, indem Sie auf die Schaltfläche „Live gehen“ klicken.
  2. Dies sollte die HTML-Datei in Ihrem Browser öffnen
  3. Drücken Sie die Daumen und testen Sie es!

? Was Sie aus diesem Projekt gelernt haben

  • Erhielt ein solides Verständnis dafür, wie Blockchain-Wallets wie Yoroi funktionieren und mit dezentralen Netzwerken interagieren.
  • Beherrschte den Prozess der sicheren Verbindung einer Browser-Wallet mit einer Web-App mithilfe von window.cardano-APIs.
  • Erkundete die Blockfrost-API zum Abrufen von Wallet-Guthaben und Adressdetails aus der Cardano-Blockchain.
  • Erweiterte Kenntnisse über Async und Wait, Fehlerbehandlung und Datenformatierung, um ein reibungsloses Benutzererlebnis zu gewährleisten.
  • Ich habe gelernt, Webseitenelemente basierend auf Echtzeit-Blockchain-Daten dynamisch zu aktualisieren.
  • Verstehen Sie die Mechanismen der Konvertierung von Kryptowährungseinheiten von Lovelace in ADA und deren Formatierung für eine bessere Lesbarkeit durch den Benutzer.
  • Erkennen, wie wichtig eine robuste Fehlerbehandlung für API-Anfragen und Benutzereingaben ist, um Störungen zu verhindern.
  • Erhielt wertvolle Einblicke in Wallet-Strukturen, Adressverwaltung und Transaktionsdarstellung auf der Blockchain.
  • Implementierte Funktionen wie Lade-Spinner, Tooltips und Warnungen, um die Benutzerinteraktion zu verbessern.
  • Bewältigung von Grenzfällen und Debugging-Herausforderungen, Stärkung der Analyse- und Programmierfähigkeiten.

? Level-Up-Ideen

Dieses Projekt ist ein Sprungbrett in die Welt der Blockchain-Entwicklung. Hier sind einige Ideen, um noch weiter zu gehen:

  • Fügen Sie einen Transaktionsverlaufs-Viewer hinzu, um vergangene Transaktionen für eine Wallet-Adresse anzuzeigen.
  • Implementieren Sie die Unterstützung mehrerer Wallets, sodass Benutzer zwischen Wallets wie Yoroi, Nami oder Eternal wechseln können.
  • Erstellen Sie ein Dashboard, das Wallet-Aktivitätstrends anzeigt, einschließlich Zusammenfassungen eingehender und ausgehender Transaktionen.
  • Integrieren Sie Echtzeit-Preisdaten, um den ADA-Saldo in Fiat-Währungen wie USD oder EUR anzuzeigen.
  • Aktivieren Sie die Möglichkeit, ADA direkt aus der App zu senden, indem Sie Funktionen zur Transaktionserstellung integrieren.
  • Fügen Sie einen Dunkelmodus-Schalter für ein optisch ansprechendes und zugängliches Design hinzu.
  • Machen Sie die Benutzeroberfläche reaktionsfähig, um die Kompatibilität mit Mobilgeräten sicherzustellen.
  • Integrieren Sie bessere Fehlermeldungen, die Benutzer bei der Behebung von Problemen, wie z. B. ungültigen Wallet-Adressen, unterstützen.

? So können Sie einen Beitrag leisten

Dieses Projekt ist mein erster Schritt in Web3 und ich bin gespannt darauf, von den Besten zu lernen. Ihre Erfahrungen, Erkenntnisse und Vorschläge können dieses Projekt verbessern und mir gleichzeitig dabei helfen, mich als Entwickler weiterzuentwickeln. So können Sie einen Beitrag leisten:

  • Forken Sie das Projekt auf GitHub und fügen Sie neue Funktionen oder Verbesserungen hinzu.
  • Melden Sie Fehler oder Probleme, die bei der Verwendung des Tools auftreten, und schlagen Sie Lösungen vor.
  • Schlagen Sie Verbesserungen vor, indem Sie eine Funktionsanfrage oder Diskussion im GitHub-Repo öffnen.
  • Schreiben Sie eine detaillierte Dokumentation für jede neue Funktion, die Sie hinzufügen, damit andere sie einfach nutzen und darauf aufbauen können.

✨ Neue Funktionen, die es zu berücksichtigen gilt

  • Fügen Sie QR-Code-Unterstützung hinzu, um die Weitergabe und das Scannen von Wallet-Adressen zu vereinfachen.
  • Implementieren Sie Benachrichtigungen für Ereignisse wie Kontostandaktualisierungen oder Transaktionsbestätigungen.
  • Fügen Sie einen Bildungsabschnitt hinzu, der Anfängern die Grundlagen der Blockchain erklärt.
  • Führen Sie spielerische Elemente ein, z. B. Erfolge für die häufige Nutzung Ihres Geldbeutels oder die Erkundung neuer Funktionen.
  • Entwickeln Sie eine Einsatzfunktion, um die Einsatzprämien und den Delegationsstatus anzuzeigen.

Lassen Sie uns weiter bauen und innovieren – Ihre Beiträge und Ihre Kreativität können die Zukunft dieses Tools gestalten! ?

? Brauchen Sie Hilfe?

Sie stecken fest? Einen Fehler gefunden? Möchten Sie chatten? Schreiben Sie unten einen Kommentar oder finden Sie mich auf Twitter!
Denken Sie daran, wir haben alle irgendwo angefangen und die einzige dumme Frage ist die, die Sie nicht gestellt haben!

Viel Spaß beim Codieren, liebe Blockchain-Entdecker! ?

Das obige ist der detaillierte Inhalt vonEinführung. zum WebBuilding eines Cardano Wallet Checkers mit JavaScript.. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Quelle:dev.to
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage