Component Focus & Blur
Здравствуйте!
Почему если вызвать метод component.focus() не генерируется событие focus у этого компонента? Или как пользоваться этими событиями и методами компонент: Focus & Blur? |
странно, конечно, но в документации написано, что вызов focus() приводит к генерации события tofront.
http://docs.sencha.com/extjs/5.1/5.1...t-method-focus А пользоваться так. Нужно в определении компонента написать свою реализацию шабонного метода postFocus или postBlur: /** * Template method to do any post-focus processing. * @protected * @param {Ext.event.Event} e The event object */ postFocus: Ext.emptyFn, http://docs.sencha.com/extjs/5.1/5.1...thod-postFocus Хотя лично у меня нет опыта работы с postFocus. Напишите, помогло ли это решение. |
Странно то, что события tofront тоже вроде как нет. По крайней мере по документации.
Писать методы post* страннно как-то... Я думал как использовать: Если я выделил объект на экране, то он в фокусе. Если я выделил какой другой объект и вызвал у него метод focus, то предыдущий объект тут же теряет фокус. Это удобно тем, что мне не нужно специально искать какой же объект сейчас в фокусе, снимать с него фокус и ставить фокус на объект, который сейчас пытаемся выделить. Я думал что такая стандартная функция уже реализована... Похоже придется дописать эту функцию... для всех компонент. Надеюсь без override. |
Попробовал эту штуку
To activate the FocusManager, simply call Ext.FocusManager.enable();. In turn, you may deactivate the FocusManager by subsequently calling Ext.FocusManager.disable();. The FocusManager is disabled by default. http://docs.sencha.com/extjs/5.1/5.1...-method-enable Но к сожалению на строке Ext.FocusManager.enable(); выдает ошибку. В чем там проблема пока не ясна, уж больно велик стек)))) |
Нашел способ вставки команды. Если так записать, то ошибки уже нету:
Ext.onReady(function() { Ext.FocusManager.enable(); ... Но к сожалению это ничего не дало. События focus|blur не появляются. |
Нашел опцию
http://docs.sencha.com/extjs/5.1/5.1...erty-focusable Поставил в своих компонентах равной true. И снова не работает... Что еще нужно сделать, чтобы этот механизм троклятый заработал? |
Вот пример https://fiddle.sencha.com/#fiddle/lgf
console.clear(); Ext.FocusManager.enable(true); Ext.define("MyComponent", { extend: "Ext.Component", focusable: true }); var comp = Ext.create("MyComponent", { renderTo: Ext.getBody(), html: "Тестовый компонент" }); comp.on("focus", function() { console.log("FOCUS"); }); comp.on("blur", function() { console.log("BLUR"); }); comp.focus(); comp.blur(); Пока это дело не работает. Может из-за того, что элементом компонента является DIV? |
Да, точно. Нужно ещё писать focusable.
Ext.application({ name : 'Fiddle', launch : function() { Ext.define("MyComponent", { extend: "Ext.Component", focusable: true, onFocus: function() { alert(1); this.callParent(arguments); }, postFocus: function() { alert(2); } }); var comp = Ext.create("MyComponent", { renderTo: Ext.getBody(), html: "Тестовый компонент" }); comp.focus(); } }); фидл |
1) Не работает. Алерты не всплывают. У вас этот пример что, работающий?
2) И самого главного нет - генерации событий focus|blur! |
Так... я подставил вместо DIV тег INPUT и все заработало. Оказывается целевой элемент должен поддерживать focus/blur. DIV не может быть фокусируемым, а вот INPUT может. Теперь ясно в чем проблема... Правда не ясно что делать, если у меня компонент допустим окно. Оно ведь на DIV-ах построено же... Есть ли какой-нибудь безобидный тег, поддерживаемый focus/blur?
|
Нашел способ как обойти этот нюанс. Правда способ не хороший на вид. Ибо в дереве DOM болтается лишний input (который приходится скрывать, причем скрывать нехорошим способом, ибо если его скрыть нормальным способом, то механизм не работает).
Вот код: https://fiddle.sencha.com/#fiddle/lgr console.clear(); Ext.FocusManager.enable(true); Ext.define("MyComponent", { extend: "Ext.Component", focusable: true, focusEl: null, privates: { getFocusEl: function() { return this.focusEl; }, }, initFocusable: function() { this.focusEl = Ext.create("Ext.Element", document.createElement("input")); this.focusEl.appendTo(Ext.getBody()); this.focusEl.applyStyles({ position: "absolute", top: "-5000px", left: "-5000px" }); } }); var comp = Ext.create("MyComponent", { renderTo: Ext.getBody(), html: "Тестовый компонент" }); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - comp.on("focus", function() { console.log("FOCUS"); }); comp.on("blur", function() { console.log("BLUR"); }); comp.focus(); comp.blur(); |
Теперь вопрос, как сделать фокусируемый компонент для случая, когда DOM-элемент компонента не является фокусируемый и при этом не использовать "грязные" способы, подобные тем, что я использовал выше? Например для окошек, которые построены на DIV-ах.
|
Ура, нашел способ без грязных методов.
Вот код: https://fiddle.sencha.com/#fiddle/lgs console.clear(); Ext.FocusManager.enable(true); Ext.define("MyComponent", { extend: "Ext.Component", focusable: true, initFocusable: function() { var me = this; me.on("render", function() { Ext.override(this.getEl(), { focus: function() { this.callParent(arguments); me.onFocus(); }, blur: function() { this.callParent(arguments); me.onBlur(); } }); }); } }); var comp = Ext.create("MyComponent", { renderTo: Ext.getBody(), html: "Тестовый компонент" }); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - comp.on("focus", function() { console.log("FOCUS"); }); comp.on("blur", function() { console.log("BLUR"); }); comp.focus(); comp.blur(); Здесь я внедрил в элемент компонента недостающий функционал, а именно вызовы методов me.onFocus() и me.onBlur() и все заработало без всяких левых тегов типа инпута. Остался последний штрих - оформить этот код в виде миксина, чтобы можно было одной строчкой его внедрять в любой компонент. |
Проблема решена полностью, чисто!
Миксин писать не надо. Итак, чтобы компонент сделать фокусируемый нужно добавить в него всего лишь две строчки. Вот код компонента с этими двумя строчками: Ext.define("MyComponent", { extend: "Ext.Component", focusable: true, tabIndex: 0, // без этой строчки не работает механизм фокусировки }); Полдня блин убил чтобы выяснить, что обязательно нужно прописать tabIndex: 0! |
Почти правильно, но не совсем. Устанавливая tabIndex: 0 вы тем самым не только делаете компонент фокусируемым, но ещё и добавляете его в tab order. Обычно это как раз то, что и нужно, но не всегда. Чтобы сделать компонент просто фокусируемым, но без возможности клавиатурной навигации, присвойте ему негативный tabIndex (обычно -1).
Более подробное объяснение: компоненты в Ext JS имеют отображение в DOM. Есть такое понятие: главный элемент; этот элемент содержит в себе всю остальную разметку компонента. Конфигурация главного элемента задаётся свойством autoEl компонента, и по умолчанию тегом является DIV. Возвращаясь к фокусировке, DIV элементы по умолчанию не являются фокусируемыми, в отличие от INPUT. Чтобы сделать DIV фокусируемым, нужно присвоить ему атрибут tabindex; фреймворк делает это за вас, если вы укажете в свойствах компонента поле tabIndex. Свойство focusable отвечает за реакцию компонента на события фокусировки и на определённые внутренние механизмы, но не влияет на отображение в DOM. Именно поэтому вам и нужно было установить оба поля: focusable: true и tabIndex: 0, чтобы ваш компонент стал фокусируемым. Ну и на добавку, учитывайте что в IE DOM события focus/blur/focusin/focusout являются асинхронными. ;) |
Цитата:
Что значит асинхронные события? Неопределенность последовательности их появления? |
Ну как откуда узнал, на практике изучил. ;) Когда два года назад на меня повесили разработку Accessibility, фреймворк пришлось изрядно отрефакторить, чтобы управление фокусом и клавиатурная навигация вообще заработали.
Про "принципы работы" часто люди спрашивают, но сам вопрос мне не очень понятен. Фреймворк сделан для того, чтобы вы могли его использовать и получать (более/менее) одинаково работающие приложения во всех браузерах, которые мы поддерживаем. Есть API документация, есть tutorials, есть курсы. Изучайте и используйте. ;) Зачем вам знание каких-то глубинных вещей? Обычно оно ничем не помогает, только грузит ненужными деталями. Хотя мне и не жалко никогда, так что если есть конкретные вопросы, то спрашивайте. ;) Асинхронные это и значит, что асинхронные: события выстреливают не в том же цикле исполнения, что и собственно момент фокусирования. Возьмём вот такой код, для примера: Код:
Ext.onReady(function() { Код:
pre Код:
pre |
спасибо!
бум юзать Правда в своем проекте отменил фокусировку. Оказывается мне нужна была selectable, чего в Ext JS нету. Пришлось самому писать миксин чтобы во всех компонентах появилась возможность выделения А так я эту фичу видел лишь в гридах. Почему то они не сделали эту фичу для всех компонент. |
Не совсем понятно, какое именно выделение вам нужно. В таблицах есть ячейки и строки, которые можно выделять. В обычных компонентах нет ни ячеек, ни колонок. В них и содержимого может не быть вовсе, кроме структурных элементов.
|
У меня есть компоненты, которые наследуются от штатного контейнера, которые нужно выделять, причем с возможностью группового выделения при нажатой Shift. Эти компоненты просто обычные графические примитивы: линии, кружки, квадраты и прочее. Также среди них есть примитив Группа, которая может внутри себя содержать другие примитивы (потому и потребовалось наследоваться от контейнера). В общем это по сути графический редактор. Причем я сделал так, что эти примитивы у меня выступают как виды со своими контролерами вида. Очень удобно!
|
Забыл написать, что эти графические примитивы представлены как обычные теги, так как я использую SVG.
|
Я рад, что вам MVC механизмы нравятся. ;)
Что касается выделения, то ваш случай является одиночным и скорее заслуживает частной разработки, а не общей поддержки в фреймворке. У нас и так энтропия по всем фронтам наступает, добавлять малоиспользуемые механизмы возможности никакой нет… |
У нас это у кого, простите?
|
MVC конечно нравится. И MVVC тоже понравился. Мало информации теоретического плана как этим пользоваться. Я сейчас на своем проекте методом тыка все осваиваю. Мне уже снится этот bind)))
|
У нас это у Sencha, я в основной команде Ext JS работаю. С учётом слияния Ext и Touch фронт работ увеличился многократно, так что времени на что-либо, кроме совершенно уж необходимых вещей, стало заметно меньше. :(
Про MVC подсказать/рассказать могу много, т.к. эту часть ковырял глубоко (правда, давненько уже). MVVM и data binding пока не трогал, времени не было. Поэтому не знаю совсем. :( |
Ух ты! Раз знакомству! Вопросов на самом деле куда больше. Представительство в России?
|
Спасибо, я также рад знакомству. ;)
По поводу представительства в России не могу сказать, я с бизнесом мало общаюсь и планов не знаю. Скорее всего таких планов нет, продаж в России мало. А вопросы задавайте, по мере возможности отвечу… Оперативности, правда, не обещаю, т.к. я на Тихоокеанском времени, это с Москвой 10 часов разницы. |
Часовой пояс GMT +3, время: 16:47. |