من المترجممن مترجم : منذ عامين ، بدأت أول مشروع لي على Angular (2+) ، ولدي خلفية كبيرة وناجحة من AngularJS. يتطلب الانتقال تنسيقًا ملحوظًا للتفكير ، حيث أن الكثير من A1 و A2 + يتم "بشكل مختلف قليلاً". قللت من وجع الانتقال بشكل ملحوظ بلوق
ثينكرام لي . قبل عام ، تلقيت إذنًا لترجمة هذه المقالة "حول الابتدائية ويمكن للجميع فهمها بسهولة". لكنهم مثل هذه الأيدي (مقالاتهم هي مجموعة من تلك التي لم تكتمل). والمثير للدهشة ، أن المقالة تترجم بشكل جيد على ترجمة جوجل. لكن بعض الفروق الدقيقة في هذه الترجمة ضاعت ، ناهيك عن أسلوب المؤلف. لم يتم الحفاظ على أسلوب المؤلف بالكامل في روايتي. لكن ، آمل ، تمكنت من نقل مزاج وأفكار المقال.
أدرك أن Angular ليس الموضوع الأكثر شيوعًا على Habré ، لكنني آمل أن تساعد الترجمة شخصًا ، تمامًا كما ساعدتني المقالة الأصلية ذات مرة.
هذا ما تسبب في تأثير نجاح باهر في AngularJS القديمة الجيدة ، لذلك هو "في اتجاهين ملزمة." وقع هذا السحر على الفور في حب AngularJS ، وكسر جميع الأفكار حول برمجة الصفحات المملة ونماذج الويب (أوه ، الرعب!). يتم عرض التغييرات على البيانات على الفور على الشاشة والعكس. أولئك الذين قاموا بتطوير تطبيقات jQuery سابقًا ينظر إليهم على أنهم يقعون في قصة خرافية. وبدأت الوحوش الملتحية ، التي كانت تنشر زبائن سمينين قبل jQuery ، بشكل محموم في حساب الشهور الضائعة من الغباء.
علاوة على ذلك ، كان سحر الربط ثنائي الاتجاه متاحًا ليس فقط للرموز الخاصة والمكونات المحددة. يمكننا استخدامه بسهولة في التوجيهات والمكونات الخاصة بنا (فقط عن طريق تعيين معلمة التكوين).
في Angular2 + ، تخلى المبدعون عن ربط البيانات ثنائي الاتجاه المدمج (باستثناء خلال ngModel). ولكن هذا لا يعني أننا لا نستطيع استخدام الربط ثنائي الاتجاه في توجيهاتنا الخاصة ... إنه مجرد انتهاء الهدية الترويجية والآن نحن بحاجة إلى القيام بشيء من تلقاء أنفسنا. ويفضل ، مع فهم كيف يعمل في الزاوي.
جدول المحتويات
ملزمة في اتجاهين باختصار
في A2 + ، يقوم توجيه واحد فقط بتنفيذ ربط البيانات ثنائي الاتجاه:
ngModel . للوهلة الأولى ، هذا هو السحر نفسه في AngularJS (فقط بترميز مختلف). ولكن ما هو تحت غطاء محرك السيارة؟
من المثير للدهشة ، تحت الغطاء ، يكون كل شيء بسيطًا ومنطقيًا نسبيًا: يتم تقليل الربط ثنائي الاتجاه إلى ربط الممتلكات وتجليد الأحداث. ارتباطان أحاديان ، بدلاً من ارتباط ثنائي؟ حسنا ، دعنا اثنين.
وعلى الفور مثال:
<input [(ngModel)]="username"> <p>Hello {{username}}!</p>
نعم ، نعم ، هذا عرض توضيحي جميل ومذهل لـ Angular2 من عام 2009. لا تمزح ، جميل. عند تغيير الحقل ، تندرج قيمة
اسم المستخدم في النموذج ، وتنعكس على الفور في رسالة الترحيب في النموذج.
ولكن كيف يعمل؟ تذكر أن الربط ثنائي الاتجاه في Angular2 هو خاصية ربط وملزمة حدث. ونعم ، يمكن أن تكون متاحة في وقت واحد في توجيه واحد. علاوة على ذلك ، حتى بدون
ngModel ، يمكننا بسهولة تنفيذ ربط البيانات ثنائي الاتجاه. على سبيل المثال ، مثل هذا:
<input [value]="username" (input)="username = $event.target.value"> <p>Hello {{username}}!</p>
الإخراج
{{اسم المستخدم}} واضح ، ولكن ما هو مكتوب هناك في
الإدخال ؟ دعنا نفهم:
- [value] = "اسم المستخدم" - التدوين بأقواس مربعة ، يربط تعبير اسم المستخدم بخاصية القيمة
- (إدخال) = "تعبير" - تدوين ذو أقواس ، التعبير مرتبط بحدث الإدخال (نعم ، يوجد مثل هذا الحدث). في حالتنا:
- اسم المستخدم = $ event.target.value - سيتم تنفيذ هذا التعبير استجابةً لحدث الإدخال
- حدث $ هو متغير اصطناعي في أحداث Angular يحمل حمولة: في هذه الحالة ، يحتوي على معلومات حول ما حدث ومحيطه
هل تزداد وضوحا؟ نحن إصلاحه.
نربط خاصية
اسم المستخدم للنموذج الزاوي بخاصية
القيمة لعنصر إدخال المستعرض (الربط أحادي الاتجاه من النموذج إلى العرض).
نربط أيضًا تعبيرًا عن حدث
إدخال عنصرنا. الذي يعين قيمة
$ event.target.value لخاصية
اسم المستخدم للنموذج.
ما هو
$ event.target.value ؟ كما ذكرنا سابقًا ،
الحدث $ مليء بمعلومات مفيدة مختلفة حول الحدث. في هذه الحالة ، يعد
InputEventObject تشير فيه الخاصية
الهدف إلى عنصر DOM الذي
أدى إلى تشغيل الحدث (أي عنصر الإدخال الخاص بنا).
لذلك ، كل ما نقوم به هو قراءة محتويات (
قيمة ) عنصر الإدخال (
$ event.target ) عندما يقوم المستخدم بإدخال قيمة. وعندما نقوم بتعيين قيمة اسم المستخدم هذه ، سيتم إرسال بيانات العرض إلى النموذج.
هذا كل شيء. هذا هو "الربط ثنائي الاتجاه باختصار .
" الجمال؟
لكن متى يتم
تشغيل ngModel ؟ سيناريو العمل مع عناصر الإدخال شائع جدًا وفي الطلب. ولسبب ما أريد الحصول على توجيه يخفي التنفيذ ويحفظه من ضغطات المفاتيح الإضافية.
فهم ngModel
إذا نظرت إلى المصدر ، يمكنك التأكد من أن
ngModel يحتوي أيضًا على رابط للخاصية والحدث. إليك ما يبدو عليه مثال ngModel الخاص بنا ، ولكن دون استخدام بناء جملة مختزل:
<input [ngModel]="username" (ngModelChange)="username = $event"> <p>Hello {{username}}!</p>
كل شيء تقريبا هو نفسه. يلتزم ربط
الخاصية [ngModel] بتحديث قيمة عنصر الإدخال. يقوم حدث ملزم
(ngModelChange) بإعلام العالم
بحدوث تغييرات في DOM.
ولاحظت أن تعبير المعالج يستخدم
حدث $ فقط ، وليس
$ event.target.value . هل هناك شيء خاطئ هنا؟ لا على الإطلاق. كما ذكر أعلاه ، يعد
حدث $ متغيرًا صناعيًا يحمل
حمولة . قرار ما يعتبر مفيداً يتخذ بواسطة الزاوي. بمعنى آخر ،
تعتني ngModelChange باستخراج
الهدف. القيمة من
حدث $ الداخلي وتعطينا ببساطة ما نريد ، دون تعبئة وتغليف. لكي تكون دقيقًا تقنيًا ، فهذه هي أدوات
DefaultValueAccessor : هو الذي يستخرج البيانات وينقلها إلى كائن DOM الأساسي ، على الرغم من ... لا يمكنك التفكير في الأمر).
أخيرًا وليس آخرًا ، نظرًا لأن كتابة
اسم المستخدم و
ngModel مرتين لا تزال زائدة عن الحاجة ، تسمح Angular باستخدام بناء الجملة المختصرة
[()] ، وتسمى أيضًا "banana in a box". وهو مشابه للمثال السابق ،
ويعيدنا إلى المثال من بداية القسم ، ولكن بفهم لتطبيق
ngModel . توفير نفس الربط ثنائي الاتجاه.
<input [(ngModel)]="username"> <p>Hello {{username}}!</p>
قم بإنشاء روابط البيانات ثنائية الاتجاه الخاصة بك
نحن نعرف الآن ما يكفي لإنشاء روابط البيانات ثنائية الاتجاه الخاصة بنا. كل ما عليك القيام به هو ببساطة اتباع نفس القواعد مثل
ngModel ، وهي:
- أدخل خاصية ربط (على سبيل المثال: [foo] )
- ربط حدث بنفس الاسم ولاحق التغيير (على سبيل المثال: (fooChange) )
- تأكد من أن رابط الحدث يعتني باسترداد العقار (إذا لزم الأمر)
لاحظ أن إنشاء ربط بيانات ثنائي الاتجاه يتطلب عملاً أكبر بكثير من AngularJS؟ قد يكون هذا الأمر محبطًا للغاية بالنسبة لنا ... إذا كنا سنحاول استخدام رابطنا ثنائي الاتجاه كلما كان ذلك ممكنًا. في الحياة الواقعية ، يجب أن تفكر دائمًا فيما إذا كنا بحاجة إلى ربط ثنائي الاتجاه ، وإذا لزم الأمر ، فهل من السهل الاستفادة من ngModel. الأخير ، على سبيل المثال ، يحدث عند إنشاء
عناصر تحكم نموذج مخصصة .
ولكن دعنا نقول أننا نقوم بإنشاء مكون عداد مخصص (ولا نريد استخدام عنصر تحكم نموذج مخصص).
@Component({ selector: 'custom-counter', template: ` <button (click)="decrement()">-</button> <span>{{counter}}</span> <button (click)="increment()">+</button> ` }) export class CustomCounterComponent { counterValue = 0; get counter() { return this.counterValue; } set counter(value) { this.counterValue = value; } decrement() { this.counter--; } increment() { this.counter++; } }
لدينا خاصية مكون
العداد لعرض القيمة الحالية للعداد. لتزويدها بربط ثنائي الاتجاه ، فإن أول ما عليك فعله هو تحويلها إلى معلمة
إدخال . لهذا ، فإن
مصممInput () مفيد للغاية:
@Component() export class CustomCounterComponent { counterValue = 0; @Input() get counter() { return this.counterValue; } ... }
يسمح لك هذا بالفعل بربط خاصية المكون للمستهلك على النحو التالي:
<custom-counter [counter]="someValue"></custom-counter>
نحتاج الآن إلى تعيين الحدث
Output () بنفس الاسم (
عداد )
وتغيير اللاحقة (اتضح عكس ذلك). نريد رفع هذا الحدث في كل مرة يتغير فيها
العداد . لماذا تضيف
خاصيةOutput () . وسننتهي ، في عدة حالتين ، أداة ضبط العداد ، والتي سنعترض فيها تغيير القيمة ونرمي حدثًا بقيمة القيمة الحالية:
@Component() export class CustomCounterComponent { ... @Output() counterChange = new EventEmitter(); set counter(val) { this.counterValue = val; this.counterChange.emit(this.counterValue); } ... }
هذا هو! الآن يمكننا ربط التعبير بهذه الخاصية باستخدام بناء جملة ربط البيانات ثنائية الاتجاه:
<custom-counter [(counter)]="someValue"></custom-counter> <p>counterValue = {{someValue}}</p>
تحقق من
التجريبي وتجربته!
مرة أخرى ، ضع في اعتبارك أن أحد المكونات مثل العداد المخصص يتم تنفيذه بشكل أفضل من خلال عنصر تحكم نموذج مخصص ، والاستفادة من
ngModel لتطبيق ربط البيانات ثنائي الاتجاه ، كما هو موضح في
هذه المقالة .
استنتاج
لم يعد الزاوي مزودًا بربط بيانات ثنائي الاتجاه. بدلاً من ذلك ، هناك واجهات برمجة التطبيقات في المربع تسمح لك بتطبيق الربط الكامل كخصائص وأحداث ربط.
يأتي
ngModel كتوجيه ملزم ثنائي الاتجاه مدمج في FormsModule (تذكر إضافته إلى قسم
الواردات في إعلان
@ NgModule : approx. per). يجب تفضيل الارتباط عبر ngModel عند إنشاء مكونات تعمل كعناصر تحكم نموذج مخصصة. خلاف ذلك ، كل هذا يتوقف على خيالك.
PS من المترجم: أصبح التطبيق الملزم في A2 + أكثر حداثة. الآن ، يتم استخدام مستعمرات "مجانية" تقريبًا لمراقبة التغييرات من خلال "feng shui" (على الرغم من أنه من الواضح أن آليات الفحص المتسخة ما زالت قائمة ، على الأقل لمكونات المستخدم عالية المستوى). جعل ذلك من الممكن التخلي عن 100،500 مراقب (إجراءات مراقبة التغييرات في البيانات "الخاصة بهم"). الذي أحب A1 في إنشاء تحميل ضار على المستعرض والمطلوب توجيه يديه بشكل غير عادي عند تخطيط الصفحات التفاعلية الغنية.
مع المكونات المصممة بشكل صحيح ، أصبح A2 خارج الصندوق أكثر استجابة بشكل ملحوظ. دع على حساب عمل المبرمجين. يمكنك الآن وضع مجموعة كبيرة من المكونات على الصفحة وعدم القلق بشأن موارد المعالج.
كان الجانب الآخر للعملة هو التكلفة الأولية "لعملية الدخول" في A2 + ، والتي أثرت على شعبية الإطار. لكن A1 كان له أيضًا تكلفة دخول عالية ، إلا أنه تم ترحيله إلى الدوري الرئيسي. نظرًا لعدم وجود فهم لكيفية تنظيم التطبيقات الكبيرة ، فإن العديد من النماذج الأولية "أقلعت" في A1 ، ثم "انهارت" وتوافق مع React و Vue.
آمل أن أتمكن من هذا المقال من خفض عتبة المدخل الأولي إلى A2 + ، والذي لا يزال في الطلب (الذي أعرفه بنفسي).