Svelte هو إطار واجهة مستخدم جديد نسبيًا تم تطويره من قِبل ريتش هاريس ، وهو أيضًا مؤلف برنامج إنشاء الملفات التراكمية. على الأرجح ، سيبدو Svelte مختلفًا تمامًا عما تعاملت معه من قبل ، ولكن ربما يكون هذا جيدًا. السمتان الأكثر إثارة للإعجاب في هذا الإطار هما السرعة والبساطة. في هذه المقالة ، سوف نركز على الثاني.

نظرًا لأن تجربتي الرئيسية في مجال التطوير مرتبطة بـ Angular ، فمن الطبيعي أن أحاول تعلم Svelte عن طريق نسخ الأساليب المألوفة بالفعل لي. وهذا هو بالضبط ما ستكون عليه هذه المقالة: كيفية القيام بنفس الأشياء في Svelte كما في Angular.
ملاحظة: على الرغم من حقيقة أنني سأعبر في بعض الحالات عن تفضيلي ، فإن المقالة ليست مقارنة بالأطر. هذه مقدمة سريعة وسهلة لـ Svelte للأشخاص الذين يستخدمون Angular بالفعل كإطار عمل رئيسي.
المفسد تحذير: Svelte هو متعة.
المكونات
في Svelte ، يرتبط كل مكون بالملف حيث يتم كتابته. على سبيل المثال ، سيتم إنشاء مكون Button
عن طريق تسمية ملف Button.svelte
. بالطبع ، عادة ما نفعل الشيء نفسه في الزاوي ، ولكن معنا هو مجرد اتفاقية. (في Svelte ، قد لا يتطابق أيضًا اسم المكون المراد استيراده مع اسم الملف - ملاحظة من المترجم)
مكونات Svelte هي ملف واحد ، وتتكون من 3 أقسام: script
، style
والقالب الذي لا يحتاج إلى أن يكون ملفوفًا في أي علامة خاصة.
لنقم بإنشاء مكون بسيط جدًا يعرض "Hello World".

