Создание настраиваемого события JavaScript
Я хотел бы создать пользовательское событие в JavaScript.
У меня есть приложение WPF с WebBrowser внутри и HTML-страница с JavaScript.
Я работаю с принтером. Когда состояние принтера изменяется, оно запускает событие в .NET.
Затем я вызываю метод JavaScript OnPrinterStateChanged(state)
с помощью функции InvokeScript
элемента управления WebBrowser.
Проблема в том, что я должен реализовать метод OnPrinterStateChanged(state)
на моей веб-странице. Я не могу изменить имя метода или подписаться/отказаться от подписки на событие...
Я хотел бы переместить JavaScript-метод OnPrinterStateChanged(state)
в отдельный файл JavaScript.
Что я хочу:
- Подписаться/Отменить подписку на мероприятие на моей странице HTML и решить, что я хочу делать, когда событие запускается (например: "function ChangeState" )
- Когда событие .NET запускается, оно вызывает
OnPrinterStateChanged(state)
моего отдельного .js файла, затем запускается событие JavaScript и вызывается функция ChangeState
.
Я нашел некоторые решения, но мне не удалось заставить их работать... Каков самый простой способ сделать это?
Ответы
Ответ 1
Возможно, что-то вроде этого?
function OnPrinterStateChanged(state) {
var evt = new CustomEvent('printerstatechanged', { detail: state });
window.dispatchEvent(evt);
}
//Listen to your custom event
window.addEventListener('printerstatechanged', function (e) {
console.log('printer state changed', e.detail);
});
Альтернативным решением было бы использовать композицию функций, но тогда было бы трудно удалить конкретных слушателей.
function OnPrinterStateChanged(state) {}
function compose(fn1, fn2) {
return function () {
fn1.apply(this, arguments);
fn2.apply(this, arguments);
};
}
//Add a new listener
OnPrinterStateChanged = compose(OnPrinterStateChanged, function (state) {
console.log('listener 1');
});
//Add another one
OnPrinterStateChanged = compose(OnPrinterStateChanged, function (state) {
console.log('listener 2');
});
EDIT:
Здесь вы можете сделать это с помощью jQuery.
function OnPrinterStateChanged(state) {
var evt = $.Event('printerstatechanged');
evt.state = state;
$(window).trigger(evt);
}
//Listen to your custom event
$(window).on('printerstatechanged', function (e) {
console.log('printer state changed', e.state);
});
Ответ 2
Мне нравится использовать этот метод конструктора EventDispatcher
, который, используя фиктивный элемент, изолирует события, чтобы они не были запущены ни по какому-либо существующему элементу DOM, ни по window
или document
.
Я использую CustomEvent
а не createEvent
потому что это новый подход. Узнайте больше здесь.
Мне нравится оборачивать каждый нативный метод следующими именами:
on
, off
, trigger
function EventDispatcher(){
// Create a dummy DOM element
var dummy = document.createTextNode('');
// Create custom wrappers with nicer names
this.off = dummy.removeEventListener.bind(dummy);
this.on = dummy.addEventListener.bind(dummy);
this.trigger = function(eventName, data){
if( !eventName ) return;
var e = new CustomEvent(eventName, {"detail":data});
dummy.dispatchEvent(e);
}
}
////////////////////////////////////
// initialize the event dispatcher by creating an instance in an isolated way
var myEventDispatcher = new EventDispatcher();
////////////////////////////////////
// listen to a "foo" event
myEventDispatcher.on('foo', e =>{
console.log(e.type, e.detail);
});
////////////////////////////////////
// trigger a "foo" event with some data
myEventDispatcher.trigger('foo', 123);
Ответ 3
Хорошо, я нашел решение.
Мне пришлось изменить версию IE WebBrowser на Internet Explorer 11: http://weblog.west-wind.com/posts/2011/May/21/Web-Browser-Control-Specifying-the-IE-Version
И затем:
function OnPrinterStateChanged(state) {
var evt = document.createEvent("Event");
evt.state = state;
evt.initEvent("printerstatechanged", true, false);
window.dispatchEvent(evt);
}
window.addEventListener('printerstatechanged', function (e) {
// Do something
});
Ответ 4
Требование: ES6
let MyClass = (function () {
let __sym = Symbol('MyClass');
class MyClass {
constructor() {
this[__sym] = {};
}
on(event, callback) {
this[__sym][event] = { callback: callback }
}
getError() {
let event = this[__sym].error;
if (event && event.callback) {
event.callback('some parameter');
}
}
}
return MyClass;
}());
let myClass = new MyClass();
myClass.on('error', function (e) {
console.log('error:', e);
});
console.log('before getting error:');
myClass.getError();