Hodnota „to“ v rámci psovoda pomocí addEventListener

hlasů
41

Vytvořil jsem javascript objekt přes prototypování. Snažím se vykreslit tabulku dynamicky. Zatímco rendering část je jednoduchý a funguje dobře, jsem také nutné zpracovat určité straně klienta události pro dynamicky vykreslené tabulky. To je také snadné. Kde mám problémy se s tímto „“ odkazu uvnitř funkce, která zpracovává událost. Místo toho, aby „to“ odkazuje na objekt, to odkazovat na prvek, který zvýšenou událost.

Viz kód. Problematický oblast je v „ticketTable.prototype.handleCellClick = funkce ()“

function ticketTable(ticks)
{
    // tickets is an array
    this.tickets = ticks;
} 

ticketTable.prototype.render = function(element)
    {
        var tbl = document.createElement(table);
        for ( var i = 0; i < this.tickets.length; i++ )
        {
            // create row and cells
            var row = document.createElement(tr);
            var cell1 = document.createElement(td);
            var cell2 = document.createElement(td);

            // add text to the cells
            cell1.appendChild(document.createTextNode(i));
            cell2.appendChild(document.createTextNode(this.tickets[i]));

            // handle clicks to the first cell.
            // FYI, this only works in FF, need a little more code for IE
            cell1.addEventListener(click, this.handleCellClick, false);

            // add cells to row
            row.appendChild(cell1);
            row.appendChild(cell2);


            // add row to table
            tbl.appendChild(row);            
        }

        // Add table to the page
        element.appendChild(tbl);
    }

    ticketTable.prototype.handleCellClick = function()
    {
        // PROBLEM!!!  in the context of this function, 
        // when used to handle an event, 
        // this is the element that triggered the event.

        // this works fine
        alert(this.innerHTML);

        // this does not.  I can't seem to figure out the syntax to access the array in the object.
        alert(this.tickets.length);
    }
Položena 27/08/2009 v 03:44
zdroj uživatelem
V jiných jazycích...                            


6 odpovědí

hlasů
46

Můžete použít bind , která umožňuje určit hodnotu, která by měla být použita jako to u všech volání na danou funkci.

   var Something = function(element) {
      this.name = 'Something Good';
      this.onclick1 = function(event) {
        console.log(this.name); // undefined, as this is the element
      };
      this.onclick2 = function(event) {
        console.log(this.name); // 'Something Good', as this is the binded Something object
      };
      element.addEventListener('click', this.onclick1, false);
      element.addEventListener('click', this.onclick2.bind(this), false); // Trick
    }

Problém ve výše uvedeném příkladu je to, že není možné odstranit posluchače se vážou. Dalším řešením je použití speciální funkci nazvanou handleEvent zachytit všechny události:

var Something = function(element) {
  this.name = 'Something Good';
  this.handleEvent = function(event) {
    console.log(this.name); // 'Something Good', as this is the Something object
    switch(event.type) {
      case 'click':
        // some code here...
        break;
      case 'dblclick':
        // some code here...
        break;
    }
  };

  // Note that the listeners in this case are this, not this.handleEvent
  element.addEventListener('click', this, false);
  element.addEventListener('dblclick', this, false);

  // You can properly remove the listners
  element.removeEventListener('click', this, false);
  element.removeEventListener('dblclick', this, false);
}

Stejně jako vždy MDN je nejlepší :). Jen jsem kopírovat vložit roli, než na tuto otázku odpovědět.

Odpovězeno 22/10/2013 v 01:31
zdroj uživatelem

hlasů
35

Musíte „bind“ popisovač instance.

var _this = this;
function onClickBound(e) {
  _this.handleCellClick.call(cell1, e || window.event);
}
if (cell1.addEventListener) {
  cell1.addEventListener("click", onClickBound, false);
}
else if (cell1.attachEvent) {
  cell1.attachEvent("onclick", onClickBound);
}

Všimněte si, že zpracování události zde normalizuje eventobjekt (předán jako první argument) a vyvolává handleCellClickve vhodném kontextu (tj s odkazem na prvek, který byl připojen na posluchače události).

Všimněte si také, že místní normalizaci zde (tj nastavení správného thisv obsluze události) vytváří cyklický odkaz mezi funkce použité jako obsluhy události ( onClickBound) a objektem prvek ( cell1). V některých verzích IE (6 a 7), to může a pravděpodobně bude, mít za následek únik paměti. Toto nevracení v podstatě je prohlížeč nedaří uvolnění paměti na načtení stránky z důvodu cyklický odkaz existující mezi nativním a hostitelským objektem.

Chcete-li ji obejít, budete muset buď a) klesnout thisnormalizace; b) použít alternativní (a komplexnější) normalizace strategie; c) „uklidit“ stávající posluchače událostí na stránce vyložit, tedy za použití removeEventListener, detachEventa prvky nulling (což bohužel rychle vykreslovat historie navigace prohlížečem k ničemu).

Dalo by se také najít knihovnu JS, která se stará o to. Většina z nich (např jQuery, prototype.js, YUI, atd) obvykle zvládnout vymazány, jak je popsáno v bodě (c).

