لديك حساب بالفعل؟ دخول
دخول  سجل الأن 
جدول المحتويات
الأحداث
في هذا الفصل سندرس الأحداث Events و هو موضوع مهم فبدونه لا تستطيع أن تجعل صفحات الويب تفاعلية.حيث أنه من خلال الأحداث Events يمكن تنفيذ دالة معينه عندما يحدث شيء مثل أن يكتمل تحميل صفحة الويب أو شيء يفعله المستخدم مثل الضغط على عنصر في الصفحه.
[تحسين] مقدمة
كثيرا ما تصادفك قوائم في المواقع المختلفة كموقعنا مثلا ,والذي ستجد فيه عدد من القوائم بالأعلى مثل قائمة لغات المتصفح ,وعندما تشير بالماوس على رأس القائمة تظهر عناصر القائمة لك .هذه القوائم تعمل من خلال الجافا سكريبت و إشاراتك بالماوس على القائمة هي مثال للحدث event و الذي هو موضوع هذا الفصل .فما يتم هو أنه عندما تشير على القائمة(حدوث حدث ) يتم تنفيذ دالة معينه بالجافا سكريب فتظهر لك القائمة ,و تسمى الدوال التي تعمل عندما يحدث حدث event بالـ event handlers(معالجات الأحداث) .
الحدث Event :هو في الغالب شيء يفعله المستخدم مثل الضغط على لنك في الصفحة أو شيء يحدث نتيجة ما يفعله المستخدم مثل إكتمال تحميل الصفحة التي طلبها المستخدم.
من أمثلة الأحداث Events:
الحدثالوصف
loadيحدث عندما يكتمل تحميل صفحة أو صورة
clickيحدث عندما يضغط المستخدم على لنك أو صورة أو أي عنصر من عناصر الصفحة
mouseoverيحدث عند دخول الماوس فوق عنصر
mouseoutعند إبتعاد الماوس من فوق عنصر
keydownعند الضغط على أي زر في لوحة المفاتيح


معالج الحدث Event handler: و يسمى أيضا بال event listener,وهو عبارة عن دالة تعمل عندما يحدث حدث محدد مثلا دالة تعمل تلقائيا عند إكتمال تحميل الصفحة.

هناك طريقيتن لمعالجة الأحداث (أي جعل دوال معينه تعمل عند حدوث الحدث) و هما:
  • طريقة بسيطة و بدائية و تسمى بالـ ِDOM Level 0 events API و يتم فيها تعيين معالج الحدث (Event handler) للحدث من خلال صفات الهيتميل (html attributes)
  • طريقة متطورة و مرنة و تسمى بالـ DOM Level 2 Event API ,و يتم فيها تعيين معالج الحدث للحدث من خلال دوال خاصة بذلك .

[تحسين] الطريقة الأولى
سنبدأ بالطريقة البسيطة في هذا الدرس ,تقوم هذه الطريقة على أساس وجود معالج حدث (event handler) لكل حدث (event) يوضع كصفة (attribute) في تاج الهيتميل الذي تريد أن تنفذ دالة عندما يحدث له حدث .
مثلا للحدث click الإيفنت هندلر له هو onClick و onClick توضع كصفة في تاج الهيتيل كما بالمثال .
مثال
<html>
  <input type="button" value='اضغط هنا' onClick="alert('تم الضغط')">
</html>

حاول بنفسك »اضغط على "حاول بنفسك" لكى ترى كيف تعمل فى الحقيقة

عندما تضغط على الزر 'اضغط هنا' سيظهر لك صندوق مكتوب فيه تم الضغط . وما يحدث هو أنه عند حدوث حدث الضغط 'click' فإن الإيفنت هندلر onClick يعمل ، ونلاحظ أننا وضعنا الجافا سكريبت داخل هيتميل مباشرة بدون إستخدام تاج <script> و هذا ممكن في بعض الحالات مثل هذه الحالة . و يمكن وضع كود جافا سكريب كبير يصل لمئات الأوامر بعد صفة الإيفنت هندلر( مثل onClick) لكن إن فعلنا هذا فإن الكود سيصبح معقد جدا ,و لذا إن أردنا إستخدام هذه الطريقة فالأفضل أن تضع الأوامر في دالة ثم تضع الدالة للإيفنت هندلر كهذا المثال:
مثال 2
<html>
  
  <head>
    <script type='text/javascript'>
      
     function func()
      {
      var text="كيف حالك؟";
      alert(text);   
      }
      
    </script>
  </head>
  
  <body>
     <input type="button" value='اضغط هنا' onClick=" func()">
  </body>
  
</html>

حاول بنفسك »اضغط على "حاول بنفسك" لكى ترى كيف تعمل فى الحقيقة

قمنا بتعريف الدالة في جزء الـ <head> ,حيث أنه يحمل قبل الـ <body> فتكون الدالة تم تعريفها قبل أن يتم إستدعائها .و من الأفضل ليصبح الكود أكثر تنظيما أن نفصل الجافا سكريبت تماما عن الهيتميل و هذا ممكن من خلال الـ dom الذي تعلمناه في الفصل السابق .هكذا
مثال 3
<html>
  <head>
    
  </head>
  
  <body>
     <input type="button" value='اضغط هنا'>
  </body>
  <script type='text/javascript'>
      
     var button=document.getElementsByTagName('input')[0]
     
         button.onclick= function ()
      {
      var text="كيف حالك؟"
       alert(text)    
      }
      
    </script>
  
</html>

حاول بنفسك »اضغط على "حاول بنفسك" لكى ترى كيف تعمل فى الحقيقة

في السطر الحادي عشر وصلنا إلى الزر الذي نريد ان نجعل الدالة تنفذ عندما يتم الضغط عليه.

في السطر الثالث عشر وصلنا إلى الصفة onclick وو ضعنا فيها الدالة التي نريد أن تنفذ .

