В одном из моих проектов я столкнулся с задачей создания компонента слайдера с возможностью ручного ввода значения поля, т. е. выглядеть он должен был так:
Причём, при нажатии на значение поля (где написано "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'
})
В дополнение прилагаю исходный код компонента и файл со стилями.
Тестовый проект с подключенным и работающим слайдером можно скачать отсюда.

Комментариев нет:
Отправить комментарий