Odpovězeno 27/08/2009 v 03:53
zdroj uživatelem

hlasů
9

Také, jeden způsob, jak je použít EventListener rozhraní (od DOM2 !! Zajímá vás, proč to nikdo nezmínil, s ohledem na to je způsob, jak neatest a znamenal právě pro takové situace.)

Tj namísto předávání funkci zpětného volání, předáte objekt, který implementuje rozhraní EventListener. Jednoduše řečeno, to prostě znamená, že byste měli mít vlastnost v objektu zvaném „handleEvent“, který odkazuje na funkci zpracování událostí. Hlavním rozdílem je zde, uvnitř funkce, thisbude odkazovat na objekt předaný addEventListener. To znamená, že this.theTicketTablebude objekt instance v belowCode. Abychom pochopili, co mám na mysli, podívejte se na upravený kód pečlivě:

ticketTable.prototype.render = function(element) {
...
var self = this;

/*
 * Notice that Instead of a function, we pass an object. 
 * It has "handleEvent" property/key. You can add other
 * objects inside the object. The whole object will become
 * "this" when the function gets called. 
 */

cell1.addEventListener('click', {
                                 handleEvent:this.handleCellClick,                  
                                 theTicketTable:this
                                 }, false);
...
};

// note the "event" parameter added.
ticketTable.prototype.handleCellClick = function(event)
{ 

    /*
     * "this" does not always refer to the event target element. 
     * It is a bad practice to use 'this' to refer to event targets 
     * inside event handlers. Always use event.target or some property
     * from 'event' object passed as parameter by the DOM engine.
     */
    alert(event.target.innerHTML);

    // "this" now points to the object we passed to addEventListener. So:

    alert(this.theTicketTable.tickets.length);
}
Odpovězeno 27/03/2013 v 06:24
zdroj uživatelem

hlasů
5

Vím, že se jedná o starší příspěvek, ale můžete také jednoduše přiřadit kontext do proměnné self, hodit si funkce v anonymní funkce, která vyvolá svou funkci s .call(self)a prochází v kontextu.

ticketTable.prototype.render = function(element) {
...
    var self = this;
    cell1.addEventListener('click', function(evt) { self.handleCellClick.call(self, evt) }, false);
...
};

To funguje lépe než „Přijímání odpovědí“, protože kontext nemusí být přiřazena proměnné pro celou třídu či globální, spíše je to úhledně zastrčený v rámci stejného postupu, který poslouchá událost.

Odpovězeno 15/02/2013 v 05:27
zdroj uživatelem

hlasů
1

Silně ovlivněn kamathln a odpověď gagarine to myslel jsem si, že řešení tohoto problému.

Myslel jsem, že by pravděpodobně mohlo získat trochu více svobody, když dáte handeCellClick v seznamu zpětné volání a použít objekt pomocí rozhraní EventListener na událost ke spuštění metody seznam callback s správné to.

function ticketTable(ticks)
    {
        // tickets is an array
        this.tickets = ticks;
        // the callback array of methods to be run when
        // event is triggered
        this._callbacks = {handleCellClick:[this._handleCellClick]};
        // assigned eventListenerInterface to one of this
        // objects properties
        this.handleCellClick = new eventListenerInterface(this,'handleCellClick');
    } 

//set when eventListenerInterface is instantiated
function eventListenerInterface(parent, callback_type) 
    {
        this.parent = parent;
        this.callback_type = callback_type;
    }

//run when event is triggered
eventListenerInterface.prototype.handleEvent(evt)
    {
        for ( var i = 0; i < this.parent._callbacks[this.callback_type].length; i++ ) {
            //run the callback method here, with this.parent as
            //this and evt as the first argument to the method
            this.parent._callbacks[this.callback_type][i].call(this.parent, evt);
        }
    }

ticketTable.prototype.render = function(element)
    {
       /* your code*/ 
        {
            /* your code*/

            //the way the event is attached looks the same
            cell1.addEventListener("click", this.handleCellClick, false);

            /* your code*/     
        }
        /* your code*/  
    }

//handleCellClick renamed to _handleCellClick
//and added evt attribute
ticketTable.prototype._handleCellClick = function(evt)
    {
        // this shouldn't work
        alert(this.innerHTML);
        // this however might work
        alert(evt.target.innerHTML);

        // this should work
        alert(this.tickets.length);
    }
Odpovězeno 24/04/2015 v 23:26
zdroj uživatelem

hlasů
0

Co takhle

...
    cell1.addEventListener("click", this.handleCellClick.bind(this));
...

ticketTable.prototype.handleCellClick = function(e)
    {
        alert(e.currentTarget.innerHTML);
        alert(this.tickets.length);
    }

e.currentTarget poukazuje na cíl , který je vázán na „událost click“ (na prvku, který zvednuté událost), zatímco

bind (this) zachovává hodnotu outerscope z thisuvnitř funkce click události.

Chcete-li získat přesné cílové klepnutí použít e.target místo.

Odpovězeno 18/09/2017 v 02:29
zdroj uživatelem

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more