ملحوظة :عند إستخدام onclick في الجافا سكريبت لابد أن تكون الحروف صغيرة كلها أما عند إستخدامها كصفة في هيتميل فلا يهم يمكن أن تكتب كل الحروف صغيرة أو تكتب الحرف الأول من الكلمة الثانية كبير أو حتى تكتب كل الحروف كبيرة لأن هيتميل لا تفرق بين الحرف الكبير و الصغير بينما هناك فرق في الجافا سكريبت.

لاحظ إنه عند وضع قيمة لصفة غير موجوده في التاج فإنها يتم إضافتها فيه . كما أن هذه الطريقة توضح أيضا أن onclcick عبارة عن دالة تنفذ عندما يحدث الحدث click .فكما يمكنك أن تلاحظ الطريقة التي عرفنا بها الدالة
  button.onclick= function ()
      {
      var text="How are you?"
       alert(text)    
      }
تشبه تلك التي إستخدمناها عندما كنا نعرف دالة method لكائن ما . عند إستخدام هذه الطريقة هناك ميزة أخرى تضاف و هي أن الدالة تنفذ داخل الكائن الذي يمثل التاج لاحظ المثال التالي
مثال 4
<html>
  
  <head>
    
  </head>
  
  <body>
     <input type="button" value='Click here'>
  </body>
  <script type='text/javascript'>
      
     var button=document.getElementsByTagName('input')[0]
     
         button.onclick= function ()
      {
       alert(this)    
      }
      
    </script>
  
</html>

حاول بنفسك »اضغط على "حاول بنفسك" لكى ترى كيف تعمل فى الحقيقة

الكود مماثل للمثال السابق ماعدا في السطر السادس عشر ستجد alert(this) ,و كما تعرف this تمثل الكائن الذي تكون داخله و لذا ستجد أن الصندوق مكتوب فيه object HTML INPUTELEMENT.و يمكننا الإستفادة من ذلك في الوصول لمعلومات مصدر الضغطه بسهولة مثلا إن أبدلت this ب this.nodeName سيرجع لك إسم التاج INPUT .

آخر معلومة في هذا الدرس هي كيف توقف الحركة الإفتراضية للحدث بمعنى مثلا أنه إن كان هناك لينك . عندما تضغط عليه الإفتراضي أنه سينقلك للعنوان المحدد له ,يمكنك من خلال الجافا سكريبت أن تمنعه من أن ينقلك للحدث بأن تجعل دالة معالج الحدث ترجع (return) خطا (flase) كما بالمثال

مثال 5
<html>
  
  <head>
    <script type='text/javascript'>
      
     function func()
      {
        
     alert('لن ينتقل إلى جوجل')  
       
       return false
      }
      
    </script>
  </head>
  
  <body>
    <a  onClick="return func()"  href='http://www.google.com.com'>go to google </a>
  </body>
  
</html>

حاول بنفسك »اضغط على "حاول بنفسك" لكى ترى كيف تعمل فى الحقيقة

أو كما بهذا المثال
مثال 6
<html>
  
  <head>
  
  </head>
  
  <body>
    <a   href='http://www.google.com.com'>go to google </a>
  </body>
    <script type='text/javascript'>
      link=document.getElementsByTagName('a')[0]
      
     link.onclick=function ()
      {
        
     alert('لن ينتقل إلى جوجل')  
       
       return false
      }
      
    </script>
</html>

حاول بنفسك »اضغط على "حاول بنفسك" لكى ترى كيف تعمل فى الحقيقة


في الدرس التالي سنأخذ تطبيقا على هذا الدرس أتصور أنه سيكون ممتعا و مفيد و هو عمل آلة حاسبة بالجافا سكريبت.
تم التحسين بواسطة: 3bood5
[تحسين] تطبيق1

في هذا الدرس سنتعلم كيف نقوم بعمل آلة حاسبة كالموجودة بالأسفل هذه بالجافا سكريبت قم بتجربتها بالضغط على الأرقام و الرموز لعمل العلميات الحسابية التي تريدها .

إخفاء/عرض الكود


<!DOCTYPE html>

<html>
<head>
    <title>Lesson 17: Example 01</title>
    <style type="text/css">
    td {
        border: 1px solid gray;
        width: 50px;
    }
    
    #results {
        height: 20px;
    }
    </style>
</head>
<body>
    <table border="0" cellpadding="2" cellspacing="2">
        <tr>
            <td colspan="4" id="results"></td>
        </tr>
        <tr>
            <td><a href="#" onclick="return addDigit(1)">1</a></td>
            <td><a href="#" onclick="return addDigit(2)">2</a></td>
            <td><a href="#" onclick="return addDigit(3)">3</a></td>
            <td><a href="#" onclick="return addDigit('+')">+</a></td>
        </tr>
        <tr>
            <td><a href="#" onclick="return addDigit(4)">4</a></td>
            <td><a href="#" onclick="return addDigit(5)">5</a></td>
            <td><a href="#" onclick="return addDigit(6)">6</a></td>
            <td><a href="#" onclick="return addDigit('-')">-</a></td>
        </tr>
        <tr>
            <td><a href="#" onclick="return addDigit(7)">7</a></td>
            <td><a href="#" onclick="return addDigit(8)">8</a></td>
            <td><a href="#" onclick="return addDigit(9)">9</a></td>
            <td><a href="#" onclick="return addDigit('*')">x</a></td>
        </tr>
        <tr>
            <td><a href="#" onclick="return reset()">Clear</a></td>
            <td><a href="#" onclick="return addDigit(0)">0</a></td>
            <td><a href="#" onclick="return calculate()">=</a></td>
            <td><a href="#" onclick="return addDigit('/')">/</a></td>
        </tr>
    </table>
    <script type="text/javascript">
    function addDigit(digit) {
        var resultField = document.getElementById("results");
        resultField.innerHTML += digit;

        return false;
    }

    function calculate() {
        var resultField = document.getElementById("results");
        
        resultField.innerHTML = eval(resultField.innerHTML);

        return false;
    }

    function reset() {
        var resultField = document.getElementById("results");
        
        resultField.innerHTML = "";

        return false;
    }
    </script>
</body>
</html>
الكود مكون من ثلاث أجزاء الإستايل شيت بالأعلى و كود الهيتميل بالمنتصف و كود الجافا سكريبت بالأسفل .بالطبع الهيتميل و الإستايل شيت مسؤولون عن المحتوى و الشكل فقط اما التفاعل فهو يخص الجافا سكريبت .شكل الآلة الحاسبة عبارة عن جدول <table> و توضع في خناته الأرقام من 0 حتى 9 و الرموز الحسابية كما يبدو لك في الأعلى .أما عن الجافا سكريبت و هو ما يهمنا هنا فالكود يتكون من ثلاث دوال دالة تكتب الرقم الذي تضغط عليه أو الرمز(ماعدا "=" )في الشاشة (خانة الصف الأول من الجدول).و دالة تنفذ عندما تضغط على "=" و تقوم بإجراء العملية الحسابية الموجوده في الشاشة ووضع الناتج في الشاشة .دالة تنفذ عندما تضغط على clear و تقوم بمسح الشاشة و سأشرح هذه الدوال بالتفصيل .

addDigit(digit)

مهمة هذه الدالة هي أنه عندما تضغط على رقم من الأرقام أو أداة من الأدوات تقوم هي بكتابة الرقم أو الأداة في الصف الأول من الجدول و الذي يمثل الشاشة .تعريف الدالة موجود في السطر الـ 48 من الكود و هو هكذا:
 function addDigit(digit) {
        var resultField = document.getElementById("results");
        resultField.innerHTML += digit;
 
        return false;
    }
في السطر رقم 2 في هذا الجزء وصلنا من خلال الـdom لخلية الصف الأول في الجدول باستخدام دالة getElementById و إذا نظرت للسطر 20 في الكود الكامل ستجد أن خلية الصف الأول لها id( الآي دي) result . السطر التالي هوا إختصار لهذا الكود
resultField.innerHTML =resultField.innerHTML+ digit;
و هو يلصق قيمة المتغير digit و (الذي يدخل كبرامتر للدالة) في النص الموجود أصلا في الشاشة ثم يضع الإثنين في داخل الشاشة ,بالطبع إن كانت الشاشة خالية أي أن النص الموجود بداخلها ("")فإنه الناتج سيكون قيمة المتغير digit فقط لأن مثلا 1+"" كما نعلم تساوي "1" . سنجعل هذه الدالة تعمل عند الضغط على أي رقم أو أي رمز ما عدا رمز "=" و ذلك بأن نضيفها من خلال الصفة onclick في كل لنك يمثل رقم أو رمز مثل
  <td><a href="#" onclick="return addDigit(1)">1</a></td>
و نضع الرقم أو الرمز كبرامتر للدالة و كذلك return لكي لا يذهب لما يؤدي إليه اللينك وهو في حالتنا علامة الشباك# و التي تعني أعلى الصفحة .

calculate()

تعمل هذه الدالة عند الضغط على علامة "=" كما يظهر من السطر 43 في الكود و الذي هو :
 <td><a href="#" onclick="return calculate()">=</a></td>
و ما تقوم به هذه الدالة هي أنها تنفذ العملية الحسابية الموجود في الشاشة فإذا نظرت للكود الخاص بتعرفيها في السطر 55 ستجده كالتالي:
    function calculate() {
        var resultField = document.getElementById("results");
         
        resultField.innerHTML = eval(resultField.innerHTML);
 
        return false;
    }

في كود الدالة السطر رقم 2 عبارة عن وصول لخلية الجدول التي تمثل الشاشة من خلال الآي دي .

أما السطر التالي رقم 4 فيتم إستخدام دالة eval و هذه الدالة تنفذ النص الموجود فيها كأوامر مثلا
x="1+3"
eval(x)
ترجع 4

و يمكنك تجربتها في الكنسول .

و أيضا
text="alert('this is a text ')"
eval(text)

دالة eval ستنفذ النص الموجود بداخلها كأوامر فيظهر لك صندوق alert .

و في دالة calculate نستخدم دالة eval لتنفيذ العملية الحسابية الموجودة في الشاشة و التي نصل لها من خلال resultField.innerHTML ثم نضع الناتج ثانية في resultField.innerHTML ليظهر على الشاشة .

reset()

و تعمل عند الضغط على كلمة Clear كما يتضح من السطر 41 و الذي هو كالتالي :
 <td><a href="#" onclick="return reset()">Clear</a></td>

و تقوم الدالة بمسح محتويات الشاشة عند تنفيذها .

تعريف الدالة يوجد في السطر 63 و هو كالتالي :
function reset() {
        var resultField = document.getElementById("results");
         
        resultField.innerHTML = "";
 
        return false;
   }
 
و كل ما تفعله الدالة هي أن تضع نص خالي في محل النص الموجود في الشاشة من خلال الكود الموجود في السطر 4.

فصل الجافا سكريبت عن الهيتميل

تعلمنا في الدرس السابق كيف نضيف معالجات الأحداث للأحداث بدون أن نخلط بين الجافا سكريبت و هيتميل و سنطبق هذه الطريقة على تطبيق الآلة الحاسبة فيكون الكود كالتالي:
فصل الجافا سكريبت عن الهيتميل
<!DOCTYPE html>

<html>
<head>
    <title>Lesson 17: Example 01</title>
    <style type="text/css">
    td {
        border: 1px solid gray;
        width: 50px;
    }
    
    #results {
        height: 20px;
    }
    </style>
</head>
<body>
    <table border="0" cellpadding="2" cellspacing="2">
        <tr>
            <td colspan="4" id="results"></td>
        </tr>
        <tr>
            <td><a href="#">1</a></td>
            <td><a href="#">2</a></td>
            <td><a href="#">3</a></td>
            <td><a href="#">+</a></td>
        </tr>
        <tr>
            <td><a href="#">4</a></td>
            <td><a href="#">5</a></td>
            <td><a href="#">6</a></td>
            <td><a href="#">-</a></td>
        </tr>
        <tr>
            <td><a href="#">7</a></td>
            <td><a href="#">8</a></td>
            <td><a href="#">9</a></td>
            <td><a href="#">*</a></td>
        </tr>
        <tr>
            <td><a href="#">Clear</a></td>
            <td><a href="#">0</a></td>
            <td><a href="#">=</a></td>
            <td><a href="#">/</a></td>
        </tr>
    </table>
    <script type="text/javascript">
    function addDigit(digit) {
        var resultField = document.getElementById("results");
        resultField.innerHTML += digit;

        return false;
    }

    function calculate() {
        var resultField = document.getElementById("results");
        
        resultField.innerHTML = eval(resultField.innerHTML);

        return false;
    }

    function reset() {
        var resultField = document.getElementById("results");
        
        resultField.innerHTML = "";

        return false;
    }

    function getHandlerFunction(innerHTML) {
        return function() {
            addDigit(innerHTML);

            return false;
        };
    }

    onload = function() {
        var links = document.getElementsByTagName("a");
        var length = links.length;

        for (var i = 0; i < length; i++) {
            var link = links[i];
            var innerHTML = link.innerHTML;

            switch(innerHTML) {
                case "Clear":
                    link.onclick = reset;
                    break;
                case "=":
                    link.onclick = calculate;
                    break;
                default:
                    link.onclick = getHandlerFunction(innerHTML);
                    break;
            }
        }

    };
    </script>
</body>
</html>

حاول بنفسك »اضغط على "حاول بنفسك" لكى ترى كيف تعمل فى الحقيقة

الدوال الموجودة في الكود الأول موجودة أيضا هنا و لم تتغير .تم إضافة دالتين دالة getHandlerFunction سنذكر مهتمتها لاحقا.و دالة تعمل عند تحميل الصفحة onload و مهمتها أن تعيين الدوال للأحداث سنبدأ بشرح الثانية أولا . إذا نظرت في الكود إلى السطر 79 ستجد أنه تم وضع دالة للإيفنت هندلر onload هذه الدالة ستعمل عند إكتمال تحميل الصفحة و مهمتها أنها تعين الدوال التي ستعمل عند الضغط على كل لينك و الآن سنفحصها و نفهم كيف تعمل .هذا هو الجزء الخاص بالدالة:
onload = function() {
        var links = document.getElementsByTagName("a");
        var length = links.length;
 
        for (var i = 0; i < length; i++) {
            var link = links[i];
            var innerHTML = link.innerHTML;
 
            switch(innerHTML) {
                case "Clear":
                    link.onclick = reset;
                    break;
                case "=":
                    link.onclick = calculate;
                    break;
                default:
                    link.onclick = getHandlerFunction(innerHTML);
                    break;
            }
        }
 
    };
في هذا الجزء السطر رقم 2 يأتي بكل اللينكات الموجوده في الصفحة و يضعها في مصفوفة و ذلك بإستخدام دالة getElementsByTagName.

السطر رقم 3 نضع عدد عناصر المصفوفة في المتغير length .

السطر رقم 5 حلقة for ستدور عدد مرات يساوي عدد عناصر مصفوفة اللينكات

داخل حلقة for يتم الوصول لمحتوى كل لينك بإستخدام innerHTML و المحتوى يكون الكتوب ما بين <a/> و<a> .

ثم نستخدم switch ففي حالة كون النص الموجود Clear نعين دالة reset للينك كما في السطر 11.

في حالة كان النص الموجود "=" نعين دالة calculate للينك كما في السطر 14.

لاحظ أنه عند تعيين دالة لإيفنت هندلر لا نضع () بعد الدالة لأن القوسين يعنيا أن يتم تنفيذ الدالة ووضع ناتجها لكن الوضع بدون أقواس يعني أن تضع الدالة نفسها و ليس ناتجها في الإيفنت هندلر

أما إن كان النص الموجود أي شيء آخر غير Clear أو = فإننا كما يظهر في السطر 17 نعين له الدالة getHandlerFunction(innerHTML) و ليس كما من المفترض أنك تتوقع أن نعين دالة addDigit لما هذا ؟ يحتاج الأمر لبعض الشرح . نحتاج لتمرير برامتر إلى دالة addDigit و يكون عبارة عن الرقم الذي سيتم كتابته في الشاشة عند الضغط على اللينك ,لكن عند إستخدام هذه الطريقة التي نستخدمها لتعين معالجات الأحداث لا يمكن تمرير برامتر بالطرق العادية و المثال التالي يوضح لماذا
مثال
<html>
  
  <head>
    
  </head>
  
  <body>
     <input type="button" value='Click here'>
  </body>
  <script type='text/javascript'>
      
     
   var button=document.getElementsByTagName('input')[0]
       
     var e=3
         
         button.onclick= function (e)
      {
     
       alert(e)    
      }
      
    </script>
  
</html>

حاول بنفسك »اضغط على "حاول بنفسك" لكى ترى كيف تعمل فى الحقيقة

عند الضغط على الزر سيظهر لك صندوق مكتوب فيه object mouse event .مع أنه كان المتوقع ان يظهر فيه الرقم 3 حيث أن قيمة e موضوعة ب 3 كما ترى بالكود .لكن ما يحدث هو أنه عند تعين الدوال للإحداث بهذه الطريقة فإن الجافا سكريبت تمرر تلقائيا كائن يسمى بالـ event سندرسه في الدروس التالية و هذا الكائن يوضع في البرامتر الذي تضعه في الدالة مثل e ,و هذا الكائن event مفيد جدا لكن دعنا منه الآن .المهم أنه لكي نمرر متغير للدالة addDigit الحل كان أن نستخدم دالة و سيطة و هي getHandlerFunction.

