Rumah >hujung hadapan web >tutorial js >Membina Borang Maklum Balas Pengguna dengan Perseid dan React

Membina Borang Maklum Balas Pengguna dengan Perseid dan React

DDD
DDDasal
2024-09-19 03:45:061010semak imbas

Dalam panduan ini, kami akan meneruskan pembinaan borang maklum balas pengguna dinamik menggunakan perpustakaan @perseid/form, alternatif yang berkuasa kepada Formik dan Borang Cangkuk Bertindak Balas. Anda akan melihat cara @perseid/form memudahkan untuk mengurus keadaan borang, pengesahan dan pemaparan bersyarat. Borang yang akan kami bina akan meminta pengguna menilai perkhidmatan dan memberikan maklum balas. Bergantung pada penilaian, ia sama ada akan memaparkan mesej "terima kasih" atau menggesa pengguna untuk memberikan maklum balas tambahan.

? Jom mulakan!


Langkah 1: Menyediakan Konfigurasi Borang

Langkah pertama ialah mentakrifkan konfigurasi borang. Konfigurasi ini menggariskan cara borang itu berkelakuan, termasuk medan, langkah dan aliran di antaranya. Di sini, kami akan mencipta medan untuk penilaian dan ulasan, dengan logik bersyarat berdasarkan penilaian pengguna. Kami juga akan menentukan mesej untuk maklum balas positif dan negatif.

Berikut ialah kod konfigurasi:

import { type Configuration } from "@perseid/form";

const formConfiguration: Configuration = {
  // Root step-the form will start from there.
  root: "feedback",
  // Callback triggered on form submission.
  onSubmit(data) {
    alert(`Submitting the following JSON: ${JSON.stringify(data)}`);
    return Promise.resolve();
  },
  // `fields` define the data model the form is going to deal with.
  // Expect the submitted data JSON to match this schema.
  fields: {
    rating: {
      type: "integer",
      required: true,
    },
    review: {
      type: "string",
      required: true,
      // Display this field only if condition is met...
      condition: (inputs) =>
        inputs.rating !== null && (inputs.rating as number) < 3,
    },
    // Type `null` means that the value of this field will not be included in submitted data.
    submit: {
      type: "null",
      submit: true,
    },
    message_good: {
      type: "null",
    },
    message_bad: {
      type: "null",
    },
  },
  // Now that fields are defined, you can organize them in a single or multiple steps,
  // depending on the UI you want to build!
  steps: {
    feedback: {
      fields: ["rating", "review", "submit"],
      // Whether to submit the form at the end of this step.
      submit: true,
      // Next step is conditionned to previous user inputs...
      nextStep: (inputs) =>
        (inputs.rating as number) < 3 ? "thanks_bad" : "thanks_good",
    },
    thanks_good: {
      fields: ["message_good"],
    },
    thanks_bad: {
      fields: ["message_bad"],
    },
  },
};

Dalam konfigurasi ini:

  • Borang bermula pada langkah maklum balas.
  • Borang mengandungi dua medan: rating (diperlukan) dan ulasan (pilihan melainkan rating di bawah 3).
  • Berdasarkan penilaian, borang tersebut menavigasi sama ada mesej maklum balas "baik" atau "buruk".
  • Setelah penyerahan borang, makluman mudah dicetuskan dengan data yang diserahkan.

Perkara utama yang perlu difahami di sini ialah fungsi sifat medan. Ia mentakrifkan struktur data yang akan diserahkan, pada asasnya bertindak sebagai model data. Sebaliknya, sifat langkah menggariskan aliran borang, menentukan cara medan ini akan dipersembahkan kepada pengguna.


Langkah 2: Mencipta Komponen Reaksi Borang

Sekarang kita mempunyai konfigurasi, tiba masanya untuk membina UI sebenar yang akan menghasilkan borang. Menggunakan @perseid/form/react, kami boleh mencipta komponen medan tersuai untuk mengurus interaksi pengguna bagi setiap bahagian borang.

Berikut ialah komponen teras React:

import React from "react";
import Form, { type FormFieldProps } from "@perseid/form/react";

