IE vs W3C event handling

ივენთები საკმაოდ პრობლემატური საკითხია თანამედროვე JavaScript პროგრამირებაში, რაც ცალსახად გამოწვეულია ყველასათვის კარგად ცნობილი და “საყვარელი” InternetExplorer – ის გამო. პრინციპში ძალიან ცოტაა ისეთი შემთხვევები როდესაც ამ პრობლემაზე გვერდის ავლა არ შეიძლება მარტივად, თუმცა ასევე არსებობს შემთხვევები როდესაც ეს არათავსებოდა ძალიან არასასიამოვნოდ იჩენს ხოლმე თავს.

მიუხედავად იმისა, რომ, W3C – ს მიერ საკმაოდ მკაფიოდ არის ჩამოყალიბებული ივენთ მენეჯმენტის მოდელი, IE როგორც სხვა, ასევე ამ შემთხვევაშიც მოწოდების სიმაღლეზეა და თავის განსაკუთრებულ და “უფრო სწორ” მიდგომას გვთავაზობს, რაც საბოლოო ჯამში იწვევს ორმაგი(მინიმუმ) კოდის წერის აუცილებლობას.

პრობლემა

W3C მოდელის მიხედვით DOM ელემენტის რომელიმე ივენთისათვის(მაგ. onclick, onmousedown, onmouseup და ა.შ.) შესაძლებელია იმდენი ივენთ ჰენდლერის(ფუნქცია/მეთოდი რომელიც ავტომატურად გამოიძახება ამ ივენთის წარმოქმნის შემთხვევაში) რეგისტრაცია რამდენიც ეს საჭიროა კონკრეტული ამოცანისათვის, ეს მიიღწევა DOM ელემენტის addEventListener მეთოდის გამოყენებით:

[javascript]
var el = document.getElementById(‘my-element’);
el.addEventListener(‘click’, myHandler1, false);
el.addEventListener(‘click’, myHandler2, false);
el.addEventListener(‘click’, myHandler3, false);
[/javascript]

როგორც ვხედავთ მაგალითიდან, მეთოდის სიგნატურა ძალიან მარტივია:

  • ივენთის სახელი(ყურადღება მიაქციეთ ივენთის სახელი გადაეცემა “on” პრეფიქსის გარეშე);
  • ფუნქცია რომელიც გამოძახებული იქნება ამ ივენთის წარმოშობის შემთხვევაში;
  • და მესამე პარამეტრი რომელიც DOM – ის ხეში ივენთის გავრცელების მიმართულებას(ქვევიდან ზევით ანუ შვილიდან მშობლისკენ ან პირიქით ზევიდან ქვევით ანუ მშობლიდან შვილისკენ) განსაზღვრავს, თუმცა ეს თემა მიმდინარე პოსტს სცილდება ამიტომ უბრალოდ მუდმივად გამოვიყენებთ “false” პარამეტრს;

რა ხდება ივენთების ამ გზით რეგისტრაციის შემთხვევაში და როგორ მუშაობს ეს მოდელი?

როგორც ზემოთ ავღნიშნე, საჭირო ივენთის წარმოქმნის შემთხვევაში(ამ შემთხვევაში onclick) გამოიძახება შესაბამისი ფუნქცია(ამ მაგლითისათვის გამოძახებული იქნება: myHandler1, myHandler2 და myHandler3 ფუნქციები), მაგრამ აქ მნიშვნელოვანია ის დეტალი რომ ფუნქცია გამოიძახება არა თავის საკუთარ არამედ DOM ელემენტის კონტექსტში. ეს ნიშნავს იმას რომ “this” ფუნქციის შიგნით მიუთითებს DOM ელემენტს. მაგალითად:

[javascript]
function myHandler() {
//”this” მიუთითებს DOM ელემენტს,
//რაც ნიშნავს იმას რომ ფუნქცია სრულდება ამ ელემენტის(ობიექტის) კონტექსტში
alert(“element’s id is: ” + this.id);
}
var el = document.getElementById(‘my-element’);
el.addEventListener(‘click’, myHandler, false);
[/javascript]

“my-element” – ზე დაწკაპუნების შემთხვევაში დავინახავთ შეტყობინებას “element’s id is: my-element”, რაც თავისთავად თვალსაჩინოს ხდის იმ ფაქტს რომ ივენთ მენეჯერი აკოპირებს ჰენლდერ ფუნქციის და იგი სრულდება მიმდინარე DOM ელემენტის კონტექსტში(უფრო მეტი სიცხადისათვის იხ. ანონიმური ივენთ ჰენდლერები და ანონიმური ფუნქციები).

ანალოგიური შედეგი შეგვეძლო მიგვეღწია შემდეგი ხერხით:
[javascript]
function myHandler() {
alert(“element’s id is: ” + this.id);
}
var el = document.getElementById(‘my-element’);
el.onclick = myHandler;
[/javascript]

ან უბრალოდ ასე:
[javascript]
var el = document.getElementById(‘my-element’);
el.onclick = function() {
alert(“element’s id is: ” + this.id);
};
[/javascript]

მიუხედავად იმისა რომ მეორე და მესამე მაგალითები თავსებადია ყველა ბრაუზერთად, მას აქვს ერთი უარყოფითი მხარე, ამ ხერხით შეუძლებელია ერთსა და იმავე ივენთისათვის მრავალი ჰენდლერ ფუნქციის რეგისტრაცია, რაც გარკვეულ შემთხვევებში დიდ უხერხულობებს იწვევს.

რა განსხვავებებია InetrnetExplorer – ში? IE – ს გააჩნია ზემოთ W3C – ს მსგავსი მიდგომა, თუმცა ეს მხოლოდ მსგავსებაა და ფუნქციონალურობის თვალსაზრისით აბსოლუტურად არაფერი არ აქვს საერთო ზემოთ აღნიშნულ მოდელთან.

