Maison >interface Web >js tutoriel >Création d'un formulaire de commentaires utilisateur avec Svelte et Perseid

Création d'un formulaire de commentaires utilisateur avec Svelte et Perseid

Patricia Arquette
Patricia Arquetteoriginal
2024-10-02 06:35:02295parcourir

Dans ce guide, nous expliquerons la création d'un formulaire de commentaires utilisateur dynamique à l'aide de la bibliothèque @perseid/form, une alternative puissante à Formly et Superforms. Vous verrez comment @perseid/form facilite la gestion de l'état, de la validation et du rendu conditionnel du formulaire. Le formulaire que nous allons créer demandera aux utilisateurs d'évaluer un service et de fournir des commentaires. En fonction de la note, il affichera un message de « remerciement » ou invitera l'utilisateur à fournir des commentaires supplémentaires.

? Commençons !


Étape 1 : Configuration du formulaire

La première étape consiste à définir la configuration du formulaire. Cette configuration décrit le comportement du formulaire, y compris les champs, les étapes et le flux entre eux. Ici, nous allons créer des champs pour une note et un avis, avec une logique conditionnelle basée sur la note de l'utilisateur. Nous définirons également des messages pour les commentaires positifs et négatifs.

Voici le code de configuration :

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"],
    },
  },
};

Dans cette configuration :

  • Le formulaire commence à l'étape de commentaires.
  • Le formulaire contient deux champs : note (obligatoire) et avis (facultatif sauf si la note est inférieure à 3).
  • En fonction de l'évaluation, le formulaire accède au message de retour « bon » ou « mauvais ».
  • Lors de la soumission du formulaire, une simple alerte est déclenchée avec les données soumises.

Le point clé à comprendre ici est la fonction de la propriété field. Il définit la structure des données qui seront soumises, agissant essentiellement comme un modèle de données. En revanche, la propriété steps décrit le flux du formulaire, déterminant comment ces champs seront présentés à l'utilisateur.


Étape 2 : Création des composants sveltes du formulaire

Maintenant que nous avons la configuration, il est temps de créer l'interface utilisateur réelle qui restituera le formulaire. En utilisant @perseid/form/svelte, nous pouvons créer des composants de champ personnalisés pour gérer les interactions des utilisateurs pour chaque partie du formulaire.

Voici le composant principal de Svelte :

<!-- The actual Svelte component, used to build the UI! -->
<script lang="ts" context="module">
import type { FormFieldProps } from "@perseid/form/svelte";
</script>

<script lang="ts">
export let path: FormFieldProps['path'];
export let type: FormFieldProps['type'];
export let value: FormFieldProps['value'];
export let Field: FormFieldProps['Field'];
export let error: FormFieldProps['error'];
export let status: FormFieldProps['status'];
export let engine: FormFieldProps['engine'];
export let fields: FormFieldProps['fields'];
export let isActive: FormFieldProps['isActive'];
export let activeStep: FormFieldProps['activeStep'];
export let isRequired: FormFieldProps['isRequired'];
export let setActiveStep: FormFieldProps['setActiveStep'];
export let useSubscription: FormFieldProps['useSubscription'];

let currentRating = 0;
$: currentValue = value as number;
$: fields, isActive, activeStep, setActiveStep, useSubscription, type, error, Field, isRequired;

const setCurrentRating = (newRating: number) => {
  currentRating = newRating;
};

const handleReviewChange = (event: Event) => {
  engine.userAction({ type: "input", path, data: (event.target as HTMLTextAreaElement).value })
};
</script>

 <!-- Display a different element depending on the field... -->

{#if path === 'thanks_good.1.message_good'}
  <div class="message">
    <h1>Thanks for the feedback ?</h1>
    <p>We are glad you enjoyed!</p>
  </div>
{:else if path === 'thanks_bad.1.message_bad'}
  <div class="message">
    <h1>We're sorry to hear that ?</h1>
    <p>We'll do better next time, promise!</p>
  </div>
{:else if path === 'feedback.0.review'}
  <div class={`review ${status === "error" ? "review--error" : ""}`}>
    <label for="#review">Could you tell us more?</label>
    <textarea
      id="review"
      on:change={handleReviewChange}
    />
  </div>
{:else if path === 'feedback.0.rating'}
  <!-- Depending on the field status, define some extra classes for styling... -->
  <div
    role="button"
    tabindex="0"
    class={`rating ${status === "error" ? "rating--error" : ""}`}
    on:mouseleave={() => {
      setCurrentRating(currentValue ?? 0);
    }}
  >
    <h1>How would you rate our service?</h1>
    {#each [1, 2, 3, 4, 5] as rating (rating)}
      <span
        role="button"
        tabindex="0"
        class={`rating__star ${currentRating >= rating ? "rating__star--active" : ""}`}
        on:mouseenter={() => {
          setCurrentRating(rating);
        }}
        on:keydown={() => {}}
        on:click={() => {
          // On click, notify the form engine about new user input.
          engine.userAction({ type: "input", path, data: rating });
        }}
    ></span>
    {/each}
  </div>
{:else}
  <!-- path === 'feedback.0.submit' -->
  <button
    class="submit"
    on:click={() => {
      engine.userAction({ type: "input", path, data: true });
    }}
  >
    Submit
  </button>
{/if}

Ici, le composant Field utilise la prop path pour décider quoi rendre :

  • Un composant de notation où les utilisateurs peuvent sélectionner une note par étoiles.
  • Une zone de texte permettant aux utilisateurs de fournir des commentaires supplémentaires.

Messages « Merci » qui apparaissent en fonction de la note. Le formulaire ajustera dynamiquement ses champs et ses étapes en fonction des saisies de l'utilisateur.

Plutôt cool, non ?

Building a User Feedback Form with Svelte and Perseid


Étape 3 : Exécuter l'application

Maintenant que la configuration et le composant de notre formulaire sont prêts, intégrons-les dans une application Svelte de base. Voici le code pour initialiser et restituer le formulaire :

// Let's run the app!
// Creating Svelte root...
const container = document.querySelector("#root") as unknown as HTMLElement;
container.innerHTML = '';
new Form({
  props: {
    Field: Field,
    configuration: formConfiguration,
  },
  target: container,
});

Ce code monte le formulaire dans le DOM. Le composant Form, qui connecte notre configuration et notre composant Field, gère tout le reste.

Étape 4 : Ajout de styles

Très bien, nous avons notre logique d'application, mais si vous exécutez le code maintenant, vous verrez que c'est un peu... brut ?

Building a User Feedback Form with Svelte and Perseid

Alors, embellissons le formulaire en ajoutant quelques styles et animations ! Vous trouverez ci-dessous une feuille de style simple qui la rend beaucoup plus attrayante :

// 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;
  }
}

Et voilà ?


Conclusion

Félicitations ! ? Vous venez de créer un formulaire de commentaires utilisateur dynamique avec Perseid et Svelte.

Dans ce tutoriel, nous avons expliqué comment :

  • Définissez une configuration de formulaire avec une logique conditionnelle.
  • Créez des composants Svelte personnalisés pour gérer les interactions des utilisateurs.
  • Rendez le formulaire dans votre application et stylisez-le avec des animations et du CSS personnalisé.

N'hésitez pas à expérimenter des champs et des étapes supplémentaires en fonction de votre cas d'utilisation. Amusez-vous à créer des formulaires géniaux ! ?


  • ? Plus d'exemples
  • ✅Documentation complète
  • ? Rejoignez notre Discord
  • ? Star le projet sur GitHub
  • ❤️ Parrainez Perséide

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn