قبل أن أبدأ – لتحديد بعض السياق – من خلال إطار عمل الواجهة الأمامية ، ما أعنيه هو إطار عمل يسمح لنا بذلك يتجنب الحاجة إلى كتابة HTML و JavaScript قديم عادي مثل هذا:
id="cool-para">
const coolPara = 'Lorem ipsum.'; const el = document.getElementById('cool-para'); el.innerText = coolPara;
وبدلاً من ذلك يسمح لنا بكتابة كود HTML و JavaScript سحري مثل هذا (Vue):
> const coolPara = 'Lorem ipsum.'; {{ coolPara }}
أو هذا (تتفاعل):
export default function Para() { const coolPara = 'Lorem ipsum'; return <p>{ coolPara }p>;}
ومزايا مثل هذا الإطار مفهومة. تذكر كلمات أو عبارات مثل document
و innerText
، و getElementById
صعبة – الكثير من المقاطع!
حسنًا ، عدد المقاطع ليس هو السبب الرئيسي.
التفاعلية ✨
ال أول رئيسي السبب هو أنه في المثالين الثاني والثالث ، يمكننا فقط تعيين قيمة المتغير أو تحديثها coolPara
والترميز – أي ملف
عنصر — يتم تحديثه دون الحاجة إلى تعيينه بشكل صريح innerText
.
هذا يسمي التفاعلية، ترتبط واجهة المستخدم بالبيانات بطريقة تؤدي فقط بتغيير البيانات إلى تحديث واجهة المستخدم.
التركيب ✨
ال الرئيسية الثانية السبب هو القدرة على تحديد المكون وإعادة استخدامه دون الحاجة إلى إعادة تعريفه في كل مرة نحتاج إلى استخدامه. هذا يسمي القدرة على التأليف.
لا يحتوي HTML + JavaScript العادي على هذا افتراضيًا. وهكذا فإن الكود التالي يفعل لا افعل ما تشعر به يجب أن:
name="cool-para"> /> Lorem ipsum.
التفاعل والتركيب هما العاملان الأساسيان اللذان توفرهما لنا أطر الواجهة الأمامية المعتادة مثل Vue و React وما إلى ذلك.
لا تُمنح هذه التجريدات مجانًا ، يتعين على المرء تحميل مجموعة من المفاهيم المحددة لإطار العمل مسبقًا ، والتعامل مع تسريبها عندما تعمل الأشياء بطرق سحرية بشكل غير مفهوم ، ناهيك عن حمولة كاملة من التبعيات المعرضة للفشل.
ولكن اتضح أن استخدام واجهات برمجة تطبيقات الويب الحديثة ليس من الصعب جدًا تحقيق هذين الأمرين. وفي معظم حالات الاستخدام ، قد لا نحتاج في الواقع إلى الأطر المعتادة ونشفر التعقيدات …
التفاعلية
عبارة بسيطة تشرح التفاعل عند تحديث البيانات ، قم بتحديث واجهة المستخدم تلقائيًا.
الجزء الأول هو أن تعرف عندما يتم تحديث البيانات. هذا للأسف ليس شيئًا كائن عادي يقدر على. لا يمكننا فقط إرفاق مستمع يسمى ondataupdate
للاستماع إلى أحداث تحديث البيانات.
لحسن الحظ ، تحتوي JavaScript على الشيء الذي يسمح لنا بالقيام بذلك ، يطلق عليه Proxy
.
Proxy
أشياء
Proxy
يسمح لنا بإنشاء ملف كائن وكيل من كائن عادي:
const user = { name: 'Lin' };const proxy = new Proxy(user, {});
وهذا كائن وكيل يمكن بعد ذلك الاستماع إلى التغييرات على البيانات.
في المثال أعلاه لدينا كائن وكيل، لكنها لا تفعل أي شيء عندما يتعلق الأمر بمعرفة ذلك name
تغير.
لذلك نحن بحاجة إلى معالج، وهو كائن يخبر كائن وكيل ماذا تفعل عندما يتم تحديث البيانات.
// Handler that listens to data assignment operationsconst handler = { set(user, value, property) { console.log(`${property} is being updated`); return Reflect.set(user, value, property); },};// Creating a proxy with the handlerconst user = { name: 'Lin' };const proxy = new Proxy(user, handler);
الآن كلما قمنا بتحديث name
باستخدام proxy
كائن ، سوف نحصل على رسالة تقول "name is being updated"
.
إذا كنت تتساءل ، ما هي الصفقة الكبيرة ، كان بإمكاني فعل ذلك باستخدام عجوز عادي واضعسأخبرك بالصفقة:
- طريقة الوكيل معممة ، ويمكن إعادة استخدام المعالجات ، مما يعني أن …
- أي القيمة التي تحددها على كائن وكيل يمكن تحويلها بشكل متكرر إلى وكيل ، مما يعني أن …
- لديك الآن هذا الكائن السحري مع القدرة على ذلك تتفاعل لتحديثات البيانات بغض النظر عن مدى تداخلها.
بخلاف هذا يمكنك مقبض العديد من أحداث الوصول الأخرى مثل عندما تكون الخاصية يقرأو محدثو تم الحذف، إلخ.
الآن بعد أن أصبح لدينا القدرة على الاستماع والاستماع إلى العمليات ، نحتاج إلى ذلك تتفاعل لهم بطريقة ذات مغزى.
تحديث واجهة المستخدم
إذا كنت تتذكر ، الجزء الثاني من التفاعلية كان تحديث واجهة المستخدم تلقائيًا. لهذا نحن بحاجة إلى إحضار ملائم سيتم تحديث عنصر واجهة المستخدم. ولكن قبل ذلك ، نحتاج أولاً إلى تمييز عنصر واجهة المستخدم على أنه ملائم.
للقيام بذلك سوف نستخدم سمات البيانات، وهي ميزة تسمح لنا بتعيين قيم عشوائية على عنصر:
data-mark="name">
تتمثل دقة سمات البيانات في أنه يمكننا الآن العثور على جميع سمات ملائم العناصر باستخدام:
document.querySelectorAll('[data-mark="name"]');
الآن قمنا بتعيين ملف innerText
من كل العناصر المناسبة:
const handler = { set(user, value, property) { const query = `[data-mark="${property}"]`; const elements = document.querySelectorAll(query); for (const el of elements) { el.innerText = value; } return Reflect.set(user, value, property); },};// Regular object is omitted cause it's not needed.const user = new Proxy({ name: 'Lin' }, handler);
هذا كل شيء ، هذا هو جوهر التفاعل!
بسبب الطبيعة العامة لدينا handler
، ل أي ممتلكات user
الذي تم تعيينه ، كل ملائم سيتم تحديث عناصر واجهة المستخدم.
هذا هو مدى قوة جافا سكريبت Proxy
الميزات ، مع عدم وجود تبعيات وبعض الذكاء يمكن أن تعطينا هذه السحرية رد الفعل أشياء.
الآن على الرئيسية الثانية شيء…
التوافق
تبين أن المتصفحات لديها بالفعل ميزة كاملة مخصصة لهذا يسمى مكونات الويب، من يعرف!
قليل من استخدامه يسبب القليل من الألم في الحمار لاستخدامه (وأيضًا لأن معظمهم يصلون إلى الأطر المعتادة كإعداد افتراضي عند بدء مشروع ، بغض النظر عن النطاق).
ل القدرة على التأليف نحتاج أولاً إلى تحديد المكونات.
تحديد المكونات باستخدام template
و slot
ال تُستخدم العلامات لاحتواء الترميز الذي لا يعرضه المتصفح. على سبيل المثال ، يمكنك إضافة الترميز التالي في HTML الخاص بك:
Will not render!
ولن يتم تقديمها. يمكنك اعتبارها حاويات غير مرئية لمكوناتك.
اللبنة التالية هي
عنصر يحدد مكان وضع محتوى المكون فيه. يمكّن هذا المكون من إعادة استخدامه بمحتوى مختلف ، أي يصبح مؤلف.
على سبيل المثال ، إليك عنصر h1 يقوم بتلوين نصه باللون الأحمر.
style="color: red">
/>
قبل أن نبدأ في استخدام مكوناتنا — مثل الأحمر h1 أعلاه ، نحتاج إلى تسجيلها.
تسجيل المكونات
قبل أن نتمكن من تسجيل مكوننا الأحمر h1 ، نحتاج إلى اسم لتسجيله بواسطته. يمكننا فقط استخدام name
السمة لذلك:
name="red-h1"> style="color: red">
/>
والآن ، باستخدام بعض JavaScript ، يمكننا الحصول على المكون واسمه:
const template = document.getElementsByTagName('template')[0];const componentName = template.getAttribute('name');
ثم أخيرًا قم بتسجيله باستخدام customElements.define
:
customElements.define( componentName, class extends HTMLElement { constructor() { super(); const component = template.content.children[0].cloneNode(true); this.attachShadow({ mode: 'open' }).appendChild(component); } });
هناك الكثير مما يحدث في الكتلة أعلاه:
- نحن نتصل
customElements.define
مع حجتين. - الوسيطة الأولى هي اسم المكون (ie
"red-h1"
). - الوسيطة الثانية هي فئة تعرف المكون المخصص لدينا على أنه
HTMLElement
.
ما نقوم به في مُنشئ الفصل الدراسي هو استخدام نسخة من القالب red-h1
لتعيين الظل شجرة DOM.
ما هو Shadow DOM؟
الظل DOM هو ما يحدد تصميم العديد من العناصر الافتراضية مثل نطاق الإدخال، أو أ عنصر الفيديو.
يكون ظل DOM الخاص بالعنصر مخفيًا بشكل افتراضي وهذا هو سبب عدم قدرتنا على رؤيته في وحدة تحكم dev ، ولكننا هنا نقوم بتعيين mode
ل 'open'
.
هذا يسمح لنا بفحص العنصر ومعرفة أن اللون الأحمر h1 متصل بـ #shadow-root
.
الاتصال customElements.define
سيسمح لنا باستخدام المكون المحدد مثل عنصر HTML عادي.
This will render in red!
لوضع هذين المفهومين معًا!
القابلية للتركيب + التفاعلية
خلاصة سريعة ، قمنا بأمرين:
- أنشأنا بنية بيانات تفاعلية مثل كائنات الوكيل والتي عند تعيين القيمة يمكنها تحديث أي عنصر وضعنا علامة عليه ملائم.
- حددنا مكونًا مخصصًا
red-h1
والتي ستجعل محتواها مثل h1 أحمر.
يمكننا الآن جمعهما معًا:
data-mark="name"> const user = new Proxy({}, handler); user.name = 'Lin';
ولديك مكون مخصص يعرض بياناتنا وتحديث واجهة المستخدم عندما نغير البيانات.
بالطبع ، لا تقوم أطر الواجهة الأمامية المعتادة بهذا فقط ، بل إنها تمتلك تركيبًا متخصصًا مثل بناء جملة النموذج في Vue و JSX في React الذي يجعل الكتابة الواجهات المعقدة أكثر إيجازًا نسبيًا مما قد يكون عليه الأمر بخلاف ذلك.
نظرًا لأن هذا التركيب المتخصص ليس JavaScript أو HTML عاديًا ، فإنه لا يمكن تحليله بواسطة مستعرض ولذا يحتاجون جميعًا إلى أدوات متخصصة لتجميعها وصولاً إلى JavaScript و HTML و CSS العادية قبل أن يتمكن المتصفح من فهمها. و حينئذ، لم يعد أحد يكتب JavaScript بعد الآن.
حتى بدون بناء جملة متخصص ، يمكنك القيام بالكثير مما يفعله إطار عمل الواجهة الأمامية المعتاد — بإيجاز مماثل — فقط باستخدام Proxy
و WebComponents
.
الكود هنا هو تبسيط أكثر من اللازم ولتحويله إلى إطار عمل عليك تجسيده. ها هي محاولتي لفعل ذلك بالضبط: إطار عمل يسمى الفراولة.
أثناء تطوير هذا ، أخطط للحفاظ على قيدين صعبين:
- لا تبعيات.
- لا توجد خطوة بناء قبل أن يمكن استخدامها.
وقيد ناعم للحفاظ على قاعدة الشفرة صغيرة. في وقت كتابة هذا التقرير ، كان الأمر مجرد ملف ملف واحد بأقل من 400 كلوك، دعنا نرى إلى أين تذهب. ✌️
أيضًا ، إليك ملف مناقشة HN لهذا المنصب.