IE გვთავაზობს ელემენტის ივენთის რეგისტრაციის თავისებურ მექანიზმს DOM ელემენტის attachEvent მეთოდის მეშვეობით:

[javascript]
var el = document.getElementById(‘my-element’);
el.attachEvent(‘onclick’, myHandler1);
el.attachEvent(‘onclick’, myHandler2);
el.attachEvent(‘onclick’, myHandler3);
[/javascript]

ეს მაგალითი მსგავისა W3C მოდელისა, თუმცა გარდა მეთოდის სახელის განსხვავებისა, ასევე განსხვავებულია თავად მეთოდის სიგნატურა:

  • ივენთის სახელი, თუმცა ამ შემთხვევაში “on” პრეფიქსი აუცილებელია;
  • შესაბამისი ჰენდლერი;
  • მესამე პარამეტრი საერთოდ არ არსებობს;
  • ამ მოდელის დანიშნულება ანალოგიურია W3C მოდელისა, და ამ ერთი შეხედვით მარტივი არათავსებადობის აღმოსაფხვრელად თითქოს საკმარისი მარტივი ე.წ. ვრაპერის დაწერა რომელიც ამ განსხვავებას დამალავს საბოლოო კოდისაგან. თუმცა თუ გადავწერთ პირველ მაგალითს ასე:

    [javascript]
    function myHandler() {
    //ამ შემთხვევაში “this” მიუთითებს “window” ობიექტს
    alert(“element’s id is: ” + this.id);
    }
    var el = document.getElementById(‘my-element’);
    el.attachEvent(‘onclick’);
    [/javascript]

    და შევასრულებთ IE – ში, მივიღებთ სრულიად განსხვავებულ რეზულტატს. რატომ? ეს ხდება იმიტომ რომ IE – ს ივენთების მენეჯერი უბრალოდ გამოიძახებს ამ ფუნქციას(ცხადია ეს ხდება DOM ელემენტის კონტექსტს მიღმა) და ამ შემთხვევაში “this” მიუთითებს არა DOM ელემენტს, არამედ გლობალურ “window” ობიექტს.

    გამოსავალი

    [javascript]
    var EventWrapper = {
    /**
    * @param Object DOM element
    * @param String Event Name
    * @param Function Event Handler
    */
    addListener: function(el, eventName, handler) {
    //თუ ბრაუზერს გააჩნია W3C მოდელის რეალიზაცია
    if (el.addEventListener) {
    el.addEventListener(‘click’, handler, false);
    } else {//მხოლოდ InternetExplorer – ის შემთხვევაში
    var fn = function() {
    //კონტექსტის ფიქსაცია ფუნქციის “call” მეთოდის გამოყენებით
    //”call” მეთოდს პირველ პარამეტრად გადაეცემა სასურველი კონტექსტი
    handler.call(el);
    }
    el.attachEvent(‘on’ + eventName, fn);
    }
    }
    };
    [/javascript]

    მაგალითიდან ნათლად ჩანს თუ რა განსხვავებაა W3C მოდელსა და InternetExplorer – ისათვის განკუთვნილ კოდში. პრობლემის აღმოფხვრა მარტივად ხორციელდება ფუნქციის “call” მეთოდის მეშვეობით, რაც სრულად ხსნის აღწერილ პრობლემას. თუ როგორ მუშაობს ფუნქციის “call” მეთოდი, შეგიძლია იხილოთ შესაბამისი პოსტი.

    დასკვნა

    მიუხედავად იმისა, რამდენად განსხვავებულიც არ უნდა იყოს ბრაუზერებს შორის ამა თუ იმ დეტალის რეალიზაცია, ნებისმიერ შემთხვევაში საჭიროა ალტერნატიული გზების ძებნა. ჩემს კონკრეტულ შემთხვევაშიც კი, მიუხედავად იმისა რომ პრიმიტივიზმის მომხრე ვარ და ყოველთვის ვცდილობ დავიცვა ეს წესი, მაინც ხშირად ვაწყდები მსგავს გამოუვალ მდგომარეობებს. ასეთი მდგომარეობებიდან გამოსავალის პოვნა როგორც წესი არ არის რთული, თუმცა არის შემთხვევები როდესაც მიგნებული გამოსავალი არ არის საუკეთესო და უფრო მეტ კვლევას შედარებით უფრო დახვეწილი შედეგისკენ მივყევარ. იმედია ეს პოსტი უფრო მეტ ნათელს მოჰფენს ამ საკითხს, ხოლო აღწერილი გამოსავალი პრობლემიდან სასარგებლო იქნება თქვენთვის.

    ტეგები: ,

    4 Responses to “IE vs W3C event handling”

    1. ოთო ამბობს:

      შესანიშნავი პოსტია ნამდვილად! ;)
      კარგი დაბრუნებაა :)

    2. საშკა ამბობს:

      სიამოვნებით წავიკითხე, მადლობ, ისე სოსო ჩემი ყოველდღიური კოდირების განუყოფელი ნაწილი რომ გახდა javascript-ი და JQuery, ვაღიარებ რომ შენი ბლოგის დიდი წვლილიც არის მაგაში :)

    3. იოსები ამბობს:

      საშკა, ძალიან მიხარია თუ ჩემი ბლოგი დადებით როლს ასრულებს შენს ყოველდღიურ დეველოპმენტში :)

    4. [...] თვისებაზე ობიექტის მინიჭებაა(იხ. განსხვავება IE და W3C მოდელებს შორის). ამ განსხვავების საფუძველზე [...]

    დატოვე კომენტარი:

    ქართული კლავიატურა, ჩართვა/გამორთვა კლავიშით "~"