getHandlerFunction()

لاحظ السطر رقم 95 في الكود الكامل و الذي هو
 link.onclick = getHandlerFunction(innerHTML);
أن دالة getHandlerFunction لا توضع في الإيفنت هندر onclick بل يوضع ناتجها و ذلك لأنه يستخدم بعدها القوسين (innerHTML) . و إذا نظرت لتعريف الدالة الموجود من بداية السطر 71 و الذي هو كالتالي:
function getHandlerFunction(innerHTML) {
        return function() {
            addDigit(innerHTML);
 
            return false;
        };
    }
كما يتضح من التعريف الدالة تأخذ المتغير innerHTML و الذي سيكون فيه القيمة التي نريد أن نمررها لaddDigit . ثم ترجع الدالة
 return function() {
            addDigit(innerHTML);
 
            return false;
  }   
هذه الدالة هي التي ستعين للإيفنت هندلر.و لنأخذ مثال للتوضيح لنفترض أنك ضغط على الرقم 1 في الآلة الحاسبة فإن الدالة التي ستنفذ ستكون عبارة عن
{addDigit(1)

return false
}


[تحسين] تعين معالجات الأحداث بإستخدام دوال خاصة بذلك
الطريقة الأولى التي عرضناها لمعالجة الأحداث تتميز بالبساطة أما الطريقة التي سنعرضها الآن فتتميز بأنها أكثر مرونة و تتيح إمكانيات أكثر .هذه الطريقة تقوم على أساس إستخدام دوال معينه لإضافة لمعالجة الأحداث لكن المشكلة في أن الإنترنت إكسبلورر له دوال تختلف عن بقية المتصفحات .سنعرف دوال الإثنين و نعرف كيف نجعل الكود صالح لكل المتصفحات .

addEventListener(نوع الحدث, الدالة المعالجة, true أو false)

دالة addEventListener تستخدم لمعالجة الأحداث في كل المتصفحات تقريبا ماعدا إنترنت إكسبلورر و تقبل ثلاث بارمترات.


نوع الحدث :نوع الحدث الذي تريد أن تعمل الدالة عند حدوثه مثل "click" كنت تريد أن تنفذ الدالة عند ضغط كلك.

الدالة المعالجة:و هي الدالة التي ستنفذ عند وقوع الحدث.


البرامتر الأخير يكون عبارة عن true أو false سنجعله الآن false و سنتحدث عن الفارق في الدرس التالي .
و لنفهم بالمثال كيف تستخدم الدالة .
مثال 1
<html>
  
  <head>
  
  </head>
  
  <body>
   <input type="button" id="link" value="click here">

  </body>
    <script type='text/javascript'>
   
   
  var para = document.getElementById("link");
      
para.addEventListener("click", eventHandler, false);
      
para.addEventListener("click", otherEventHandler, false);
      
function eventHandler(event) {
alert("لقد ضغطت على " + this.nodeName);
}
      
function otherEventHandler(event) {
alert("نوع هذا الحدث كان " + event.type );
}
      
    </script>
</html>

حاول بنفسك »اضغط على "حاول بنفسك" لكى ترى كيف تعمل فى الحقيقة

يتضح من المثال أن addEventListener تستخدم كـ method للنقطة التي نعين لها الحدث .كما يتبين أيضا ميزة من مميزات هذه الطريقة و هي أنه يمكن بسهولة تعيين أكثر من دالة لنفس الحدث في حين أنه إذا أردنا عمل ذلك بالطريقة الأولى فإنه يكون موضوعا معقدا إلى حد ما. كما أيضا يتضح من السطر
alert("لقد ضغطت على " + this.nodeName);
أن الدالة التي تعين للحدث تعتبر داخل الكائن الذي يمثل النقطة التي يحدث لها الحدث و لذا يظهر لك في الصندوق الأول INPUT. البرامتر event فهو يمرر فيه تلقائيا كائن له عدد من الخصائص مثل type و التي تعرف من خلالها نوع الحدث و له خواص أخرى سنتحدث عنها و عنه لاحقا . الدالة المقابلة لـ addEventListener في الإنترنت إكسبلورر هي attachEvent و تقبل متغيرين فقط الأول نوع الحدث(يكتب نوع الحدث بشكل مختلف فبدلا من "click" يكتب "onclick" و الثاني الدالة المعالجة.

removeEventListener(نوع الحدث, المعالج, true أو flase)

تأخذ نفس البرامتر التي تأخذها addEventListener لكن تقوم بالعكس فهي .تزيل مراقبة الحدث كما يوضح المثال:
مثال
<html>
  
  <head>
  
  </head>
  
  <body>
   <input type="button" id="link" value="click here">

  </body>
    <script type='text/javascript'>
   
   
  var link = document.getElementById("link");
      
link.addEventListener("click", selfRemovingEvent, false);
      
function selfRemovingEvent(event) {
  
alert("يتم مراقبة الحدث مرة واحدة ثم إلغاء المراقبة");
  
this.removeEventListener(event.type, selfRemovingEvent,false);
}     
    </script>
</html>

حاول بنفسك »اضغط على "حاول بنفسك" لكى ترى كيف تعمل فى الحقيقة

عندما تضغط على الزر للمرة الأولى سيظهر لك صندوق alert,لكن إذا ضغطت ثانية لن يظهر الصندق لأن المراقبة يكون قد تم إزالتها من خلال دالة removeEventListener.

الدالة المقابلة في الإنترنت إكسبلورر هي detachEvent و تقبل نفس البرامترز التي تقبلها attachEvent .

الكائن Event

في كل المتصفحات بإستثناء إنترنت إكسبلورر يمرر تلقائيا للدالة كبرامتر أما في إنترنت إكسبلور فهو يكون خاصية لـ window ,و لكي يكون الكود متوافق مع المتصفحات كلها يمكنك كتابته هكذا:
function handler(event) {
event = event || window.event;
}
و الكائن event له خصائص و دوال تختلف بإختلاف الحدث لكن هناك عدد منها عم أهمهم: الخصائص:

type:نوع الحدث مثل "click" او "load".

target:سنستخدمه في معرفة العنصر الذي حدث له الحدث مثلا العنصر الذي تم الضغط عليه يختلف إنترنت إكسبلورر حيث تستخدم srcElemen . الدوال :

preventDefault():لمنع التصرف الإفتراضي من الحدوث بمعنى أنه إن كنت تضغط على لينك لا يفتح الصفحة التي كان من المفترض انه سيفتحها .

و في إنترنت أكسبلورر يكون البديل event.returnValue = false;. مثال:
مثال
<html>
<head>
    

</head>
<body>


<a href="http://www.google.com">Click here</a>


</body>
  <script type="text/javascript">
var a = document.getElementsByTagName("a")[0];
   
a.addEventListener("click", whatNode, false);

    function whatNode(event) {

alert("Target is : " + event.target);
       
event.preventDefault();
}

</script>

</html>

حاول بنفسك »اضغط على "حاول بنفسك" لكى ترى كيف تعمل فى الحقيقة

كيفية العثور على الأحداث.

أنظر إلى الشكل التالي .

هو عبارة عن ناتج كود الهيتميل هذا مع بعض الإستايل شيت.
<html>
<head>
    <style type="text/css">
        body, div, p {
padding: 10px;
border: 2px solid blue;
}
a{
 position: absolute;
left: 200px
}
    </style>

</head>
<body>
body
<div>
    div
<p>
 p
<a href="http://www.google.com">Click</a>
</p>
</div>
</body>
<html/>
عند قيامك بالضغط على اللينك Click فأنت أيضا تضغط داخل الصندوق p أي تضغط على الفقرة .و أيضا تضغط دخال الـ div و داخل الـ body , و بالطبع داخل document . بمعنى أنك عندما تضغط على عنصر فأنت أيضا تضغط على أباء هذا العنصر و أباء أبائه.

إذا كان هناك دالة ستعمل عند الضغط على اللينك aو دالة تعمل عند الضغط على p و دالة ستعمل عند الضغط على div و دالة ستعمل عند الضغط على body و دالة ستعمل عند الضغط على document.عند الضغط على اللينك أي دالة ستنفذ أولا ؟؟

ستعرف ذلك بفهم كيف يعثر المتصفح على الأحداث يتم ذلك من خلال ثلاث مراحل(three phases) يبدأ اولا من الخارج من الأب الأكبر document يبحث عن الأحداث و ينفس الدوال المعينه لها حتى يصل إلى أصغر إبن حدث له الحدث و تسمى هذه المرحلة بالـ Capturing و عند وصوله للإبن الأصغر الوصول يعتبر المرحلة الثانية و بعد الوصول يبدأ في مرحلة ثالثه Bubbling و هي أنه يبدأ ثانية من الإبن الأصغر و ينتقل منه إلى الأب حتى الأب الأكبر document يبحث عن الأحداث و ينفذها ثانية و ربما أفضل طريقة لتوضيح المفهوم تكون من خلال الأمثلة.

قبل أن نأخذ أمثلة سنذكر بعض الأشياء.

البرامتر الثالث للدالة addEventListener يحدد المرحلة التي ستنفذ فيها الدالة هل في Capturing أم Bubbling. عند وضعه true فإنه سيتم تنفيذ الدالة عند الوصول للعنصر في مرحلة الـCapturing الأولى.

أما عند وضعه false فإنه سيتم تنفيذ الدالة عند العثور عليه في مرحلة الـ Bubbling الثانية. عند معالجة الأحداث بالطريقة الأولى التي ذكرناها في أول الفصل فإنه يتم تنفيذ الدالة في مرحلة Bubbling ,و أيضا إنترنت أكسبلورر لا يدعم إلا التنفيذ في مرحلة الـBubbling .

eventPhase :خاصية من خواص الكائن event و تعرف من خلالها المرحلة التي فيها المتصفح في بحثه عن الأحداث إن كانت قيمته1 تكون المرحلة capturing و ان كانت 2 تكون المرحلة الثانية الوصول للعنصر و إن كانت 3 تكون المرحلة الثالثة bubbling مثال
مثال
<html>
<head>
    <style type="text/css">
        body, div, p {
padding: 10px;
border: 2px solid blue;
}
a{
 position: absolute;
left: 200px
}
    </style>

</head>
<body>
body
<div>
    div
<p>
 p
<a href="http://www.google.com">Click</a>
</p>
</div>
</body>
<script type="text/javascript">
   var div = document.getElementsByTagName("div")[0];
var p = document.getElementsByTagName("p")[0];
var a = document.getElementsByTagName("a")[0];
   //on Bubbling
   document.addEventListener("click", whatNode, false);
document.body.addEventListener("click", whatNode, false);
div.addEventListener("click", whatNode, false);
p.addEventListener("click", whatNode, false);
a.addEventListener("click", whatNode, false);
  //on Capturing
document.addEventListener("click", whatNode, true);
document.body.addEventListener("click", whatNode, true);
div.addEventListener("click", whatNode, true);
p.addEventListener("click", whatNode, true);
a.addEventListener("click", whatNode, true);

    function whatNode(event) {

alert(this.nodeName+' '+"phase: " + event.eventPhase);
       
event.preventDefault();
}

</script>

</html>

حاول بنفسك »اضغط على "حاول بنفسك" لكى ترى كيف تعمل فى الحقيقة

في هذا الكود :
  • من السطر 1 حتى 24 أنشأنا صفحة الهيتميل التي عرضناها في أول الدرس.
  • من السطر 26 لـ28 وصلنا إلى جميع عناصر الصفحة
  • من السطر 30 حتى 34 أضفنا معالجات دوال لكل عنصر ستلاحظ في مرحلة الـBubbling.
  • من السطر 36 حتى 40أضفنا معالجات دوال لكل عنصر ستلاحظ في مرحلة الـCapturing .
  • بداية من السطر 42 عرفنا دالة whatNode التي ستعمل عند حدوث الحدث و هي تظهر إسم العنصر الذي تنفذ دالته و المرحلة التي فيها البحث (eventPhase)
إذا ضغطت على اللينك click ستظهر الرسائل بهذا الترتيب:
#document phase: 1
BODY phase: 1
DIV phase: 1
P phase: 1
A phase: 2
A phase: 2
P phase: 3
DIV phase: 3
BODY phase: 3
#document phase: 3
حيث ستبدأ المرحلة الأولى الـCapturing من الخارج للداخل و لأننا و سيتم تنفيذ معالجات الأحداث التي لها القيمة true في البرمتر الثالث ثم عندما نصل لأصغر عنصر حدث له حدث الضغط و هو اللينك نصبح إنتقالنا للمرحلة 2 و يعود البحث ثانية من الداخل إلى الخارج في المرحلة الثالثة الـBubbling و تنفذ فيها معالجات الأحداث التي لها القيمة false في البرامتر الثالث . إذا قمت بالضغط على div فإن هذه الرسائل فقط ستظهر:
#document phase: 1
BODY phase: 1
DIV phase: 2
DIV phase: 2
BODY phase: 3
#document phase: 3
فكما قلنا أن الضغط على عنصر يؤثر على العناصر الأباء له و أباء الأباء.

stopPropagation()

هذه الدالة من دوال (methods) الكائن event ,ووظيفتها أنها توقف البحث عن الأحداث كما بالمثال التالي حيث سنعدل دالة whatNode بحيث أن البحث عن الأحداث و تنفيذ الدوال بالتالي سيتوقف عند الوصول للـ div .
function whatNode(event) {
if (this.nodeName === "DIV") {
event.stopPropagation();
}
console.log(this.nodeName, "phase: " + event.eventPhase);
event.preventDefault();
}
و من فهم كيف يتم تنفيذ الأحداث يمكننا الإستفادة من ذلك في بعض التطبيقات مثلا يمكنك إضافة دالة ما تعمل عند الضغط على أي لينك فبدلا من أن تحدد معالجات الأحداث له بإستخدام whlie بهذه الطريقة :
var allLinks = document.getElementsByTagName("a");
var i = allLinks.length; (continues on next page)
172 The JavaScript Pocket Guide
while (i--) {
allLinks[i].addEventListener("click", somethingSpecial,false);
}
function somethingSpecial(event) {
alert(this.href);
event.preventDefault();
}
يمكننا أن نفعل نفس الشيء بطريقة أبسط هكذا
document.addEventListener("click", delegatedSomethingSpecial,true);
function delegatedSomethingSpecial(event) {
if (event.target.nodeName === "A") {
alert(event.target.href);
event.preventDefault();


و ميزة هذه الطريقة الثانية إذا أضيفت لينكات جديدة للصفحة من خلال الجافا سكريبت أو أجاكس(ajax) فإنه أيضا ستعمل الدالة عند الضغط عليهم و تسمى الطريقة الثانية بالـevent delegation.
[تحسين] تابع تطبيق 1.
يمكن إعادة كتابة كود الآلة الحاسبة بإستخدام و يكون كالتالي:
لجميع المتصفحات ما عدا إنترنت إكسبلورر
<!DOCTYPE html>

<html>
<head>
    <title>Lesson 19: Example 01</title>
    <style type="text/css">
    td {
        border: 1px solid gray;
        width: 50px;
    }
    
    #results {
        height: 20px;
    }
    </style>
</head>
<body>
    <table border="0" cellpadding="2" cellspacing="2">
        <tr>
            <td colspan="4" id="results"></td>
        </tr>
        <tr>
            <td><a href="#">1</a></td>
            <td><a href="#">2</a></td>
            <td><a href="#">3</a></td>
            <td><a href="#">+</a></td>
        </tr>
        <tr>
            <td><a href="#">4</a></td>
            <td><a href="#">5</a></td>
            <td><a href="#">6</a></td>
            <td><a href="#">-</a></td>
        </tr>
        <tr>
            <td><a href="#">7</a></td>
            <td><a href="#">8</a></td>
            <td><a href="#">9</a></td>
            <td><a href="#">*</a></td>
        </tr>
        <tr>
            <td><a href="#">Clear</a></td>
            <td><a href="#">0</a></td>
            <td><a href="#">=</a></td>
            <td><a href="#">/</a></td>
        </tr>
    </table>
    <script type="text/javascript">
    function addDigit(digit) {
        var resultField = document.getElementById("results");
        resultField.innerHTML += digit;

    }

    function calculate() {
        var resultField = document.getElementById("results");
        
        resultField.innerHTML = eval(resultField.innerHTML);

    }

    function reset() {
        var resultField = document.getElementById("results");
        
        resultField.innerHTML = "";

    }

    function getHandlerFunction(innerHTML) {
        return function() {
            addDigit(innerHTML);

        };
    }

    onload = function() {
        var links = document.getElementsByTagName("a");
        var length = links.length;

        for (var i = 0; i < length; i++) {
            var link = links[i];
            var innerHTML = link.innerHTML;
            var func = null;

            switch(innerHTML) {
                case "Clear":
                    func = reset;
                    break;
                case "=":
                    func = calculate
                    break;
                default:
                    func = getHandlerFunction(innerHTML);
                    break;
            }

            link.addEventListener("click", func, false);
        }

    };
    </script>
</body>
</html>
للإنترنت إكسبلورر
<!DOCTYPE html>

<html>
<head>
    <title>Lesson 19: Example 02</title>
    <style type="text/css">
    td {
        border: 1px solid gray;
        width: 50px;
    }
    
    #results {
        height: 20px;
    }
    </style>
</head>
<body>
    <table border="0" cellpadding="2" cellspacing="2">
        <tr>
            <td colspan="4" id="results"></td>
        </tr>
        <tr>
            <td><a href="#">1</a></td>
            <td><a href="#">2</a></td>
            <td><a href="#">3</a></td>
            <td><a href="#">+</a></td>
        </tr>
        <tr>
            <td><a href="#">4</a></td>
            <td><a href="#">5</a></td>
            <td><a href="#">6</a></td>
            <td><a href="#">-</a></td>
        </tr>
        <tr>
            <td><a href="#">7</a></td>
            <td><a href="#">8</a></td>
            <td><a href="#">9</a></td>
            <td><a href="#">*</a></td>
        </tr>
        <tr>
            <td><a href="#">Clear</a></td>
            <td><a href="#">0</a></td>
            <td><a href="#">=</a></td>
            <td><a href="#">/</a></td>
        </tr>
    </table>
    <script type="text/javascript">
    function addDigit(digit) {
        var resultField = document.getElementById("results");
        resultField.innerHTML += digit;

    }

    function calculate() {
        var resultField = document.getElementById("results");
        
        resultField.innerHTML = eval(resultField.innerHTML);

    }

    function reset() {
        var resultField = document.getElementById("results");
        
        resultField.innerHTML = "";

    }

    function getHandlerFunction(innerHTML) {
        return function() {
            addDigit(innerHTML);

        };
    }

    onload = function() {
        var links = document.getElementsByTagName("a");
        var length = links.length;

        for (var i = 0; i < length; i++) {
            var link = links[i];
            var innerHTML = link.innerHTML;
            var func = null;

            switch(innerHTML) {
                case "Clear":
                    func = reset;
                    break;
                case "=":
                    func = calculate
                    break;
                default:
                    func = getHandlerFunction(innerHTML);
                    break;
            }

            link.attachEvent("onclick", func);
        }

    };
    </script>
</body>
</html>
و بالطبع نحن نحتاج كود يعمل في حالة أي متصفح و لذا نقوم بعمل هذا الكائن و نضعه في ملف خارجي هذا الملف سنستخدمه في أي مرة نريد فيها إستخدام دوال معالجة الأحداث:
var eventUtility = {
    addEvent : (function() {
        if (typeof addEventListener !== "undefined") {
            return function(obj, evt, fn) {
                obj.addEventListener(evt, fn, false);
            };
        } else {
            return function(obj, evt, fn) {
                obj.attachEvent("on" + evt, fn);
            };
        }
    }()),
    removeEvent : (function() {
        if (typeof removeEventListener !== "undefined") {
            return function(obj, evt, fn) {
                obj.removeEventListener(evt, fn, false);
            };
        } else {
            return function(obj, evt, fn) {
                obj.detachEvent("on" + evt, fn);
            };
        }
    }())
};
عند تعريف دالة بهذه الطريقة function(){}() فإنها تكون عبارة عن دالة تنفذ تلقائيا . تضع كود هذا الكائن في ملف يسمى eventUtility.js و نقوم بإستدعائه في كود الآلة الحاسبة كالتالي:
<!DOCTYPE html>

<html>
<head>
    <title>Lesson 20: Example 01</title>
    <style type="text/css">
    td {
        border: 1px solid gray;
        width: 50px;
    }
    
    #results {
        height: 20px;
    }
    </style>
</head>
<body>
    <table border="0" cellpadding="2" cellspacing="2">
        <tr>
            <td colspan="4" id="results"></td>
        </tr>
        <tr>
            <td><a href="#">1</a></td>
            <td><a href="#">2</a></td>
            <td><a href="#">3</a></td>
            <td><a href="#">+</a></td>
        </tr>
        <tr>
            <td><a href="#">4</a></td>
            <td><a href="#">5</a></td>
            <td><a href="#">6</a></td>
            <td><a href="#">-</a></td>
        </tr>
        <tr>
            <td><a href="#">7</a></td>
            <td><a href="#">8</a></td>
            <td><a href="#">9</a></td>
            <td><a href="#">*</a></td>
        </tr>
        <tr>
            <td><a href="#">Clear</a></td>
            <td><a href="#">0</a></td>
            <td><a href="#">=</a></td>
            <td><a href="#">/</a></td>
        </tr>
    </table>
    <script src="eventUtility.js" type="text/javascript"></script>
    <script type="text/javascript">
    function addDigit(digit) {
        var resultField = document.getElementById("results");
        resultField.innerHTML += digit;

    }

    function calculate() {
        var resultField = document.getElementById("results");
        
        resultField.innerHTML = eval(resultField.innerHTML);

    }

    function reset() {
        var resultField = document.getElementById("results");
        
        resultField.innerHTML = "";

    }

    function getHandlerFunction(innerHTML) {
        return function() {
            addDigit(innerHTML);

        };
    }

    onload = function() {
        var links = document.getElementsByTagName("a");
        var length = links.length;

        for (var i = 0; i < length; i++) {
            var link = links[i];
            var innerHTML = link.innerHTML;
            var func = null;

            switch(innerHTML) {
                case "Clear":
                    func = reset;
                    break;
                case "=":
                    func = calculate;
                    break;
                default:
                    func = getHandlerFunction(innerHTML);
                    break;
            }

            eventUtility.addEvent(link, "click", func);
            //link.addEventListener("click", func, false);
        }

    };
    </script>
</body>
</html>

هذا الكود صالح لأي نوع من المتصفحات.