อธิบายการจัดการเหตุการณ์ ExtJS 4


130

ฉันเพิ่งเริ่มเรียนรู้ ExtJS และมีปัญหาในการทำความเข้าใจวิธีจัดการกับเหตุการณ์ ฉันไม่มีประสบการณ์ ExtJS เวอร์ชันก่อนหน้าใด ๆ

จากการอ่านคู่มือคำแนะนำและหน้าเอกสารต่างๆฉันได้ทราบวิธีการใช้งานแล้ว แต่ยังไม่ชัดเจนว่ามันทำงานอย่างไร ฉันพบบทช่วยสอนมากมายสำหรับ ExtJS เวอร์ชันเก่า แต่ฉันไม่แน่ใจว่ามันใช้งานได้อย่างไรใน ExtJS 4

ฉันมองเฉพาะ "คำสุดท้าย" ในสิ่งต่างๆเช่น

  • ฟังก์ชันการจัดการเหตุการณ์ส่งผ่านอาร์กิวเมนต์อะไร มีชุดมาตรฐานของ args ที่มักจะผ่านไปหรือไม่?
  • จะกำหนดเหตุการณ์ที่กำหนดเองสำหรับส่วนประกอบที่เราเขียนได้อย่างไร? เราจะเริ่มเหตุการณ์ที่กำหนดเองเหล่านี้ได้อย่างไร
  • ค่าที่ส่งคืน (จริง / เท็จ) มีผลต่อฟองอากาศหรือไม่ ถ้าไม่เราจะควบคุมเหตุการณ์ที่เดือดปุด ๆ จากภายในหรือภายนอกตัวจัดการเหตุการณ์ได้อย่างไร
  • มีวิธีมาตรฐานในการลงทะเบียนผู้ฟังเหตุการณ์หรือไม่? (ฉันเจอสองวิธีที่แตกต่างกันจนถึงตอนนี้และฉันไม่แน่ใจว่าทำไมจึงใช้แต่ละวิธี)

ตัวอย่างเช่นคำถามนี้ทำให้ฉันเชื่อว่าตัวจัดการเหตุการณ์สามารถรับข้อโต้แย้งได้ไม่กี่ข้อ ฉันเคยเห็นบทช่วยสอนอื่น ๆ ที่มีข้อโต้แย้งเพียงสองข้อสำหรับตัวจัดการ เปลี่ยนแปลงอะไรบ้าง?


2
เพิ่งสังเกต ... นอกหัวข้อ?
jrharshath

12
88 โหวตขึ้นสำหรับคำถาม 155 คะแนนโหวตสำหรับคำตอบแรกและแอนดรูว์ผู้ยิ่งใหญ่และทรงพลังตัดสินใจว่าคำถามนี้ไม่อยู่ในหัวข้อ ทริปสุดสตรอง!
boatcoder

3
ฉันได้โหวตให้เปิดคำถามนี้อีกครั้งเนื่องจากคำตอบที่นี่คือเหมืองทองคำ ฉันได้แก้ไขคำถามเพื่อให้เหมาะกับสไตล์ Q และ A มากขึ้น
dbrin

1
โปรดเปิดคำถามนี้อีกครั้งเนื่องจากเป็นคำถามที่เป็นประโยชน์และเป็นคำถามที่แท้จริง สุ่มสี่สุ่มห้าเราจึงไม่สามารถปิดมันได้
Piyush Dholariya

2
นี่เป็นคำถามที่ใช้คำได้ดีและฉันไม่เห็นเหตุผลที่จะปิดคำถามนี้ เรียกว่าปิดหัวข้อนี้ไร้สาระ โหวตให้เปิดอีกครั้ง
Mike Fuchs

คำตอบ:


222

เริ่มต้นด้วยการอธิบายการจัดการเหตุการณ์ขององค์ประกอบ DOM

การจัดการเหตุการณ์โหนด DOM

ก่อนอื่นคุณไม่ต้องการทำงานกับโหนด DOM โดยตรง แต่คุณอาจต้องการใช้Ext.Elementอินเทอร์เฟซแทน เพื่อวัตถุประสงค์ในการกำหนดตัวจัดการเหตุการณ์Element.addListenerและElement.on(สิ่งเหล่านี้เทียบเท่า) ถูกสร้างขึ้น ตัวอย่างเช่นหากเรามี html:

<div id="test_node"></div>

และเราต้องการเพิ่มclickตัวจัดการเหตุการณ์
มาเรียกดูElement:

var el = Ext.get('test_node');

ตอนนี้มาตรวจสอบเอกสารสำหรับclickเหตุการณ์ ตัวจัดการอาจมีพารามิเตอร์สามตัว:

คลิก (Ext.EventObject e, HTMLElement t, Object eOpts)

เมื่อรู้สิ่งเหล่านี้แล้วเราสามารถกำหนดตัวจัดการได้:

//       event name      event handler
el.on(    'click'        , function(e, t, eOpts){
  // handling event here
});

การจัดการเหตุการณ์วิดเจ็ต

การจัดการเหตุการณ์วิดเจ็ตค่อนข้างคล้ายกับการจัดการเหตุการณ์โหนด DOM

ประการแรกการจัดการเหตุการณ์วิดเจ็ตเกิดขึ้นได้จากการใช้Ext.util.Observablemixin เพื่อที่จะจัดการกับเหตุการณ์ต่างๆได้อย่างถูกต้องวิดเจ็ตของคุณจะต้องExt.util.Observableเป็นมิกซ์อิน วิดเจ็ตในตัวทั้งหมด (เช่น Panel, Form, Tree, Grid, ... ) มีExt.util.Observableเป็น mixin โดยค่าเริ่มต้น

สำหรับวิดเจ็ตมีสองวิธีในการกำหนดตัวจัดการ อันแรก - ใช้กับ method (หรือaddListener) ยกตัวอย่างเช่นสร้างButtonวิดเจ็ตและกำหนดclickเหตุการณ์ให้ ก่อนอื่นคุณควรตรวจสอบเอกสารของเหตุการณ์เพื่อหาอาร์กิวเมนต์ของตัวจัดการ:

คลิก (Ext.button Button this, Event e, Object eOpts)

ตอนนี้มาใช้on:

var myButton = Ext.create('Ext.button.Button', {
  text: 'Test button'
});
myButton.on('click', function(btn, e, eOpts) {
  // event handling here
  console.log(btn, e, eOpts);
});

วิธีที่สองคือใช้การกำหนดค่าListenersของวิดเจ็ต:

var myButton = Ext.create('Ext.button.Button', {
  text: 'Test button',
  listeners : {
    click: function(btn, e, eOpts) {
      // event handling here
      console.log(btn, e, eOpts);
    }
  }
});

สังเกตว่าButtonวิดเจ็ตเป็นวิดเจ็ตชนิดพิเศษ เหตุการณ์การคลิกสามารถกำหนดให้กับวิดเจ็ตนี้ได้โดยใช้handlerconfig:

var myButton = Ext.create('Ext.button.Button', {
  text: 'Test button',
  handler : function(btn, e, eOpts) {
    // event handling here
    console.log(btn, e, eOpts);
  }
});

เหตุการณ์ที่กำหนดเองเริ่มทำงาน

ก่อนอื่นคุณต้องลงทะเบียนเหตุการณ์โดยใช้เมธอดaddEvents :

myButton.addEvents('myspecialevent1', 'myspecialevent2', 'myspecialevent3', /* ... */);

การใช้addEventsวิธีนี้เป็นทางเลือก ตามความคิดเห็นของวิธีนี้บอกว่าไม่จำเป็นต้องใช้วิธีนี้ แต่เป็นสถานที่สำหรับเอกสารเหตุการณ์

ในการเริ่มกิจกรรมของคุณให้ใช้วิธีfireEvent :

myButton.fireEvent('myspecialevent1', arg1, arg2, arg3, /* ... */);

arg1, arg2, arg3, /* ... */จะถูกส่งผ่านไปยังตัวจัดการ ตอนนี้เราจัดการกิจกรรมของคุณได้แล้ว:

