منطق شرطی در Svelte و توضیح Promise و رویدادها — آموزش Svelte (بخش پنجم-پایانی)
در یک کامپوننت Svelte هنگامی که قصد داریم HTML را رندر کنیم، میتوانیم با برخی ساختارهای خاص برای ساخت UI در هر مرحله از چرخه عمر اپلیکیشن کار کنیم. در این مقاله با منطق شرطی در Svelte و همچنین Promise-ها و رویدادها آشنا خواهیم شد. برای مطالعه بخش قبلی این سری مقالات آموزشی روی لینک زیر کلیک کنید:
فرض کنید میخواهید یک مقدار/عبارت را بررسی کنید و در صورتی که به یک مقدار true اشاره میکند کاری را انجام دهید و در صورتی که به مقدار false اشاره میکند کار دیگری را انجام دهید. Svelte یک مجموعه قدرتمند از ساختارهای کنترلی پیشنهاد میشوند. نخستین مورد if است:
1{#if isRed}
2 <p>Red</p>
3{/if}
چنان که میبینید یک بلوک آغازین #if#} و یک بلوک پایانی {if/} وجود دارد. ساختار آغازین درست بودن یک مقدار یا گزاره را بررسی میکند. در این حالت isRed میتواند یک مقدار بولی با مقدار true باشد:
1<script>
2let isRed = true
3</script>
- یک رشته خالی مقدار false دارد، اما یک رشته دارای محتوا مقدار بولی true دارد.
- مقدار 0 به صورت false است، اما اعداد بزرگتر از 0 true هستند.
- مقدار بولی true خود true است و البته مقدار بولی false نیز خود false است.
اگر مارکاپ آغازین برآورده شود و مقدار flase ارائه شده باشد، در این صورت اتفاقی نمیافتد.
برای این که در بخش else نیز کاری انجام یابد، باید از گزاره else مناسبی استفاده کنیم:
1{#if isRed}
2 <p>Red</p>
3{:else}
4 <p>Not red</p>
5{/if}
در قالب فوق یا بخش نخست رندر میشود یا بخش دوم. هیچ گزینه دیگری وجود ندارد. میتوان از هر عبارت جاوا اسکریپت درون شرط بلوک if استفاده کرد و از این رو میتوانید یک گزینه را با استفاده از ! منفی کنید:
1{#if !isRed}
2 <p>Not red</p>
3{:else}
4 <p>Red</p>
5{/if}
اکنون درون else میتوانید یک شرط دیگر را بررسی کنید. این همان جایی است که ساختار {else if somethingElse:} به کار میآید:
1{#if isRed}
2 <p>Red</p>
3{:else if isGreen}
4 <p>Green</p>
5{:else}
6 <p>Not red nor green</p>
7{/if}
میتوان تعداد زیادی از این بلوکها و نه فقط یکی داشت و میتوان آنها را به صورت تودرتو تعریف کرد. در ادامه مثال پیچیدهتری را مشاهده میکنید:
1{#if isRed}
2 <p>Red</p>
3{:else if isGreen}
4 <p>Green</p>
5{:else if isBlue}
6 <p>It is blue</p>
7{:else}
8 {#if isDog}
9 <p>It is a dog</p>
10 {/if}
11{/if}
تعریف حلقه در Svelte
در این بخش به بررسی حلقهها در فریمورک Svlete میپردازیم. در قالبهای Svlete میتوان با استفاده از ساختار {#each}{/each} حلقههایی ایجاد کرد:
1<script>
2let goodDogs = ['Roger', 'Syd']
3</script>
4
5{#each goodDogs as goodDog}
6 <li>{goodDog}</li>
7{/each}
اگر با فریمورکهای دیگر که از قالبها استفاده میکنند، آشنایی داشته باشید، میبینید که ساختار کاملاً مشابهی دارند. اندیس تکرار را میتوان با استفاده از کد زیر به دست آورد:
1<script>
2let goodDogs = ['Roger', 'Syd']
3</script>
4
5{#each goodDogs as goodDog, index}
6 <li>{index}: {goodDog}</li>
7{/each}
توجه کنید که اندیسها از صفر آغاز میشوند. هنگامی که لیستها را به صورت دینامیک ویرایش میکنید و آیتمها را حذف و اضافه مینمایید، میتوانید یک شناسه در لیستها ارسال کنید تا از بروز مشکل جلوگیری کنید. این کار با استفاده از ساختار زیر انجام مییابد:
1<script>
2let goodDogs = ['Roger', 'Syd']
3</script>
4
5{#each goodDogs as goodDog (goodDog)}
6 <li>{goodDog}</li>
7{/each}
8
9<!-- with the index -->
10{#each goodDogs as goodDog, index (goodDog)}
11 <li>{goodDog}</li>
12{/each}
میتوانید یک شیء نیز ارسال کنید، اما اگر لیست شما یک شناسه یکتا برای هر عنصر داشته باشد بهتر است از آن استفاده کنید:
1<script>
2let goodDogs = [
3 { id: 1, name: 'Roger'},
4 { id: 2, name: 'Syd'}
5]
6</script>
7
8{#each goodDogs as goodDog (goodDog.id)}
9 <li>{goodDog.name}</li>
10{/each}
11
12<!-- with the index -->
13{#each goodDogs as goodDog, index (goodDog.id)}
14 <li>{goodDog.name}</li>
15{/each}
Promise-ها در قالبهای Svelte
Promise-ها ابزار جالبی هستند که با آنها میتوان با رویدادهای ناهمگام در جاوا اسکریپت کار کرد. Promise-ها همراه با ساختار await در ES2017 در سطح قالب معرفی شدهاند. ما میتوانیم صبر کنیم تا Promise-ها resolve شوند و یک UI دیگر برای حالتهای مختلف یک Promise تعریف کنیم که شامل unresolved ،resolved و rejected میشود. طرز کار آن به صورت زیر است. ابتدا یک Promise تعریف میکنیم و از بلوک استفاده کرده و صبر میکنیم تا resolve شود. زمانی که Promise به صورت resolve در آمد، نتیجه به بلوک {then:} ارسال میشود:
1<script>
2 const fetchImage = (async () => {
3 const response = await fetch('https://dog.ceo/api/breeds/image/random')
4 return await response.json()
5 })()
6</script>
7
8{#await fetchImage}
9 <p>...waiting</p>
10{:then data}
11 <img src={data.message} alt="Dog image" />
12{/await}
ریجکت شدن یک Promise را میتوانید با افزودن بلوک {catch:} متوجه شوید:
1{#await fetchImage}
2 <p>...waiting</p>
3{:then data}
4 <img src={data.message} alt="Dog image" />
5{:catch error}
6 <p>An error occurred!</p>
7{/await}
کار با رویدادها در Svlete
در این بخش در مورد رویدادها و شیوه کار کردن با آنها در فریمورک Svlete صحبت میکنیم.
گوش دادن به رویدادهای DOM
در Svelte میتوان یک listener برای یک رویداد DOM مستقیماً درون قالب و با استفاده از ساختار <on:<event تعریف کرد. برای نمونه برای گوش دادن به رویداد click یک تابع به خصوصیت on:click ارسال میکنیم. برای گوش دادن به رویداد onmousemove باید یک تابع به خصوصیت on:mousemove ارسال کنیم. در ادامه مثالی از این وضعیت همراه با مدیریت تابع تعریف به صورت inline را میبینیم:
1<button on:click={() => {
2 alert('clicked')
3}}>Click me</button>
و در ادامه مثالی دیگر همراه با مدیریت تابع تعریف در بخش script کامپوننت را میبینیم:
1<script>
2const doSomething = () => {
3 alert('clicked')
4}
5</script>
6
7<button on:click={doSomething}>Click me</button>
استفاده از ساختار inline ترجیح بیشتری دارد، زیرا طولانی نیست. برای نمونه در اغلب موارد 2 یا 3 خط طول دارد که اختلاف زیادی با روش استفاده از بخش script دارد. Svelte دستگیره رویداد را به صورت یک آرگومان تابع ارسال میکند که در صورت نیاز به توقف انتشار یا ارجاع به چیزی در شیء رویداد مفید است:
1<script>
2const doSomething = event => {
3 console.log(event)
4 alert('clicked')
5}
6</script>
7
8<button on:click={doSomething}>Click me</button>
در بخش قبلی به «توقف انتشار» (stop propagation) اشاره کردیم. این وضعیت در زمان رویداد submit فرم بسیار رایج است. Svelte مادیفایرها را در اختیار ما قرار میدهد که روشی برای اعمال مستقیم آن بدون نیاز به انجام کار دیگر است. stopPropagation و preventDefault دو مادیفایر هستند که به طور مکرر استفاده میشوند. برای استفاده از مادیفایر به صورت زیر عمل میکنیم:
1<button on:click|stopPropagation|preventDefault={doSomething}>Click me</button>
مادیفایرهای دیگری هم وجود دارد که کارآمد هستند. capture امکان در اختیار گرفتن رویدادها را به جای buble کردن آنها فراهم میسازد. once تنها روی رویداد اول فعال میشود، self تنها در صورتی روی رویداد فعال میشود که هدف رویداد این شیء باشد.
ایجاد رویدادهای سفارشی در کامپوننتها
نکته جالب این است که ما میتوانیم رویدادهای سفارشی خودمان را در کامپوننتها بسازیم و از ساختار مشابه رویدادهای داخلی DOM استفاده کنیم. به این منظور باید تابع createEventDispatcher را از پکیج svelte ایمپورت کنیم و آن را برای دریافت یک رویداد فراخوانی نماییم:
1<script>
2 import { createEventDispatcher } from 'svelte'
3 const dispatch = createEventDispatcher()
4</script>
زمانی که این کار انجام یافت، میتوانیم تابع ()dispatch را فراخوانی کنیم و یک رشته ارسال کنیم که رویداد را شناسایی میکند. در این مورد از ساختار on: در کامپوننتهای دیگر که از آن استفاده میکنند بهره میگیریم:
1<script>
2 import { createEventDispatcher } from 'svelte'
3 const dispatch = createEventDispatcher()
4
5 //when it's time to trigger the event
6 dispatch('eventName')
7</script>
اکنون کامپوننتهای دیگر میتوانند از رویدادها به صورت زیر استفاده کنند: