이 가이드에서는 Formly 및 Superforms의 강력한 대안인 @perseid/form 라이브러리를 사용하여 동적 사용자 피드백 양식을 작성하는 과정을 안내합니다. @perseid/form을 사용하여 양식 상태, 유효성 검사 및 조건부 렌더링을 쉽게 관리하는 방법을 살펴보겠습니다. 우리가 만들 양식은 사용자에게 서비스를 평가하고 피드백을 제공하도록 요청합니다. 평가에 따라 "감사합니다" 메시지가 표시되거나 사용자에게 추가 피드백을 제공하라는 메시지가 표시됩니다.
? 시작해 보세요!
첫 번째 단계는 양식 구성을 정의하는 것입니다. 이 구성은 필드, 단계 및 이들 사이의 흐름을 포함하여 양식이 작동하는 방식을 간략하게 설명합니다. 여기서는 사용자 평가에 따른 조건부 논리를 사용하여 평가 및 리뷰를 위한 필드를 생성하겠습니다. 또한 긍정적인 피드백과 부정적인 피드백에 대한 메시지를 정의할 것입니다.
구성 코드는 다음과 같습니다.
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"], }, }, };
이 구성에서는:
여기서 핵심적으로 파악해야 할 점은 필드 속성의 기능입니다. 이는 제출될 데이터의 구조를 정의하며 본질적으로 데이터 모델 역할을 합니다. 이와 대조적으로 steps 속성은 양식의 흐름을 간략하게 설명하여 이러한 필드가 사용자에게 표시되는 방식을 결정합니다.
이제 구성이 완료되었으므로 양식을 렌더링할 실제 UI를 구축할 차례입니다. @perseid/form/svelte를 사용하면 사용자 정의 필드 구성 요소를 만들어 양식의 각 부분에 대한 사용자 상호 작용을 관리할 수 있습니다.
핵심 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}
여기서 Field 구성 요소는 경로 소품을 사용하여 렌더링할 대상을 결정합니다.
평가에 따라 표시되는 '감사합니다' 메시지입니다. 양식은 사용자 입력에 따라 필드와 단계를 동적으로 조정합니다.
정말 멋지죠?
이제 양식 구성과 구성 요소가 준비되었으므로 기본 Svelte 앱에 통합해 보겠습니다. 양식을 초기화하고 렌더링하는 코드는 다음과 같습니다.
// 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, });
이 코드는 양식을 DOM에 마운트합니다. 구성과 필드 구성 요소를 연결하는 양식 구성 요소가 다른 모든 것을 처리합니다.
알겠습니다. 앱 로직이 있지만 지금 코드를 실행해 보면 약간... 원시적이라는 것을 알 수 있습니다.
스타일과 애니메이션을 추가하여 양식을 멋지게 만들어 보겠습니다! 다음은 훨씬 더 매력적인 간단한 스타일시트입니다.
// 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; } }
자, 짜잔?
축하합니다! ? Perseid와 Svelte를 사용하여 동적 사용자 피드백 양식을 구축했습니다.
이 튜토리얼에서는 다음 방법을 살펴보았습니다.
사용 사례에 맞게 추가 필드와 단계를 자유롭게 실험해 보세요. 멋진 양식을 재미있게 만들어 보세요! ?
위 내용은 Svelte 및 Perseid를 사용하여 사용자 피드백 양식 작성의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!