programing

사용자 정의 개체의 addEventListener

javaba 2021. 1. 14. 23:04
반응형

사용자 정의 개체의 addEventListener


여러 메서드가있는 개체를 만들었습니다. 이러한 메서드 중 일부는 비동기식이므로 메서드가 완료 될 때 작업을 수행 할 수 있도록 이벤트를 사용하고 싶습니다. 이를 위해 객체에 addEventListener를 추가하려고했습니다.

jsfiddle

var iSubmit = {
    addEventListener: document.addEventListener || document.attachEvent,
    dispatchEvent: document.dispatchEvent,
    fireEvent: document.fireEvent,   


    //the method below is added for completeness, but is not causing the problem.

    test: function(memo) {
        var name = "test";
        var event;
        if (document.createEvent) {
            event = document.createEvent("HTMLEvents");
            event.initEvent(name, true, true);
        } else {
            event = document.createEventObject();
            event.eventType = name;
        }
        event.eventName = name;
        event.memo = memo || { };

        if (document.createEvent) {
            try {
                document.dispatchEvent(event);
            } catch (ex) {
                iAlert.debug(ex, 'iPushError');
            }
        } else {
            document.fireEvent("on" + event.eventType, event);
        }
    }
}

iSubmit.addEventListener("test", function(e) { console.log(e); }, false);


//This call is added to have a complete test. The errors are already triggered with the line before this one.

iSubmit.test();

그러면 오류가 반환됩니다. Failed to add eventlisterens: TypeError: 'addEventListener' called on an object that does not implement interface EventTarget."

이제이 코드는 phonegap 앱에서 사용되며 내가 할 때 android / ios에서 작동합니다. 그러나 테스트하는 동안 적어도 하나의 브라우저에서 작동하도록 할 수 있다면 좋을 것입니다.

PS> 버블 링을 활성화 한 다음 문서 루트를들을 수 있다는 것을 알고 있지만 각 개체가 자체적으로 작동 할 수있는 약간의 OOP를 갖고 싶습니다.


addEventListener특정 이벤트 관련 인터페이스를 구현하는 DOM 요소를위한 것입니다. 순수 JavaScript 개체에 대한 이벤트 시스템을 원한다면 사용자 지정 이벤트 시스템을 찾고 있습니다. 예는 Backbone.EventsBackbone.js에 있습니다. 기본 아이디어는 등록 된 콜백을 추적하기 위해 객체를 해시로 사용하는 것입니다.

개인적으로 나는 이것을 사용합니다 : emitter .

매우 간단하고 우아한 솔루션 입니다. on(), off()emit(). 를 사용하여 새 인스턴스를 만들 new Emitter()거나를 사용 Emitter(obj)하여 기존 개체에 이벤트 기능을 혼합 할 수 있습니다 . 이 라이브러리는 CommonJS 모듈 시스템과 함께 사용하도록 작성되었지만 module.exports = ...을 제거하여 다른 곳에서 사용할 수 있습니다 .


실제 이벤트 기능 (버블 링, stopPropagation 등)이 필요하지 않은 경우 자체 이벤트를 구현할 수 있습니다. addEventListener는 DOM의 API 일 뿐이므로 DOM 외부의 자체 개체에는 실제로 필요하지 않습니다. 객체 주위에 이벤트 패턴을 생성하려는 경우 추가 브라우저 API가 필요하지 않고 이전 버전과 매우 호환되어야하는 좋은 방법이 있습니다.

디스패치 메서드가 호출 될 때 여러 이벤트를 트리거하려는 객체가 있다고 가정 해 보겠습니다.

var OurDispatcher, dispatcher;

OurDispatcher = (function() {
  function OurDispatcher() {
    this.dispatchHandlers = [];
  }

  OurDispatcher.prototype.on = function(eventName, handler) {
    switch (eventName) {
      case "dispatch":
        return this.dispatchHandlers.push(handler);
      case "somethingElse":
        return alert('write something for this event :)');
    }
  };

  OurDispatcher.prototype.dispatch = function() {
    var handler, i, len, ref;
    ref = this.dispatchHandlers;
    for (i = 0, len = ref.length; i < len; i++) {
      handler = ref[i];
      setTimeout(handler, 0);
    }
  };

  return OurDispatcher;

})();

dispatcher = new OurDispatcher();

dispatcher.on("dispatch", function() {
  return document.body.innerHTML += "DISPATCHED</br>";
});