// The actual React component, used to build the UI!
function Field(props: FormFieldProps): JSX.Element {
  const { path, engine, value, status } = props;
  const [currentRating, setCurrentRating] = React.useState(0);

  // Display a different element depending on the field...

  if (path === "thanks_good.1.message_good") {
    return (
      <div className="message">
        <h1>Thanks for the feedback ?</h1>
        <p>We are glad you enjoyed!</p>
      </div>
    );
  }

  if (path === "thanks_bad.1.message_bad") {
    return (
      <div className="message">
        <h1>We're sorry to hear that ?</h1>
        <p>We'll do better next time, promise!</p>
      </div>
    );
  }

  if (path === "feedback.0.rating") {
    return (
      // Depending on the field status, define some extra classes for styling...
      <div
        className={`rating ${status === "error" ? "rating--error" : ""}`}
        onMouseLeave={() => {
          setCurrentRating((value as number | null) ?? 0);
        }}
      >
        <h1>How would you rate our service?</h1>
        {[1, 2, 3, 4, 5].map((rating) => (
          <span
            key={rating}
            className={`rating__star ${
              currentRating >= rating ? "rating__star--active" : ""
            }`}
            onMouseEnter={() => {
              setCurrentRating(rating);
            }}
            onClick={() => {
              // On click, notify the form engine about new user input.
              engine.userAction({ type: "input", path, data: rating });
            }}
          ></span>
        ))}
      </div>
    );
  }

  if (path === "feedback.0.review") {
    return (
      <div className={`review ${status === "error" ? "review--error" : ""}`}>
        <label>Could you tell us more?</label>
        <textarea
          onChange={(e) =>
            engine.userAction({ type: "input", path, data: e.target.value })
          }
        />
      </div>
    );
  }

  // path === 'feedback.0.submit'
  return (
    <button
      className="submit"
      onClick={() => {
        engine.userAction({ type: "input", path, data: true });
      }}
    >
      Submit
    </button>
  );
}

Di sini, komponen Medan menggunakan prop laluan untuk memutuskan perkara yang hendak dipaparkan:

  • Komponen rating yang membolehkan pengguna memilih rating bintang.
  • Kawasan teks untuk pengguna memberikan maklum balas tambahan.

Mesej "Terima kasih" yang dipaparkan berdasarkan penilaian. Borang akan melaraskan medan dan langkahnya secara dinamik berdasarkan input pengguna.

Cukup keren, bukan?

Building a User Feedback Form with Perseid and React


Langkah 3: Menjalankan Aplikasi

Setelah konfigurasi dan komponen borang kami sudah sedia, mari sepadukan mereka ke dalam apl React asas. Berikut ialah kod untuk memulakan dan memberikan borang:

import { createRoot, type Root } from "react-dom/client";

// Let's run the app!
let app: Root;

// Creating React root...
const container = document.querySelector("#root") as unknown as HTMLElement;
app = createRoot(container);
app.render(
  // Router is the main component for any Perseid app.
  <Form Field={Field} configuration={formConfiguration} />
);

Kod ini melekapkan borang ke DOM menggunakan API createRoot React. Komponen Borang, yang menghubungkan konfigurasi dan komponen Medan kami, mengendalikan segala-galanya.

Langkah 4: Menambah Gaya

Baiklah, kami mempunyai logik apl kami, tetapi jika anda menjalankan kod itu sekarang, anda akan melihat bahawa ia agak... mentah ?

Building a User Feedback Form with Perseid and React

Jadi, mari kita pimp borang dengan menambah beberapa gaya dan animasi! Di bawah ialah helaian gaya ringkas yang menjadikannya lebih menarik:

// A few animations for fun...

@keyframes swipe-out {
  0% {
    opacity: 1;
    transform: translateX(0);
  }
  75% {
    opacity: 0;
    transform: translateX(-100%);
  }
  100% {
    opacity: 0;
    transform: translateX(-100%);
  }
}