myButton.on('myspecialevent1', function(arg1, arg2, arg3, /* ... */) {
  // event handling here
  console.log(arg1, arg2, arg3, /* ... */);
});

เป็นมูลค่าการกล่าวขวัญว่าสถานที่ที่ดีที่สุดสำหรับการแทรกการเรียกเมธอดaddEventsคือinitComponentวิธีการของวิดเจ็ตเมื่อคุณกำหนดวิดเจ็ตใหม่:

Ext.define('MyCustomButton', {
  extend: 'Ext.button.Button',
  // ... other configs,
  initComponent: function(){
    this.addEvents('myspecialevent1', 'myspecialevent2', 'myspecialevent3', /* ... */);
    // ...
    this.callParent(arguments);
  }
});
var myButton = Ext.create('MyCustomButton', { /* configs */ });

ป้องกันเหตุการณ์เดือด

เพื่อป้องกันไม่ให้เดือดปุด ๆ ที่คุณสามารถหรือการใช้งานreturn false Ext.EventObject.preventDefault()เพื่อป้องกันการใช้การกระทำเริ่มต้นของเบราว์เซอร์Ext.EventObject.stopPropagation()เพื่อที่จะป้องกันการใช้การดำเนินการเริ่มต้นของเบราว์เซอร์

ตัวอย่างเช่นกำหนดตัวจัดการเหตุการณ์คลิกให้กับปุ่มของเรา และหากไม่คลิกปุ่มซ้ายจะป้องกันการทำงานของเบราว์เซอร์เริ่มต้น:

myButton.on('click', function(btn, e){
  if (e.button !== 0)
    e.preventDefault();
});

3
นี่คือความโลภ แต่มีวิธีใดบ้างที่จะทำสิ่ง "addEvents" ผ่านการกำหนดค่าบางอย่าง :)
jrharshath

@jrharshath เท่าที่ฉันรู้โชคไม่ดีที่ไม่มีทางทำเช่นนั้นผ่าน config
Molecular Man

จะสร้าง -'myspecialevent1 'เหล่านี้ได้อย่างไรฉันเห็นว่าคุณได้แนบและจัดการ แต่เราจะสร้างสิ่งเหล่านี้ได้อย่างไร
heyNow

1
คำตอบที่ยอดเยี่ยม! ฉันยังใหม่กับ ExtJs และกำลังมองหาวิธีอ้างอิงองค์ประกอบใด ๆ ในเพจและใช้ตัวจัดการเหตุการณ์กับพวกเขาเช่นเดียวกับ jQuery คุณสอนฉันให้! ขอบคุณ!
Rutwick Gangurde

1
ข้อผิดพลาดเล็กน้อยในหัวข้อ "การป้องกันไม่ให้เกิดเหตุการณ์เดือด" stopPropagation ถูกใช้เพื่อป้องกันไม่ให้เหตุการณ์เป็นฟองและใช้ PreventDefault เพื่อป้องกันพฤติกรรม / การกระทำเริ่มต้น
MatRt

44

การเริ่มต้นเหตุการณ์ทั่วทั้งแอปพลิเคชัน

จะทำให้คอนโทรลเลอร์คุยกันได้อย่างไร ...

นอกเหนือจากคำตอบที่ยอดเยี่ยมข้างต้นแล้วฉันยังต้องการพูดถึงเหตุการณ์ในวงกว้างของแอปพลิเคชันซึ่งมีประโยชน์มากในการตั้งค่า MVC เพื่อให้สามารถสื่อสารระหว่างคอนโทรลเลอร์ได้ (extjs4.1)

สมมติว่าเรามีสถานีควบคุม (ตัวอย่าง Sencha MVC) พร้อมกล่องเลือก:

Ext.define('Pandora.controller.Station', {
    extend: 'Ext.app.Controller',
    ...

    init: function() {
        this.control({
            'stationslist': {
                selectionchange: this.onStationSelect
            },
            ...
        });
    },

    ...

    onStationSelect: function(selModel, selection) {
        this.application.fireEvent('stationstart', selection[0]);
    },    
   ...
});