dispatcher.on("dispatch", function() {
  return document.body.innerHTML += "DISPATCHED AGAIN</br>";
});

dispatcher.dispatch();

대부분의 경우 그보다 더 복잡 할 필요는 없습니다. 이렇게하면 이벤트를 적절히 제어 할 수 있으며 모든 것이 널리 지원되므로 이전 버전과의 호환성이나 외부 라이브러리에 대해 걱정할 필요가 없습니다. 기술적으로는 setTimeout 없이도 할 수 있고 API없이 콜백을 처리 할 수도 있습니다. stopPropagation ()과 같은 다른 것은 스스로 처리해야합니다.

https://jsfiddle.net/ozsywxer/

물론 CustomEvent에 대한 polyfill이 있지만 고급 이벤트 기능이 필요하지 않은 경우 자체 이벤트 시스템을 "클래스"로 래핑하고 다른 클래스 / 함수를 확장하는 것을 선호합니다.

다음은 JavaScript가 파생 된 CoffeeScript 버전입니다. https://jsfiddle.net/vmkkbbxq/1/

^^ 조금 이해하기 쉽습니다.


자바 스크립트 객체를 듣고 싶다면 세 가지 방법이 있습니다.

sup / pub 패턴 정보 :

이벤트를 게시해야합니다.

기본 구현 정보 :

  • Object get/set operators이벤트 추가, 제거, 변경, 가져 오기를 듣기에 충분합니다. 운영자는 좋은 지원을 받고 있습니다 . IE8-에서만 문제가 발생합니다. 그러나 IE8에서 get / set을 사용하려면 Object.definePropertyDOM 개체를 사용하거나 Object.defineProperty sham을 사용하십시오 .
  • Object.prototype.watch좋은 ES5 polyfill이 있습니다.
  • Proxy API ES Harmony 지원이 필요합니다.

Object.observe 예제

var o = {};
Object.observe(o, function (changes) {
  changes.forEach(function (change) {
    // change.object contains changed object version
    console.log('property:', change.name, 'type:', change.type);
  });
});
o.x = 1     // property: x type: add
o.x = 2     // property: x type: update
delete o.x  // property: x type: delete

두 가지 문제가 있습니다.

첫째, iSubmit.addEventListener()메서드는 실제로 EventTargetDOM 인터페이스 의 메서드입니다 .

이들은 DOM 요소에서만 사용하도록 의도되었습니다. iSubmit객체에 메서드로 추가 하면 EventTarget. 이것이 Chrome에서 Uncaught TypeError: Illegal invocationJavaScript 오류가 발생 하는 이유 입니다.

첫 번째 문제는 중요하지만 EventTarget#addEventListener()이벤트가에 추가 iSubmit되지만에서 전달 되기 때문에 코드를 사용할 수 있다면 작동하지 않습니다 document. 일반적으로, 같은 객체의 메소드는 이벤트 리스너를 부착하고 (당신이 인 버블 링 이벤트를 사용하지 않는 이벤트를 파견 할 때 사용할 필요가 다른 이야기 - : 버블 링, 자바 스크립트 또는 DOM 관련 이벤트에 제한되지 않는다 참고 예 : ).

자신의 개체와 함께 사용자 지정 이벤트를 사용하는 것은 매우 정상입니다. 으로 에반 유 언급 ,이에 대한 라이브러리가 있습니다. 다음은 몇 가지입니다.

나는 js-signals그것을 꽤 많이 사용 하고 좋아합니다. 나는 한번도 사용 해본 적이 Wolfy87/EventEmitter없지만 멋지게 보입니다.

다음을 사용한 경우 예제는 다음과 같습니다. js-signals

jsFiddle

var iSubmit = {
    finished: new signals.Signal(),
    test: function test(memo) {
        this.finished.dispatch(memo || {});
    }
};

iSubmit.finished.add(function(data) {
    console.log('finished:', data);
});

iSubmit.test('this is the finished data');


// alternatively
iSubmit.finished.dispatch('this is dispatched directly from the signal');

Node.js 환경에 있다면 Node의 EventEmitter 클래스를 사용할 수 있습니다 .

CustomObject.js

const EventEmitter = require('events');

class CustomObject extends EventEmitter {
  constructor() {
    super();
  }

  doSomething() {
    const event = {message: 'Hello World!'};
    this.emit('myEventName', event);
  }
}

module.exports = CustomObject;

용법:

const CustomObject = require('./CustomObject');

// 1. Create a new instance
const myObject = new CustomObject();

// 2. Subscribe to events with ID "myEventName"
myObject.on('myEventName', function(event) {
  console.log('Received event', event);
});

// 3. Trigger the event emitter
myObject.doSomething();

Node.js 환경 외부에서 Node의 EventEmitter를 사용하려면 webpack (바람직하게는 v2.2 이상)을 CustomClass사용하여 EventEmitter polyfill (webpack에서 빌드)과 함께 번들을 얻을 수 있습니다.

작동 방식은 다음과 같습니다 (를 사용하여 전역 적으로 webpack을 설치했다고 가정 npm install -g webpack).

  1. 운영 webpack CustomObject.js bundle.js --output-library=CustomObject
  2. bundle.jsHTML 페이지에 포함 (노출됨 window.CustomObject)
  3. 3 단계가 없습니다!

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Title</title>
    <script src="bundle.js"></script>
  </head>
  <body>
    <script>
      // 1. Create a new instance
      const myObject = new window.CustomObject();

      // 2. Subscribe to events with ID "myEventName"
      myObject.on('myEventName', function(event) {
        console.log('Received event', event);
      });

      // 3. Trigger the event emitter
      myObject.doSomething();
    </script>
  </body>
</html>

추측 일뿐입니다. 나는 그것을 직접 시도하지 않았습니다. 그러나 더미 요소를 만들고 더미 요소에서 이벤트를 발생 / 수신 할 수 있습니다. 또한 도서관없이가는 것을 선호합니다.

function myObject(){
    //create "dummy" element
    var dummy = document.createElement('dummy');
    //method for listening for events
    this.on = function(event, func){dummy.addEventListener(event, func);};
    //you need a way to fire events
    this.fireEvent = function(event, obj){
      dummy.dispatchEvent(new CustomEvent(event, {detail: obj}));
    }
}
//now you can use the methods in the object constructor
var obj = new myObject();
obj.on("custom", function(e){console.log(e.detail.result)});
obj.fireEvent("custom", {result: "hello world!!!"});

이 도움말에서는 맞춤 이벤트 생성에 대해 설명합니다. http://www.sitepoint.com/javascript-custom-events/

다음은 예입니다.

이벤트 만들기-

var event = new CustomEvent(
    "newMessage",
    {
        detail: {
            message: "Hello World!",
            time: new Date(),
        },
        bubbles: true,
        cancelable: true
    }
);

이벤트를 무언가에 할당-

document.getElementById("msgbox").dispatchEvent(event);

이벤트 구독-

document.addEventListener("newMessage", newMessageHandler, false);

사용법 : jsfiddle

이것은 순진한 접근 방식이지만 일부 응용 프로그램에서는 작동 할 수 있습니다.

CustomEventTarget.prototype = {

    'constructor': CustomEventTarget,

    on:   function( ev, el ) { this.eventTarget.addEventListener( ev, el ) },
    off:  function( ev, el ) { this.eventTarget.removeEventListener( ev, el ) },
    emit: function( ev ) { this.eventTarget.dispatchEvent( ev ) }

}

function CustomEventTarget() { this.eventTarget = new EventTarget }

Object $ Deferred와 promise를 사용할 수 있다고 생각합니다. 다음과 같이 할 수 있습니다.

스택 형 : 애플리케이션의 모든 위치에있는 여러 핸들러를 동일한 promise 이벤트에 바인딩합니다.

  var request = $.ajax(url);
  request.done(function () {
  console.log('Request completed');
});

// 애플리케이션의 다른 위치

   request.done(function (retrievedData) {
     $('#contentPlaceholder').html(retrievedData);
   });

병렬 작업 : 상호 완료를 경고하는 약속을 반환하도록 여러 약속을 요청합니다.

$.when(taskOne, taskTwo).done(function () {
  console.log('taskOne and taskTwo are finished');
});

순차적 작업 : 작업을 순차적으로 실행합니다.

 var step1, step2, url;

 url = 'http://fiddle.jshell.net';

 step1 = $.ajax(url);

 step2 = step1.then(
   function (data) {
       var def = new $.Deferred();

       setTimeout(function () {
           console.log('Request completed');
           def.resolve();
       },2000);

     return def.promise();

 },
   function (err) {
       console.log('Step1 failed: Ajax request');
   }
 );
 step2.done(function () {
     console.log('Sequence completed')
     setTimeout("console.log('end')",1000);
 });

출처 : http://blog.mediumequalsmessage.com/promise-deferred-objects-in-javascript-pt2-practical-use


다음은 브라우저에서 Node.js 스타일 구문으로이를 수행하는 방법입니다.

Events클래스 :

  • 이벤트 키와 관련된 해시에 콜백을 저장합니다.
  • 제공된 매개 변수로 콜백을 트리거합니다.

사용자 정의 클래스에 동작을 추가하려면 Events 객체를 확장하면됩니다 (아래 예제).

class Events {
  constructor () {
    this._callbacks = {}
  }

  on (key, callback) {
    // create an empty array for the event key
    if (this._callbacks[key] === undefined) { this._callbacks[key] = [] }
    // save the callback in the array for the event key
    this._callbacks[key].push(callback)
  }

  emit (key, ...params) {
    // if the key exists
    if (this._callbacks[key] !== undefined) {
      // iterate through the callbacks for the event key
      for (let i=0; i<this._callbacks[key].length; i++) {
        // trigger the callbacks with all provided params
        this._callbacks[key][i](...params)
      }
    }
  }
}


// EXAMPLE USAGE

class Thing extends Events {
  constructor () {
    super()
    setInterval(() => {
      this.emit('hello', 'world')
    }, 1000)
  }
}

const thing = new Thing()

thing.on('hello', (data) => {
  console.log(`hello ${data}`)
})

다음은이 코드가있는 github 요점 링크입니다. https://gist.github.com/alextaujenis/0dc81cf4d56513657f685a22bf74893d


작동하는 쉬운 대답을 찾고있는 사람을위한 것입니다. 나는 대부분의 브라우저가 그것을 지원하지 않는다는 것을 알기 위해이 문서를 방문 했다. 하지만 페이지 하단에 기본적으로 Object.watch () 및 Object.unwatch ()가 수행했을 작업을 수행 이 GitHub 페이지 가 있으며 저에게 적합합니다!

변경 사항을 확인하는 방법은 다음과 같습니다.

/*
 * object.watch polyfill
 *
 * 2012-04-03
 *
 * By Eli Grey, http://eligrey.com
 * Public Domain.
 * NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
 * https://gist.github.com/eligrey/384583
 */

// object.watch
if (!Object.prototype.watch) {
    Object.defineProperty(Object.prototype, "watch", {
          enumerable: false
        , configurable: true
        , writable: false
        , value: function (prop, handler) {
            var
              oldval = this[prop]
            , newval = oldval
            , getter = function () {
                return newval;
            }
            , setter = function (val) {
                oldval = newval;
                return newval = handler.call(this, prop, oldval, val);
            }
            ;

            if (delete this[prop]) { // can't watch constants
                Object.defineProperty(this, prop, {
                      get: getter
                    , set: setter
                    , enumerable: true
                    , configurable: true
                });
            }
        }
    });
}

// object.unwatch
if (!Object.prototype.unwatch) {
    Object.defineProperty(Object.prototype, "unwatch", {
          enumerable: false
        , configurable: true
        , writable: false
        , value: function (prop) {
            var val = this[prop];
            delete this[prop]; // remove accessors
            this[prop] = val;
        }
    });
}

그리고 이것은 당신의 코드 여야합니다.

var object = {
    value: null,
    changeValue: function(newValue) {
        this.value = newValue;
    },
    onChange: function(callback) {
        this.watch('value', function(obj, oldVal, newVal) {
            // obj will return the object that received a change
            // oldVal is the old value from the object
            // newVal is the new value from the object

            callback();
            console.log("Object "+obj+"'s value got updated from '"+oldValue+"' to '"+newValue+"'");
            // object.changeValue("hello world");
            // returns "Object object.value's value got updated from 'null' to 'hello world'";

            // and if you want the function to stop checking for
            // changes you can always unwatch it with:
            this.unwatch('value');

            // you can retrieve information such as old value, new value
            // and the object with the .watch() method, learn more here:
            // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/watch
        })
    }
};

또는 짧게 :

var object = { user: null };

// add a watch to 'user' value from object
object.watch('user', function() {
    // object user value changed
});

참조 URL : https://stackoverflow.com/questions/20835768/addeventlistener-on-custom-object

반응형