النص الإنجليزي الأصلي: القواعد السبع لجافا سكريبت غير المزعجة
العنوان الأصلي: http://icant.co.uk/articles/seven-rules-of-unobtrusive-javascript/
المؤلف الأصلي: كريس هيلمان
عنوان الترجمة: http://www.zhuoqun.net/html/y2008/1103.html
مكتوب في المقدمة: عندما كان Kejun يدربنا على JavaScript منذ بعض الوقت، أوصى بالعديد من المقالات الكلاسيكية على الشرائح، بما في ذلك هذه المقالة الواحدة. أشعر أنني بحالة جيدة جدًا بعد قراءتها، لكنني في كثير من الأحيان لا أفهم المقالات بعمق، وحدث أنني لم أجد نسخة صينية من هذه المقالة، لذلك خطرت ببالي فكرة ترجمتها. حتى أتمكن من مشاركتها وتعميق فهمي. مؤلف هذا المقال، كريس هيلمان، هو مهندس بريطاني في شركة ياهو! (شخصية "العراب" بحسب كيجون)، وقد تمت الموافقة على ترجمة هذا المقال من قبله أيضًا.
شيء آخر هنا، لقد قمت بترجمة الكثير من الأشياء من قبل، ولكن في ذلك الوقت كنت أترجم أكثر من أجل الترجمة، ولم أفهم الكثير من المقالات التقنية، لذلك لا أزال مترجمًا حتى الآن. سأستمر في ترجمة بعض المقالات في المستقبل، لكن يجب أن أترجم فقط المقالات الكلاسيكية التي تحتاج إلى الفهم بعناية. إذا كان لديك الوقت، فلا يزال يتعين عليك كتابة المزيد من التعليمات البرمجية.
ترجمة المصطلحات: فيما يتعلق بمصطلح "جافا سكريبت غير المزعج"، لا أستطيع التفكير في ترجمة مناسبة بشكل خاص. بعد البحث على الإنترنت، وجدت أن بعضها تمت ترجمته على أنه "جافا سكريبت منخفض المستوى"، والبعض الآخر تمت ترجمته على أنه "جافا سكريبت غير تدخلي"، والبعض الآخر تمت ترجمته في تايوان على أنه "جافا سكريبت غير تدخلي"... وبعد العديد من الأبحاث، قررت استخدام "جافا سكريبت غير متطفل". هذه الترجمة هي "جافا سكريبت المتطفلة" (على الرغم من أن هذا لا يناسبني تمامًا)، يرجى الاطلاع على هذه المقالة للحصول على التفاصيل. وفي الواقع فإن "جافا سكريبت غير المزعجة" تحتوي على معاني كثيرة، ومن الصعب تلخيصها في كلمة واحدة، وإذا كنت مهتمًا، فيمكنك إلقاء نظرة على شرح "جافا سكريبت غير المزعجة" على ويكيبيديا. بالإضافة إلى ذلك، أعتقد أن الترجمة هي التعبير عن معنى المؤلف، وليس بالضرورة أن تكون مترجمة كلمة بكلمة، لذلك، ولتسهيل فهم القراء، قمت بحذف بعضها وإضافة بعضها في المقال، لكن هذه دون الإضرار بمعنى النص الأصلي.
هناك نقطة أخرى يجب ملاحظتها، وهي أن مهاراتي في الترجمة هي هواة للغاية، لذا لا بد أن تكون هناك أخطاء في الترجمة، لذا يرجى تصحيحي.
بعد سنوات من تطوير وتعليم وكتابة جافا سكريبت غير المزعجة، اكتشفت الإرشادات التالية. آمل أن يساعدوك في فهم القليل عن السبب الذي يجعل من الأفضل تصميم وتنفيذ JavaScript بهذه الطريقة. لقد ساعدتني هذه القواعد في تقديم المنتجات بشكل أسرع وبجودة أعلى وأسهل في الصيانة.
1. لا تضع أي افتراضات (جافا سكريبت مساعد غير موثوق به)
ولعل أهم ما يميز جافا سكريبت غير المزعجة هو أنه يجب عليك التوقف عن وضع أي افتراضات:
لا تفترض أن جافا سكريبت متاح، فمن الأفضل أن تعتقد أنه ممكن غير متوفرة بدلاً من الاعتماد عليها بشكل مباشر.
لا تفترض أن المتصفح يدعم الأساليب والخصائص حتى تقوم باختبارها والتأكد من عملها.
لا تفترض أن كود HTML صحيح كما تعتقد، وتحقق منه في كل مرة، ولا تفعل شيئًا إذا لم يكن متاحًا.
اجعل وظيفة JavaScript مستقلة عن أجهزة الإدخال تذكر أن البرامج النصية الأخرى قد تؤثر على وظائف JavaScript، لذا تأكد من تحديد نطاق البرامج النصية الخاصة بك بأمان قدر الإمكان.
قبل البدء في تصميم البرنامج النصي الخاص بك، أول شيء يجب مراعاته هو التحقق من كود HTML الذي ستقوم بكتابة البرنامج النصي له ومعرفة ما إذا كان هناك أي شيء يمكن أن يساعدك في تحقيق هدفك.
2. ابحث عن علاقات الخطافات والعقد (HTML هو حجر الزاوية في البرمجة النصية)
قبل البدء في كتابة البرامج النصية، قم بإلقاء نظرة على HTML الذي تريد كتابة JavaScript له. إذا كان HTML غير منظم أو غير معروف، فمن المستحيل تقريبًا أن يكون لديك حل جيد للبرمجة النصية - فمن المحتمل أنك ستقوم إما بإنشاء الكثير من العلامات في JavaScript، أو أن التطبيق سيعتمد بشكل كبير على JavaScript.
هناك بعض الأشياء التي يجب مراعاتها في HTML، وهي العلاقات بين الخطافات والعقد.
<1>.HTML Hook
الرابط الأصلي والأكثر أهمية لـ HTML هو المعرف، ويمكن الوصول إلى المعرف من خلال أسرع طريقة DOM - getElementById. إذا كانت جميع المعرفات الموجودة في مستند HTML صالح فريدة من نوعها (يوجد خطأ في IE فيما يتعلق بالاسم والمعرف، ولكن بعض المكتبات الجيدة تحل هذه المشكلة)، فإن استخدام المعرفات آمن وموثوق وسهل الاختبار.
بعض الخطافات الأخرى هي عناصر HTML وفئات CSS يمكن الوصول إليها من خلال الأسلوب getElementsByTagName، لكن لا يمكن الوصول إلى فئات CSS من خلال أساليب DOM الأصلية في معظم المتصفحات. ومع ذلك، هناك العديد من مكتبات الفئات الخارجية التي توفر طرقًا يمكنها الوصول إلى أسماء فئات CSS (على غرار getElementsByClassName).
<2>.علاقة عقدة HTML.
هناك نقطة أخرى مثيرة للاهتمام حول HTML وهي العلاقة بين العلامات. فكر في السؤال التالي:
كيف يمكننا الوصول إلى العقدة المستهدفة بسهولة أكبر وبأقل قدر من اجتياز DOM؟
من خلال تعديل العلامة، يمكننا الوصول إلى أكبر عدد ممكن من العقد الفرعية التي تحتاج إلى تعديل؟
ما هي السمات أو المعلومات التي يمتلكها عنصر معين والتي يمكن استخدامها للوصول إلى عنصر آخر؟
يعد اجتياز DOM عملية كثيفة الاستخدام للموارد وبطيئة، ولهذا السبب يجب عليك محاولة استخدام التقنيات المستخدمة بالفعل في المتصفحات للقيام بذلك.
3. اترك عملية الاجتياز للخبراء (CSS، اجتياز DOM بشكل أسرع).
يبدو أن برمجة DOM واستخدام الأساليب أو الخصائص (getElementsByTagName، وnextSibling، وpreviousSibling، وparentNode وغيرها) لاجتياز DOM، أمر مربك للغاية . مثير للاهتمام. الشيء المثير للاهتمام هو أننا قمنا بالفعل بهذه الأشياء من خلال تقنية CSS أخرى.
CSS هي تقنية تستخدم محددات CSS للوصول إلى العناصر المستهدفة وتغيير خصائصها المرئية عن طريق اجتياز DOM. يمكن استبدال جزء معقد من JavaScript يستخدم DOM بمحدد CSS:
var n = document.getElementById('nav');
إذا (ن) {
var as = n.getElementsByTagName('a');
إذا (as.length > 0) {
for(var i=0;as[i];i++){
as[i].style.color = '#369';
as[i].style.textDecoration = 'none';
}
}
}
/* الكود التالي له نفس الوظيفة المذكورة أعلاه*/
#nav a{
اللون: #369؛
زخرفة النص: لا شيء؛
}
هذه تقنية قوية جدًا ويمكن استخدامها بشكل جيد. يمكنك تحقيق ذلك عن طريق إضافة فئات ديناميكيًا إلى العناصر عالية المستوى في DOM أو تغيير معرف العنصر. إذا كنت تستخدم DOM لإضافة فئة CSS إلى نص المستند، فيمكن للمصممين تحديد الإصدارات الثابتة والديناميكية للمستند بسهولة.
جافا سكريبت:
vardynamicClass = 'js';
فار ب = document.body;
b.className = b.className ? b.className + 'js' : 'js';
CSS:
/* النسخة الثابتة*/
#nav {
....
}
/* الإصدار الديناميكي*/
body.js #nav {
....
}
4. فهم المتصفحات والمستخدمين (وبناء ما تحتاجه بناءً على أنماط الاستخدام الحالية)
جزء كبير من جافا سكريبت غير المزعجة هو فهم كيفية عمل المتصفحات (خاصة كيفية تعطل المتصفحات) وما يتوقعه المستخدمون. بغض النظر عن المتصفح، يمكنك بسهولة إنشاء واجهة مختلفة تمامًا باستخدام JavaScript. يمكن إنشاء واجهات السحب والإفلات، ومناطق الطي، وأشرطة التمرير، وشرائح التمرير باستخدام JavaScript، ولكن هذه المشكلة ليست مشكلة فنية بسيطة، ويجب عليك التفكير في الأسئلة التالية:
هل يمكن أن تكون هذه الواجهة الجديدة مستقلة عن أجهزة الإدخال؟ إذا لم يكن الأمر كذلك، ما الذي يمكنك الاعتماد عليه؟
هل تتبع الواجهة الجديدة التي أقوم بإنشائها إرشادات المتصفح أو أي واجهة غنية أخرى (هل يمكنك التبديل بين القوائم متعددة المستويات مباشرةً باستخدام الماوس؟ أم أنك بحاجة إلى استخدام مفتاح tab؟)
ما هي الوظيفة التي أحتاج إلى توفيرها والتي تعتمد على JavaScript؟
السؤال الأخير لا يمثل مشكلة حقًا لأنه يمكنك استخدام DOM لإنشاء HTML من لا شيء إذا لزم الأمر. مثال على ذلك هو رابط "الطباعة" نظرًا لأن المتصفحات لا توفر وظيفة غير JavaScript لطباعة مستند، فأنت بحاجة إلى استخدام DOM لإنشاء مثل هذه الروابط. وينطبق الشيء نفسه على شريط العنوان القابل للنقر والذي يقوم بتنفيذ وحدات محتوى التوسيع والطي. لا يمكن تنشيط شريط العنوان بواسطة لوحة المفاتيح، ولكن يمكن تنشيط الروابط. لذلك، لإنشاء شريط عنوان قابل للنقر عليه، تحتاج إلى إضافة الرابط باستخدام JavaScript، وبعد ذلك يمكن لجميع المستخدمين الذين لديهم لوحة مفاتيح طي وحدة المحتوى وتوسيعها.
من الموارد الممتازة لحل هذا النوع من المشكلات مكتبة أنماط التصميم. أما معرفة الأشياء الموجودة في المتصفح المستقلة عن أجهزة الإدخال، فهي تعتمد على تراكم الخبرة. أول شيء تحتاج إلى فهمه هو آلية التعامل مع الحدث.
5. فهم الأحداث (التعامل مع الأحداث يؤدي إلى التغيير)
تعد معالجة الأحداث هي الخطوة الثانية نحو جافا سكريبت غير المزعجة. الهدف ليس جعل كل شيء قابلاً للسحب أو النقر أو إضافة معالجة مضمّنة إليه، ولكن فهم أن معالجة الأحداث شيء يمكن فصله تمامًا. لقد قمنا بفصل HTML وCSS وJavaScript، لكننا لم نقطع شوطًا طويلاً في فصل التعامل مع الأحداث.
سيراقب معالج الأحداث التغييرات التي تحدث على العناصر الموجودة في المستند. في حالة حدوث حدث، سيجد المعالج كائنًا رائعًا (عادةً ما يكون معلمة تسمى e). سيخبر هذا الكائن ما حدث وما يمكن فعله به .
الأمر المثير للاهتمام حقًا في معظم التعامل مع الأحداث هو أنه لا يحدث فقط على العنصر الذي تريد الوصول إليه، ولكن على جميع العناصر الأعلى في DOM (ولكن ليست كل الأحداث على هذا النحو، التركيز على الاستثناء هو حدث التمويه) . على سبيل المثال، يمكنك استخدام هذه الميزة لإضافة معالج حدث واحد فقط إلى قائمة التنقل، واستخدام أسلوب معالج الأحداث للحصول على العنصر الذي أدى إلى تشغيل الحدث بالفعل. تسمى هذه التقنية تفويض الحدث، ولها العديد من المزايا:
ما عليك سوى التحقق من وجود عنصر، بدلاً من التحقق من كل عنصر، يمكنك إضافة العقد الفرعية أو إزالتها ديناميكيًا دون إزالة معالج الحدث المقابل، ويمكنك تذكر شيء آخر عند الاستجابة لنفس الحدث على عناصر مختلفة، يمكنك إيقاف الحدث من الانتشار إلى العنصر الأصلي ويمكنك تجاوز السلوك الافتراضي لعناصر HTML (مثل الروابط). ومع ذلك، في بعض الأحيان لا تكون هذه فكرة جيدة لأن المتصفحات تمنح عناصر HTML السلوكيات التي تقوم بها لسبب ما. على سبيل المثال، قد تشير الروابط إلى هدف داخل الصفحة، ويضمن تركها بدون تعديل إمكانية قيام المستخدم أيضًا بوضع إشارة مرجعية على حالة البرنامج النصي الحالية للصفحة.
6. فكر في الآخرين (مساحات الأسماء والنطاقات والمخططات)
لن تكون التعليمات البرمجية الخاصة بك أبدًا هي التعليمات البرمجية النصية الوحيدة في المستند. لذلك من المهم بشكل خاص التأكد من عدم وجود وظائف عامة أو متغيرات عامة في التعليمات البرمجية الخاصة بك والتي يمكن للبرامج النصية الأخرى تجاوزها. هناك عدة أنماط متاحة لتجنب هذه المشكلة، أبسطها هو استخدام الكلمة الأساسية var لتهيئة جميع المتغيرات. لنفترض أننا نكتب النص التالي:
var nav = document.getElementById('nav');
وظيفة الحرف الأول () {
// افعل الأشياء
}
عرض الوظيفة () {
// افعل الأشياء
}
إعادة تعيين الوظيفة (){
// افعل الأشياء
}
يحتوي الكود أعلاه على متغير عام يسمى nav وثلاث وظائف تسمى init وshow وreset. يمكن لهذه الوظائف الوصول إلى متغير التنقل ويمكنها الوصول إلى بعضها البعض من خلال اسم الوظيفة:
var nav = document.getElementById('nav');
وظيفة الحرف الأول () {
يعرض()؛
إذا (nav.className === 'إظهار'){
إعادة ضبط()؛
}
// افعل الأشياء
}
عرض الوظيفة () {
var c = nav.className;
// افعل الأشياء
}
إعادة تعيين الوظيفة (){
// افعل الأشياء
}
يمكنك تجنب الترميز العالمي أعلاه عن طريق تغليف التعليمات البرمجية في كائن، بحيث يمكن تحويل الوظائف إلى أساليب في الكائن، ويمكن تحويل المتغيرات العامة إلى خصائص في الكائن. تحتاج إلى استخدام طريقة "الاسم + النقطتين" لتحديد الطرق والخصائص، وتحتاج إلى إضافة فاصلة كفاصل بعد كل خاصية أو أسلوب.
فار ماي سكريبت = {
التنقل:document.getElementById('nav')،
الحرف الأول: وظيفة () {
// افعل الأشياء
},
عرض:وظيفة(){
// افعل الأشياء
},
إعادة تعيين: وظيفة () {
// افعل الأشياء
}
}
يمكن الوصول إلى كافة الأساليب والخصائص خارجيًا وداخليًا باستخدام "اسم الفئة + عامل التشغيل النقطة".
فار ماي سكريبت = {
التنقل:document.getElementById('nav')،
الحرف الأول: وظيفة () {
myScript.show();
إذا (myScript.nav.className === 'show'){
myScript.reset();
}
// افعل الأشياء
},
عرض:وظيفة(){
var c = myScript.nav.className;
// افعل الأشياء
},
إعادة تعيين: وظيفة () {
// افعل الأشياء
}
}
عيب هذا النموذج هو أنه في كل مرة تقوم فيها بالوصول إلى أساليب أو خصائص أخرى من إحدى الطرق، يجب عليك إضافة اسم الكائن في المقدمة، ويمكن الوصول إلى كل شيء في الكائن من الخارج. إذا كنت تريد فقط أن تكون بعض التعليمات البرمجية قابلة للوصول إلى البرامج النصية الأخرى في المستند، ففكر في نمط الوحدة النمطية التالي:
فار ماي سكريبت = وظيفة(){
// هذه طرق وخصائص خاصة
var nav = document.getElementById('nav');
وظيفة الحرف الأول () {
// افعل الأشياء
}
عرض الوظيفة () {
// افعل الأشياء
}
إعادة تعيين الوظيفة (){
// افعل الأشياء
}
// يتم تغليف الأساليب والخصائص العامة في بيان الإرجاع باستخدام بناء جملة الكائن
يعود {
عامة: وظيفة () {
}،
فو: "شريط"
}
}();
يمكنك الوصول إلى الخصائص والأساليب العامة التي تم إرجاعها بنفس طريقة التعليمة البرمجية السابقة، في هذه الحالة: myScript.public() وmyScript.foo. ولكن هناك نقطة أخرى غير مريحة هنا: عندما تريد الوصول إلى طريقة عامة من الخارج أو من طريقة خاصة من الداخل، فلا يزال يتعين عليك كتابة اسم طويل (يمكن أن يكون اسم الكائن طويلًا جدًا). لتجنب ذلك، تحتاج إلى تعريفها على أنها خاصة وإرجاع اسم مستعار فقط في بيان الإرجاع:
فار ماي سكريبت = وظيفة(){
// هذه أساليب وخصائص خاصة
var nav = document.getElementById('nav');
وظيفة الحرف الأول () {
// افعل الأشياء
}
عرض الوظيفة () {
// افعل الأشياء
// افعل الأشياء
}
إعادة تعيين الوظيفة (){
// افعل الأشياء
}
var foo = 'bar';
function public(){
}
// إرجاع المؤشرات فقط إلى تلك الأساليب والخصائص الخاصة التي تريد الوصول إليها
يعود {
عام: عام،
فو:فو
}
}();
ويضمن ذلك نمطًا متسقًا للتعليمات البرمجية ويسمح لك باستخدام أسماء مستعارة أقصر للوصول إلى الأساليب أو الخصائص.
إذا كنت لا ترغب في كشف أي أساليب أو خصائص للعالم الخارجي، فيمكنك تغليف جميع التعليمات البرمجية في طريقة مجهولة وتنفيذها مباشرة بعد تعريفها:
(function(){
// هذه كلها أساليب وخصائص خاصة
var nav = document.getElementById('nav');
وظيفة الحرف الأول () {
// افعل الأشياء
show(); // لا توجد بادئة اسم فئة مطلوبة هنا
}
عرض الوظيفة () {
// افعل الأشياء
}
إعادة تعيين الوظيفة (){
// افعل الأشياء
}
})();
يعد هذا النمط رائعًا لوحدات التعليمات البرمجية التي يتم تنفيذها مرة واحدة فقط وليس لها أي تبعيات على وظائف أخرى.
من خلال اتباع القواعد المذكورة أعلاه، ستعمل التعليمات البرمجية الخاصة بك بشكل أفضل للمستخدمين، وسيتم تشغيل التعليمات البرمجية الخاصة بك بشكل أفضل على الأجهزة وتتوافق بشكل أفضل مع تعليمات المطورين الآخرين. ومع ذلك، هناك مجموعة واحدة يجب أن تؤخذ بعين الاعتبار.
7. ضع في اعتبارك المطورين الذين سيتولون مسؤولية التعليمات البرمجية الخاصة بك (يجعل الصيانة أسهل)
الخطوة الأخيرة في جعل البرنامج النصي الخاص بك غير مزعج حقًا هو التحقق مرة أخرى بعد كتابته، والعناية بالمطورين الذين سيتولون التعليمات البرمجية الخاصة بك بمجرد الانتهاء من ذلك. يبدأ البرنامج النصي. خذ بعين الاعتبار الأسئلة التالية:
هل جميع أسماء المتغيرات والوظائف معقولة وسهلة الفهم؟
هل الكود منظم بشكل صحيح؟ هل يتدفق بسلاسة من البداية إلى النهاية؟
هل كل التبعيات واضحة؟
هل تمت إضافة تعليقات حيثما أمكن ذلك قد تسبب ارتباكًا؟
أهم شيء يجب ملاحظته هو: إدراك أن كود HTML وCSS الموجود في المستند من المرجح أن يتغيرا أكثر من JavaScript (لأنهما مسؤولان عن التأثير المرئي). لذلك، لا تقم بتضمين أي فئات ومعرفات يمكن للمستخدمين النهائيين رؤيتها في التعليمات البرمجية النصية، ولكن قم بفصلها إلى كائن يحتوي على معلومات التكوين.
مايسكريبت = وظيفة () {
فار التكوين = {
معرف التنقل: "التنقل"،
فئة مرئية: "إظهار"
};
var nav = document.getElementById(config.navigationID);
وظيفة الحرف الأول () {
يعرض()؛
إذا (nav.className === config.visibleClass){
إعادة ضبط()؛
};
// افعل الأشياء
};
عرض الوظيفة () {
var c = nav.className;
// افعل الأشياء
};
إعادة تعيين الوظيفة (){
// افعل الأشياء
};
}();
بهذه الطريقة يعرف المشرف مكان تعديل هذه الخصائص دون الحاجة إلى تغيير تعليمات برمجية أخرى.
مزيد من المعلومات
هذه هي الإرشادات السبعة التي اكتشفتها.
إذا كنت تريد معرفةحول المواضيع التي تمت مناقشتها أعلاه، فراجع الروابط التالية