В одном из моих проектов я столкнулся с задачей создания компонента слайдера с возможностью ручного ввода значения поля, т. е. выглядеть он должен был так:
Причём, при нажатии на значение поля (где написано "8.50 %") должна выдвигаться клавиатура для ввода значения поля вручную, а при перетаскивании ползунка значение поля должно обновляться.
Итак, первым делом я изучил внутренности компонента Ext.form.Slider и выяснил, что внешний вид задаётся свойством renderTpl.
Вот так выглядит renderTpl в оригинале:
В моём компоненте, помимо дополнительного поля для ручного ввода, будет присутствовать постфикс, т. е. один символ или набор символов, которые будут добавляться после поля со значением (на скриншоте - это "%"), поэтому я изменил шаблон компонента следующим образом:
CSS-классы, прописанные в этом шаблоне, заданы следующим образом:
Теперь компонент будет выглядеть должным образом, но значения value и postfix не будут применяться нашему полю, поэтому переходим к функциональной части.
Итак, value и postfix изначально не будут подставляться в шаблон, даже если мы передадим их в конфигурационные свойства при объявлении нашего кастомизированного слайдера. Изучив исходный код Ext.form.Field, от которого унаследован Ext.form.Slider, я выяснил, что список полей, которые будут заполнять шаблон, определяется функцией initRenderData, поэтому для нашего слайдера я перегрузил эту функцию следующим образом:
Теперь в шаблон будут вписаны значения, указанные в конфигурационных свойствах компонента. Осталось сделать так, чтобы эти значения менялись при перемещении ползунка слайдера.
Чтобы при перемещении ползунка новое значение применялась только к одному компоненту, а не ко всем слайдерам, добавленным на страницу, в шаблоне я задал полю input атрибут id, формирующийся из префикса dnt-form-slider-valuefield- и значения конфигурационного свойства name, которое должно быть объявлено.
Для динамического изменения значения поля необходимо подписаться к событию 'change' нашего слайдера и в качестве обработчика назначить следующую функцию:
Итак, теперь значение поля меняется, но меняется оно только тогда, когда мы отпускаем ползунок. Для того, чтобы значение поля менялось постоянно при перетаскивании слайдера, нам необходимо функцию onChangeValue подписать и на событие 'drag'.
Осталось совсем немного: надо сделать так, чтобы при ручном изменении значения поля слайдер передвигался на нужную позицию.
Для этого подписываемся на событие 'render' нашего компонента и ставим обработчиком функцию onRenderSlider - в этот момент наш компонент прорендерен, поэтому мы можем подписаться на события, выбрасываемые нашим input-элементом, отображающим текущее значение поля.
Всё, наш новый слайдер с полем для ручного ввода значения полностью готов, причём никаких дополнительных защит "от дурака" писать не надо!
Добавить компонент можно следующим образом:
В дополнение прилагаю исходный код компонента и файл со стилями.
Тестовый проект с подключенным и работающим слайдером можно скачать отсюда.
Причём, при нажатии на значение поля (где написано "8.50 %") должна выдвигаться клавиатура для ввода значения поля вручную, а при перетаскивании ползунка значение поля должно обновляться.
Итак, первым делом я изучил внутренности компонента Ext.form.Slider и выяснил, что внешний вид задаётся свойством renderTpl.
Вот так выглядит renderTpl в оригинале:
renderTpl: [ '<tpl if="label">', '<div class="x-form-label"><span>{label}</span></div>', '</tpl>', '<tpl if="fieldEl">', '<div id="{inputId}" name="{name}" class="{fieldCls}"', '<tpl if="tabIndex">tabIndex="{tabIndex}"</tpl>', '<tpl if="style">style="{style}" </tpl>', '/></tpl>' ]
В моём компоненте, помимо дополнительного поля для ручного ввода, будет присутствовать постфикс, т. е. один символ или набор символов, которые будут добавляться после поля со значением (на скриншоте - это "%"), поэтому я изменил шаблон компонента следующим образом:
renderTpl: [ '<tpl if="label">', '<div class="x-form-label"><span>{label}</span></div>', '<div class="dnt_form_slider_value">' + '<input type="text" id="dnt-form-slider-valuefield-{name}" class="dnt_form_slider_value_input" value="{value}" />' + '{postfix}' + '</div>', '</tpl>', '<tpl if="fieldEl">', '<div id="{inputId}" name="{name}" class="{fieldCls}"', '<tpl if="tabIndex">tabIndex="{tabIndex}"</tpl>', '<tpl if="style">style="{style}" </tpl>', '/></tpl>' ]
CSS-классы, прописанные в этом шаблоне, заданы следующим образом:
.dnt_form_slider_title { background-color: transparent; display: inline; } .dnt_form_slider_value { position: absolute; right: 26px; display: inline; } .dnt_form_slider_value_input { display: inline !important; min-height: 20px !important; padding: 0px !important; text-align: right; width: 60px !important; }
Теперь компонент будет выглядеть должным образом, но значения value и postfix не будут применяться нашему полю, поэтому переходим к функциональной части.
Итак, value и postfix изначально не будут подставляться в шаблон, даже если мы передадим их в конфигурационные свойства при объявлении нашего кастомизированного слайдера. Изучив исходный код Ext.form.Field, от которого унаследован Ext.form.Slider, я выяснил, что список полей, которые будут заполнять шаблон, определяется функцией initRenderData, поэтому для нашего слайдера я перегрузил эту функцию следующим образом:
initRenderData: function() { //вызываю код, который был прописан в оригинальном Ext.form.Field var renderData = Dnt.form.Slider.superclass.initRenderData.call(this); //добавляю новые поля, которые будут подставляться в шаблон Ext.applyIf(renderData, { value : this.getValue(), postfix : this.postfix }); return renderData; }
Теперь в шаблон будут вписаны значения, указанные в конфигурационных свойствах компонента. Осталось сделать так, чтобы эти значения менялись при перемещении ползунка слайдера.
Чтобы при перемещении ползунка новое значение применялась только к одному компоненту, а не ко всем слайдерам, добавленным на страницу, в шаблоне я задал полю input атрибут id, формирующийся из префикса dnt-form-slider-valuefield- и значения конфигурационного свойства name, которое должно быть объявлено.
Для динамического изменения значения поля необходимо подписаться к событию 'change' нашего слайдера и в качестве обработчика назначить следующую функцию:
onChangeValue: function(slider, thumb, newValue, oldValue) { //получаю ссылку на input-элемент компонента var valueField = Ext.get('dnt-form-slider-valuefield-' + this.name); /* устанавливаю новое значение, обрезав количество символов после запятой до значения конфигурационного свойства digitalAfterPoint (у меня по умолчанию 2) */ valueField.dom.value = newValue.toFixed(this.digitalsAfterPoint); }
Итак, теперь значение поля меняется, но меняется оно только тогда, когда мы отпускаем ползунок. Для того, чтобы значение поля менялось постоянно при перетаскивании слайдера, нам необходимо функцию onChangeValue подписать и на событие 'drag'.
Осталось совсем немного: надо сделать так, чтобы при ручном изменении значения поля слайдер передвигался на нужную позицию.
Для этого подписываемся на событие 'render' нашего компонента и ставим обработчиком функцию onRenderSlider - в этот момент наш компонент прорендерен, поэтому мы можем подписаться на события, выбрасываемые нашим input-элементом, отображающим текущее значение поля.
onRenderSlider: function() { //получаю ссылку на input-элемент компонента var valueField = Ext.get('dnt-form-slider-valuefield-' + this.name); //подписываюсь на изменения значения input-элемента valueField.on('change', function(event, el) { //формирую из введённых данных новое значение поля var newValue = parseFloat(el.value) || 0; //форматирую значение и передвигаю слайдер this.setValue(newValue.toFixed(this.digitalsAfterPoint)); }, this); }
Всё, наш новый слайдер с полем для ручного ввода значения полностью готов, причём никаких дополнительных защит "от дурака" писать не надо!
Добавить компонент можно следующим образом:
new Dnt.form.Slider({ name : 'interestRate', postfix : '%', digitalsAfterPoint: 2, minValue : 1, maxValue : 15, increment : 0.05, label : 'Interest Rate' })
В дополнение прилагаю исходный код компонента и файл со стилями.
Тестовый проект с подключенным и работающим слайдером можно скачать отсюда.
Комментариев нет:
Отправить комментарий