@keyframes swipe-in-one {
  0% {
    opacity: 0;
    transform: translateX(100%);
  }
  75% {
    transform: translateX(0);
  }
  100% {
    opacity: 1;
    transform: translateX(0);
  }
}

@keyframes swipe-in-two {
  0% {
    opacity: 0;
    transform: translateX(0);
  }
  75% {
    transform: translateX(-100%);
  }
  100% {
    opacity: 1;
    transform: translateX(-100%);
  }
}

@keyframes bubble-in {
  0% {
    transform: scale(0.5);
  }
  75% {
    transform: scale(1.5);
  }
  100% {
    transform: scale(1);
  }
}

@keyframes fade-in {
  0% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}

// Some global basic styling...

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  display: grid;
  height: 100vh;
  color: #aaaaaa;
  align-items: center;
  font-family: "Helvetica", sans-serif;
}

// And form-specific styling.

.perseid-form {
  width: 100%;
  margin: auto;

  &__steps {
    display: flex;
    overflow: hidden;
  }

  &__step {
    min-width: 100%;
    padding: 1rem 3rem;
    animation: 500ms ease-in-out forwards swipe-out;

    &__fields {
      display: grid;
      row-gap: 2rem;
    }
  }

  &__step[class*="active"]:first-child {
    animation: 500ms ease-in-out forwards swipe-in-one;
  }
  &__step[class*="active"]:last-child:not(:first-child) {
    animation: 500ms ease-in-out forwards swipe-in-two;
  }
}

.submit {
  border: none;
  cursor: pointer;
  padding: 1rem 2rem;
  border-radius: 8px;
  color: #fefefe;
  font-size: 1.25rem;
  background: #46c0b0;
  justify-self: flex-end;
  transition: all 250ms ease-in-out;

  &:hover {
    background: #4cccbb;
  }
}

.rating {
  position: relative;
  padding: 0.25rem 0;

  &__star {
    cursor: pointer;
    display: inline-block;
    font-size: 2rem;
    min-width: 2rem;
    min-height: 2rem;

    &::after {
      content: "⚪️";
    }

    &--active {
      animation: 250ms ease-in-out forwards bubble-in;
      &::after {
        content: "?";
      }
    }
  }

  &[class*="error"] {
    &::after {
      left: 0;
      bottom: -1.5rem;
      color: #f13232;
      position: absolute;
      font-size: 0.75rem;
      content: "? This field is required";
      animation: 250ms ease-in-out forwards fade-in;
    }
  }
}

.review {
  display: grid;
  row-gap: 1rem;
  position: relative;
  animation: 250ms ease-in-out forwards fade-in;

  label {
    font-size: 1.25rem;
  }

  textarea {
    resize: none;
    min-height: 5rem;
    border-radius: 8px;
    border: 1px solid #46c0b0;
    transition: all 250ms ease-in-out;
  }

  &[class*="error"] {
    &::after {
      left: 0;
      bottom: -1.5rem;
      color: #f13232;
      position: absolute;
      font-size: 0.75rem;
      content: "? This field is required";
      animation: 250ms ease-in-out forwards fade-in;
    }
  }
}

@media screen and (min-width: 30rem) {
  .perseid-form {
    max-width: 30rem;
  }
}

Dan voilà ?


Kesimpulan

Tahniah! ? Anda baru sahaja membina borang maklum balas pengguna dinamik dengan Perseid dan React.

Dalam tutorial ini, kami membincangkan cara untuk:

  • Tentukan konfigurasi borang dengan logik bersyarat.
  • Bina komponen React tersuai untuk mengendalikan interaksi pengguna.
  • Render borang dalam apl anda dan gayakannya dengan animasi dan CSS tersuai.

Jangan ragu untuk bereksperimen dengan medan dan langkah tambahan yang sesuai dengan kes penggunaan anda. Berseronoklah membina borang yang hebat! ?


  • ? Lagi contoh
  • ✅ Dokumentasi lengkap
  • ? Sertai Discord kami
  • ? Bintangkan projek di GitHub
  • ❤️ Taja Perseid

Atas ialah kandungan terperinci Membina Borang Maklum Balas Pengguna dengan Perseid dan React. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn