Недавно я столкнулся с проблемой в пользовательском интерфейсе приложения, когда дочерним представлениям удалялись прослушиватели событий касания / мыши, когда другое представление было помещено в стек в компоненте ViewNavigator .
Если вы еще этого не видели, интерфейс приложения представляет собой набор повторно используемых компонентов «контейнера приложений» для создания нативных мобильных приложений для приложений, созданных с помощью веб-технологий. Он все еще находится на очень ранней стадии разработки, и я активно работаю над этим… поэтому, пожалуйста, дайте мне знать, если у вас возникнут какие-либо вопросы или предложения .
Я просмотрел весь код своего приложения и фреймворка, но никак не мог понять, почему / где были удалены прослушиватели событий. То, что мне нужно было сделать, было просто, выяснить, где вызывается «removeEventListener». «RemoveEventListener» — это встроенная функция, поэтому вы не можете установить точку останова, чтобы увидеть каждый экземпляр, где она вызывается, верно?
На самом деле, вы можете, но вы должны взглянуть на проблему немного по-другому …
Однако вы не можете установить точку останова для нативной функции, поскольку JavaScript использует прототипное наследование, вы можете изменить прототип объекта, чтобы изменить его поведение и переопределить нативные функции. Поскольку вы можете изменить прототип объекта, изменения в прототипе этого объекта будут применены ко всем экземплярам этого типа объекта. Таким образом, вы можете добавить некоторый отладочный код, чтобы переопределить поведение функции «removeEventListener» HTMLElement.
Сначала создайте копию исходной функции removeEventListener для HTMLElement.prototype:
HTMLElement.prototype.originalRemoveEventListener = HTMLElement.prototype.removeEventListener
Затем переопределите исходную функцию removeEventListener, добавьте оператор console.log (), а затем вызовите оригинальную функцию removeEventListener, копию которой вы только что сделали:
HTMLElement.prototype.removeEventListener = function(type, listener, useCapture) { console.log('remove: ' + type); this.originalRemoveEventListener(type, listener, useCapture); };
Теперь каждый раз, когда вызывается функция removeEventListener HTMLElement, вы получите оператор console.log (). Вы не только получаете отладку консоли, но и можете установить точку останова внутри новой переопределенной функции removeEventListener. Используя точку останова, вы можете использовать инструменты разработчика для просмотра стека вызовов и отслеживания того, где вызывается функция removeEventListener. Таким образом, вы можете отследить корень вашей проблемы. Я использую инструменты разработчика Chrome , но аналогичные инструменты также доступны в Safari , FireFox , IE и Opera .
Используя стек вызовов, я смог отследить, что я случайно вызвал функцию remove () jQuery для элемента DOM представления вместо функции detach () jQuery . Как remove (), так и detach () удаляют ваши элементы из DOM страницы , однако, remove () также избавляет от любых прослушивателей событий, чтобы предотвратить утечки памяти. Когда я изменил однострочный код с remove () на detach (), все возобновилось, как и ожидалось. Затем я удалил код отладки.
Вот полный код в одном фрагменте для переопределения removeEventListener:
HTMLElement.prototype.originalRemoveEventListener = HTMLElement.prototype.removeEventListener; HTMLElement.prototype.removeEventListener = function(type, listener, useCapture) { console.log('remove: ' + type); this.originalRemoveEventListener(type, listener, useCapture); };
Наследование прототипов дает вам возможность изменять поведение объектов во время выполнения, и оно может быть невероятно мощным при создании ваших приложений HTML / JS.