استيراد المكونات
بشكل عام ، يشبه هذا استيراد ملف JS ، ولكن مع اثنين من المحاذير:
- يجب عليك تحديد
.svelte
ملف المكون .svelte
بشكل صريح - يتم استيراد المكونات داخل علامة
<script>
<script> import Todo from './Todo.svelte'; </script> <Todo></Todo>
من المقتطفات أعلاه ، من الواضح أن عدد الأسطر لإنشاء مكون في Svelte صغير بشكل لا يصدق. بالطبع ، هناك بعض التضمينات والقيود ، ولكن في نفس الوقت كل شيء بسيط بما فيه الكفاية لتعتاد عليه بسرعة.
بناء الجملة الأساسية
استيفاء
التشابهات في Svelte تشبه تلك الموجودة في React أكثر من Vue أو Angular:
<script> let someFunction = () => {...} </script> <span>{ 3 + 5 }</span> <span>{ someFunction() }</span> <span>{ someFunction() ? 0 : 1 }</span>
اعتدت على استخدام الأقواس المزدوجة المتعرجة ، لذلك أنا مختوم أحيانًا ، لكن ربما أواجه هذه المشكلة فقط.
سمات
تمرير سمات للمكونات هو أيضا بسيط جدا. علامات الاقتباس اختيارية ويمكن استخدام أي تعبيرات Javascript:
//Svelte <script> let isFormValid = true; </script> <button disabled={!isFormValid}></button>
أحداث
بناء جملة معالجات الأحداث هو: on:={}
.
<script> const onChange = (e) => console.log(e); </script> <input on:input={onChange} />
على عكس الزاوي ، لا نحتاج إلى استخدام الأقواس بعد اسم الوظيفة لاستدعائها. إذا كنت بحاجة إلى تمرير الوسائط إلى المعالج ، فما عليك سوى استخدام الوظيفة المجهولة:
<input on:input={(e) => onChange(e, 'a')} />
وجهة نظري حول سهولة قراءة هذا الرمز:
- يجب أن نطبع أقل ، لأننا لسنا بحاجة إلى علامات اقتباس وأقواس - هذا أمر جيد على أي حال.
- قراءة أصعب. لطالما أحببت النهج الزاوي بدلاً من الرد ، لذا من الصعب بالنسبة لي و Svelte. ولكن هذه مجرد عادتي ورأيي متحيز إلى حد ما.
التوجيهات الهيكلية
على عكس التوجيهات المهيكلة في Vue and Angular ، تقدم Svelte بناء جملة خاص للحلقات والفروع داخل القوالب:
{#if todos.length === 0} {:else} {#each todos as todo} <Todo {todo} /> {/each} {/if}
أنا حقا أحب ذلك. ليست هناك حاجة لعناصر HTML إضافية ، ومن حيث سهولة القراءة ، فإن هذا يبدو مذهلاً. لسوء الحظ ، الرمز #
في تخطيط لوحة المفاتيح البريطانية الخاص بي Macbook في مكان لا يمكن الوصول إليه ، وهذا يؤثر سلبًا على تجربتي مع هذه الهياكل.
خصائص الإدخال
يعد تحديد الخصائص التي يمكن نقلها إلى مكون (مماثل لـ @Input
in Angular) سهلاً مثل تصدير متغير من وحدة JS باستخدام الكلمة الأساسية export
. ربما في البداية قد يكون الأمر مربكًا - ولكن دعنا نكتب مثالًا ونرى كم هو بسيط حقًا:
<script> export let todo = { name: '', done: false }; </script> <p> { todo.name } { todo.done ? '✓' : '✕' } </p>
- كما ترون ، قمنا بتهيئة خاصية ما يجب
todo
مع القيمة: ستكون قيمة الخاصية بشكل افتراضي ، في حالة عدم تمريرها من الأصل
قم الآن بإنشاء حاوية لهذا المكون ، والتي ستنقل البيانات إليها:
<script> import Todo from './Todo.svelte'; const todos = [{ name: " Svelte", done: false }, { name: " Vue", done: false }]; </script> {#each todos as todo} <Todo todo={todo}></Todo> {/each}
على غرار الحقول الموجودة في كائن JS عادي ، يمكن اختصار todo={todo}
وإعادة كتابته كما يلي:
<Todo {todo}></Todo>
في البداية بدا لي غريباً ، لكن الآن أعتقد أنه رائع.
خصائص الانتاج
لتنفيذ سلوك توجيه @Output
، على سبيل المثال ، عندما @Output
المكون الأصل أي إعلامات من الطفل ، createEventDispatcher
الدالة createEventDispatcher
، والتي تتوفر في Svelte.
- قم باستيراد دالة
createEventDispatcher
وقم بتعيين قيمة الإرجاع إلى متغير dispatch
- تحتوي وظيفة
dispatch
على معلمتين: اسم الحدث والبيانات (التي ستقع في حقل detail
الخاص بكائن الحدث) markDone
dispatch
داخل وظيفة markDone
، والتي يطلق عليها حدث النقر ( on:click
)
<script> import { createEventDispatcher } from 'svelte'; export let todo; const dispatch = createEventDispatcher(); function markDone() { dispatch('done', todo.name); } </script> <p> { todo.name } { todo.done ? '✓' : '✕' } <button on:click={markDone}></button> </p>
في المكون الأصل ، تحتاج إلى إنشاء معالج للحدث done
بحيث يمكنك وضع علامة على الكائنات الضرورية في صفيف todo
.
- إنشاء وظيفة
onDone
- نقوم بتعيين هذه الوظيفة إلى معالج الأحداث المسمى في المكون
on:done={onDone}
، كما يلي: on:done={onDone}
<script> import Todo from './Todo.svelte'; let todos = [{ name: " Svelte", done: false }, { name: " Vue", done: false }]; function onDone(event) { const name = event.detail; todos = todos.map((todo) => { return todo.name === name ? {...todo, done: true} : todo; }); } </script> {#each todos as todo} <Todo {todo} on:done={onDone}></Todo> {/each}
ملاحظة: لبدء اكتشاف التغييرات في كائن ما ، فإننا لا نغير الكائن نفسه. بدلاً من ذلك ، نقوم بتعيين متغير جديد في todos
، حيث سيتم بالفعل تغيير كائن المهمة المطلوبة إلى مكتمل.
لذلك ، يعتبر Svelte تفاعليًا حقيقيًا: مع التخصيص المعتاد لقيمة ما لمتغير ، سيتغير أيضًا الجزء المقابل من التمثيل.
ngModel
يحتوي Svelte على بناء جملة bind:<>={}
خاص bind:<>={}
لربط متغيرات محددة بسمات مكون ومزامنتها مع بعضها البعض.
بمعنى آخر ، يسمح لك بتنظيم ربط بيانات ثنائي الاتجاه:
<script> let name = ""; let description = ""; function submit(e) { </script> <form on:submit={submit}> <div> <input placeholder="" bind:value={name} /> </div> <div> <input placeholder="" bind:value={description} /> </div> <button> </button> </form>
التعبيرات التفاعلية
كما رأينا سابقًا ، يستجيب Svelte إلى تعيين قيم للمتغيرات ويعيد رسم العرض. يمكنك أيضًا استخدام التعبيرات التفاعلية للاستجابة للتغيرات في قيمة أحد المتغيرات وتحديث قيمة الآخر.
على سبيل المثال ، لنقم بإنشاء متغير من شأنه أن يوضح لنا أنه في صفيف todos
تم وضع علامة على جميع المهام على أنها مكتملة:
let allDone = todos.every(({ done }) => done);
ومع ذلك ، لن يتم إعادة رسم العرض عندما يتم تحديث الصفيف ، لأنه allDone
تعيين قيمة المتغير allDone
مرة واحدة فقط. سنستخدم تعبيرًا تفاعليًا ، والذي سيذكرنا في الوقت نفسه بوجود "علامات" في Javascript:
$: allDone = todos.every(({ done }) => done);
يبدو غريبا جدا. إذا بدا لك أن هناك "الكثير من السحر" ، فأنا أذكرك بأن العلامات صالحة لجافا سكريبت .
عرض توضيحي صغير يشرح ما يلي:

حقن المحتوى
لتضمين المحتوى ، يتم أيضًا استخدام فتحات يتم وضعها في المكان الصحيح داخل المكون.
لعرض المحتوى الذي تم نقله داخل عنصر المكون ، يتم استخدام عنصر slot
خاص:
// Button.svelte <script> export let type; </script> <button class.type={type}> <slot></slot> </button> // App.svelte <script> import Button from './Button.svelte'; </script> <Button> </Button>
في هذه الحالة ، سيأخذ ""
مكان عنصر <slot></slot>
.
ستحتاج الفتحات المسماة إلى تسمية:
// Modal.svelte <div class='modal'> <div class="modal-header"> <slot name="header"></slot> </div> <div class="modal-body"> <slot name="body"></slot> </div> </div> // App.svelte <script> import Modal from './Modal.svelte'; </script> <Modal> <div slot="header"> </div> <div slot="body"> </div> </Modal>
السنانير دورة حياة
توفر Svelte 4 خطافات لدورة الحياة التي يتم استيرادها من حزمة svelte
.
- onMount - يسمى عند تركيب مكون في DOM
- قبل التحديث - يسمى قبل تحديث المكون
- afterUpdate - يسمى بعد تحديث المكون
- onDestroy - يسمى عند إزالة مكون من DOM
تأخذ وظيفة onMount
كمعلمة وظيفة رد الاتصال التي سيتم استدعاؤها عند وضع المكون في DOM. ببساطة ، إنه يشبه ngOnInit
ربط ngOnInit
.
إذا أرجعت وظيفة رد الاتصال وظيفة أخرى ، فسيتم استدعاؤها عند إزالة المكون من DOM.
<script> import { onMount, beforeUpdate, afterUpdate, onDestroy } from 'svelte'; onMount(() => console.log('', todo)); afterUpdate(() => console.log('', todo)); beforeUpdate(() => console.log(' ', todo)); onDestroy(() => console.log('', todo)); </script>
من المهم أن تتذكر أنه عند استدعاء onMount
يجب تهيئة جميع الخصائص المضمنة فيه بالفعل. هذا ، في الجزء أعلاه ، يجب أن يكون موجود بالفعل.
إدارة الدولة
إدارة حالتك في Svelte أمر بسيط للغاية ، وربما يتعاطف معي هذا الجزء من الإطار أكثر من أي شخص آخر. يمكنك أن تنسى مدى شفافية الكود عند استخدام Redux. على سبيل المثال ، سنقوم بإنشاء تخزين في تطبيقنا للتخزين وإدارة المهام.
خزائن قابلة للتسجيل
تحتاج أولاً إلى استيراد writable
التخزين writable
من حزمة svelte/store
initialState
بالقيمة الأولية initialState
import { writable } from 'svelte/store'; const initialState = [{ name: " Svelte", done: false }, { name: " Vue", done: false }]; const todos = writable(initialState);
عادةً ما أضع رمزًا مشابهًا في ملف منفصل مثل todos.store.js
وقم بتصدير متغير التخزين منه حتى يتمكن المكون الذي todos.store.js
من العمل به.
من الواضح أن كائن todos
أصبح الآن مستودعًا ولم يعد صفيفًا. للحصول على قيمة التخزين ، سنستخدم سحرًا صغيرًا في Svelte:
- بإضافة الحرف
$
إلى اسم متغير التخزين ، يمكننا الوصول مباشرة إلى قيمتها!
وبالتالي ، فإننا ببساطة نستبدل في الكود جميع الإشارات إلى متغير todos
بـ $todos
:
{#each $todos as todo} <Todo todo={todo} on:done={onDone}></Todo> {/each}
وضع الدولة
يمكن تحديد القيمة الجديدة للتخزين القابل للتسجيل عن طريق استدعاء الأسلوب set
، والذي يغير الحالة وفقًا للقيمة التي تم تمريرها:
const todos = writable(initialState); function removeAll() { todos.set([]); }
تحديث الحالة
لتحديث وحدة التخزين (في حالتنا ، todos
) ، بناءً على حالتها الحالية ، تحتاج إلى استدعاء طريقة update
وتمريرها وظيفة رد اتصال ستعيد الحالة الجديدة للتخزين.
نعيد كتابة وظيفة onDone
التي أنشأناها سابقًا:
function onDone(event) { const name = event.detail; todos.update((state) => { return state.map((todo) => { return todo.name === name ? {...todo, done: true} : todo; }); }); }
أنا هنا استخدم المخفض مباشرة في المكون ، وهو ممارسة سيئة. نقوم بنقله إلى ملف به مستودعنا وتصدير وظيفة منه ستقوم ببساطة بتحديث الحالة.
تغيير حالة الاشتراك
لمعرفة أن القيمة في المستودع قد تغيرت ، يمكنك استخدام طريقة subscribe
. ضع في اعتبارك أن المستودع ليس كائنًا observable
، ولكنه يوفر واجهة مشابهة.
const subscription = todos.subscribe(console.log); subscription();
المتغيرات الظاهرة
إذا تسبب هذا الجزء في إثارة أكبر لك ، فأسرعت لإرضاء أنه منذ وقت ليس ببعيد ، تمت إضافة دعم RxJS إلى Svelte وتم تقديم Observable for ECMAScript.
كمطور Angular ، اعتدت بالفعل على العمل مع البرمجة التفاعلية ، وسيكون عدم وجود نظير توجيه غير متزامن غير مريح للغاية. ولكن فاجأتني Svelte هنا أيضًا.
دعونا نلقي نظرة على مثال لكيفية عمل هذه الأدوات معًا: عرض قائمة من المستودعات على Github ، التي عثر عليها بالكلمة الرئيسية "Svelte"
.
يمكنك نسخ الكود أدناه وتشغيله مباشرة في REPL :
<script> import rx from "https://unpkg.com/rxjs/bundles/rxjs.umd.min.js"; const { pluck, startWith } = rx.operators; const ajax = rx.ajax.ajax; const URL = `https://api.github.com/search/repositories?q=Svelte`; const repos$ = ajax(URL).pipe( pluck("response"), pluck("items"), startWith([]) ); </script> {#each $repos$ as repo} <div> <a href="{repo.url}">{repo.name}</a> </div> {/each}
فقط أضف رمز $
إلى اسم المتغير الذي يمكن ملاحظته repos$
وسيعرض Svelte محتوياته تلقائيًا.
قائمة أمنياتي ل Svelte
دعم الطباع
بصفتي متحمسًا لـ Typescript ، لا يسعني إلا أن أتمنى إمكانية استخدام أنواع في Svelte. أنا معتاد على ذلك أحيانًا ما يتم ترحيلي وترتيب أنواع في الكود الخاص بي ، والتي يجب علي إزالتها بعد ذلك. آمل حقًا أن تضيف Svelte قريبًا دعم Typescript. أعتقد أن هذا العنصر سيكون في قائمة الأمنيات لأي شخص يريد استخدام Svelte مع تجربة Angular.
الاتفاقيات والمبادئ التوجيهية
يعد تقديم أي متغير من كتلة <script>
ميزة قوية جدًا للإطار ، لكن في رأيي ، قد يؤدي ذلك إلى ازدحام التعليمات البرمجية. آمل أن يعمل مجتمع Svelte من خلال عدد من الاتفاقيات والإرشادات لمساعدة المطورين على كتابة رمز مكون نظيف ومفهوم.
دعم المجتمع
Svelte هو مشروع فخم ، مع زيادة جهد المجتمع في كتابة حزم الطرف الثالث ، والأدلة ، ومقالات المدونات ، وأكثر من ذلك ، يمكن أن ينطلق ويصبح أداة معروفة في عالم تطوير Frontend المذهل الذي لدينا اليوم.
في الختام
على الرغم من أنني لم أكن معجبًا بالإصدار السابق من الإطار ، إلا أن Svelte 3 تركت انطباعًا جيدًا عني. انها بسيطة وصغيرة ، ولكن يمكن أن تفعل الكثير. إنه مختلف تمامًا عن كل شيء حوله ، وقد ذكرني بالإثارة التي مررت بها عندما انتقلت من jQuery إلى Angular.
بغض النظر عن الإطار الذي تستخدمه الآن ، من المرجح أن يستغرق تعلم Svelte بضع ساعات فقط. بمجرد أن تتعلم الأساسيات وتفهم الاختلافات مع ما اعتدت على كتابته ، سيكون العمل مع Svelte سهلاً للغاية.
في قناة Telegram باللغة الروسية @ sveltejs ، ستجد بالتأكيد مطورين يتمتعون بخبرة في مختلف الأطر وعلى استعداد لمشاركة قصصهم وأفكارهم ونصائحهم بشأن Svelte.