เมื่อกล่องเลือกทริกเกอร์เหตุการณ์การเปลี่ยนแปลงฟังก์ชันonStationSelectจะเริ่มทำงาน

ภายในฟังก์ชั่นนั้นเราจะเห็น:

this.application.fireEvent('stationstart', selection[0]);

สิ่งนี้จะสร้างและเริ่มเหตุการณ์กว้าง ๆ ของแอปพลิเคชันที่เราสามารถฟังจากคอนโทรลเลอร์อื่น ๆ

ดังนั้นในคอนโทรลเลอร์อื่นตอนนี้เราสามารถรู้ได้แล้วว่าเมื่อใดที่กล่องเลือกสถานีมีการเปลี่ยนแปลง ซึ่งทำได้ผ่านการฟังthis.application.onดังนี้:

Ext.define('Pandora.controller.Song', {
    extend: 'Ext.app.Controller', 
    ...
    init: function() {
        this.control({
            'recentlyplayedscroller': {
                selectionchange: this.onSongSelect
            }
        });

        // Listen for an application wide event
        this.application.on({
            stationstart: this.onStationStart, 
                scope: this
        });
    },
    ....
    onStationStart: function(station) {
        console.info('I called to inform you that the Station controller select box just has been changed');
        console.info('Now what do you want to do next?');
    },
}

หากกล่องเลือกมีการเปลี่ยนแปลงตอนนี้เราจะเรียกใช้ฟังก์ชันonStationStartในคอนโทรลเลอร์Songด้วย ...

จากเอกสาร Sencha:

เหตุการณ์ของแอปพลิเคชันมีประโยชน์อย่างยิ่งสำหรับเหตุการณ์ที่มีตัวควบคุมจำนวนมาก แทนที่จะฟังเหตุการณ์มุมมองเดียวกันในแต่ละตัวควบคุมเหล่านี้คอนโทรลเลอร์เพียงตัวเดียวเท่านั้นที่ฟังเหตุการณ์มุมมองและเริ่มเหตุการณ์ทั่วทั้งแอปพลิเคชันที่ผู้อื่นสามารถฟังได้ นอกจากนี้ยังช่วยให้ผู้ควบคุมสามารถสื่อสารกันได้โดยไม่รู้เรื่องหรือขึ้นอยู่กับการดำรงอยู่ของกันและกัน

ในกรณีของฉัน: คลิกที่โหนดต้นไม้เพื่ออัปเดตข้อมูลในแผงตาราง

อัปเดต 2016 ขอบคุณ @ gm2008 จากความคิดเห็นด้านล่าง:

ในแง่ของการเริ่มต้นเหตุการณ์ที่กำหนดเองทั่วทั้งแอปพลิเคชันตอนนี้มีวิธีการใหม่หลังจากExtJS V5.1Ext.GlobalEventsมีการเผยแพร่ซึ่งมีการใช้

เมื่อคุณเริ่มกิจกรรมคุณสามารถโทร: Ext.GlobalEvents.fireEvent('custom_event');

เมื่อคุณลงทะเบียนตัวจัดการเหตุการณ์คุณโทร: Ext.GlobalEvents.on('custom_event', function(arguments){/* handler codes*/}, scope);

วิธีนี้ไม่ จำกัด เฉพาะตัวควบคุม ส่วนประกอบใด ๆ สามารถจัดการเหตุการณ์ที่กำหนดเองได้โดยการวางออบเจ็กต์คอมโพเนนต์เป็นขอบเขตพารามิเตอร์อินพุต

พบใน Sencha Docs: MVC ตอนที่ 2


1
ในแง่ของการเริ่มต้นเหตุการณ์ที่กำหนดเองทั่วทั้งแอปพลิเคชันขณะนี้มีวิธีการใหม่หลังจากเผยแพร่ ExtJS V5.1 ซึ่งใช้ Ext.GlobalEvents เมื่อคุณยิงเหตุการณ์ที่คุณเรียกExt.GlobalEvents.fireEvent('custom_event');เมื่อคุณลงทะเบียนจัดการของเหตุการณ์ที่คุณโทรExt.GlobalEvents.on('custom_event', function(arguments){/* handler codes*/}, scope};นี่คือไวโอลิน วิธีนี้ไม่ จำกัด เฉพาะตัวควบคุม ส่วนประกอบใด ๆ scopeที่สามารถจัดการกับเหตุการณ์ที่กำหนดเองผ่านการวางวัตถุส่วนประกอบเป็นพารามิเตอร์การป้อนข้อมูล คำถามควรจะเปิดใหม่
gm2008

15

อีกหนึ่งเคล็ดลับสำหรับผู้ฟังเหตุการณ์คอนโทรลเลอร์

คุณสามารถใช้สัญลักษณ์แทนเพื่อดูเหตุการณ์จากส่วนประกอบใดก็ได้:

this.control({
   '*':{ 
       myCustomEvent: this.doSomething
   }
});

12

เพียงแค่ต้องการเพิ่มเพนนีสองสามคำตอบที่ยอดเยี่ยมข้างต้น: หากคุณกำลังทำงานกับ Extjs 4.1 ก่อนหน้าและไม่มีเหตุการณ์ที่กว้างของแอปพลิเคชัน แต่ต้องการมันฉันใช้เทคนิคง่ายๆที่อาจช่วยได้: สร้าง ออบเจ็กต์อย่างง่ายที่ขยาย Observable และกำหนดเหตุการณ์กว้าง ๆ ของแอพที่คุณอาจต้องการ จากนั้นคุณสามารถเริ่มต้นเหตุการณ์เหล่านั้นได้จากทุกที่ในแอปของคุณรวมถึงองค์ประกอบ html dom จริงและฟังจากองค์ประกอบใดก็ได้โดยการถ่ายทอดองค์ประกอบที่ต้องการจากส่วนประกอบนั้น

Ext.define('Lib.MessageBus', {
    extend: 'Ext.util.Observable',

    constructor: function() {
        this.addEvents(
            /*
             * describe the event
             */
                  "eventname"

            );
        this.callParent(arguments);
    }
});

จากนั้นคุณสามารถทำได้จากส่วนประกอบอื่น ๆ :

 this.relayEvents(MesageBus, ['event1', 'event2'])

และยิงพวกมันจากส่วนประกอบหรือองค์ประกอบ Dom:

 MessageBus.fireEvent('event1', somearg);

 <input type="button onclick="MessageBus.fireEvent('event2', 'somearg')">

สำหรับข้อมูลนี้ได้เลิกใช้งาน this.addEvents แล้วโดยเริ่มจาก EXT JS 5.0 ดังนั้นจึงไม่จำเป็นต้องเพิ่มเหตุการณ์ในตอนนี้
Ajay Sharma

11

มีอีกสองสิ่งที่ฉันพบว่าเป็นประโยชน์ที่ควรทราบแม้ว่าจะไม่ได้เป็นส่วนหนึ่งของคำถามก็ตาม

คุณสามารถใช้relayEventsวิธีบอกให้คอมโพเนนต์ฟังเหตุการณ์บางอย่างของคอมโพเนนต์อื่นแล้วเริ่มการทำงานอีกครั้งราวกับว่าเกิดจากคอมโพเนนต์แรก เอกสาร API ให้ตัวอย่างของกริดที่ส่งต่อร้านค้าloadเหตุการณ์มีประโยชน์มากเมื่อเขียนส่วนประกอบแบบกำหนดเองที่ห่อหุ้มส่วนประกอบย่อยหลาย ๆ

ในทางกลับกันเช่นการส่งผ่านเหตุการณ์ที่ได้รับจากส่วนประกอบที่ห่อหุ้มmycmpไปยังส่วนประกอบย่อยหนึ่งในsubcmpนั้นสามารถทำได้เช่นนี้

mycmp.on('show' function (mycmp, eOpts)
{
   mycmp.subcmp.fireEvent('show', mycmp.subcmp, eOpts);
});
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.