С Blaze вы также должны явно импортировать файл .css
, чтобы применить стили:
// no slider without css
import 'nouislider/distribute/nouislider.css'
import noUiSlider from 'nouislider'
Затем вы можете легко использовать встроенный в шаблон jQuery, чтобы получить целевой div, где nouisliderбудет оказывать.
Рассмотрим следующий шаблон:
<template name="MyTemplate">
<div>
<div id="range"></div>
</div>
{{#if values}}
<div>
<span>values: </span>
<span>{{values}}</span>
</div>
{{/if}}
<button class="test">Show Slider</button>
</template>
Теперь давайте визуализируем новый nouislider в div с id range
, нажав кнопку:
Template.MyTemplate.events({
'click .test': function (event, templateInstance) {
createSliders(templateInstance)
},
})
function createSliders (templateInstance) {
// get the target using the template's jQuery
const range = templateInstance.$('#range').get(0)
noUiSlider.create(range, {
start: [0, 100],
range: {
'min': [0],
'max': [100]
},
connect: true
})
}
Теперь выздесь также можно легко добавить некоторые реактивные данные (но избегать Session
):
Template.MyTemplate.onCreated(function () {
const instance = this
instance.state = new ReactiveDict()
instance.state.set('values', null)
})
... и связать их с некоторыми данными.noUiSlider
позволяет вам подключиться к событию обновления, откуда вы можете передать значения в состояние:
function createSliders (templateInstance) {
// get slider, render slider...
// ...
range.noUiSlider.on('update', function (values, handle) {
// update values, for instance use a reactive dict
templateInstance.state.set('values', values)
})
}
Визуализировать значение в шаблон с помощью помощника:
Template.MyTemplate.helpers({
values () {
return Template.instance().state.get('values')
}
})
Импортируйте свои собственные .css
файлы для статического стиля слайдера следующим образом:
#range {
width: 300px;
margin: 14px;
}
или динамического стиля, используя jQuery's css .
ОБНОВЛЕНИЕ: правильная визуализация в обновленном списке отображения
Описанная вами проблема верна и может быть воспроизведена.Однако это также можно предотвратить, используя Template.onRendered
для управления точкой, когда может произойти рендеринг.
Я расширил шаблон до следующего кода:
<template name="MyTemplate">
{{#each sliders}}
<div class="range">
<div>
<span>id:</span>
<span>{{this.id}}</span>
</div>
<div id="{{this.id}}">
{{#if ready}}{{slider this}}{{/if}}
</div>
{{#with values this.id}}
<div>
<span>values: </span>
<span>{{this}}</span>
</div>
{{/with}}
</div>
{{/each}}
<button class="test">Switch Sliders</button>
</template>
Теперь загляните внутрь целевого элемента div, которому ранее был назначен только идентификатор.Теперь есть флаг {{#if ready}}
и функция, вызывающая {{slider this}}
.
Теперь, чтобы выполнить рендеринг только тогда, когда DOM был изначально визуализирован, нам нужно Template.onRendered
:
Template.MyTemplate.onRendered(function () {
const instance = this
instance.state.set('ready', true)
})
и добавьте его к (обновленным) помощникам:
Template.MyTemplate.helpers({
sliders () {
return Template.instance().state.get('sliders')
},
values (sliderId) {
return Template.instance().state.get('values')[sliderId]
},
slider (source) {
createSliders(source.id, source.options, Template.instance())
},
ready() {
return Template.instance().state.get('ready')
}
})
Теперь у нас есть еще несколько проблем, которые необходимо решить.Мы хотим визуализировать только если переключатель меняется, но не если значения обновляются.Но нам нужны последние значения, чтобы переназначить их в качестве начальной позиции при следующем рендере (в противном случае ползунки будут установлены с начальными значениями 0,100).
Для этого мы изменим код onCreated
немного:
Template.MyTemplate.onCreated(function () {
// initial slider states
const sliders = [{
id: 'slider-a',
options: {
start: [0, 100],
range: {
'min': [0],
'max': [100]
},
connect: true
}
}, {
id: 'slider-b',
options: {
start: [0, 100],
range: {
'min': [0],
'max': [100]
},
connect: true
}
},
]
const instance = this
instance.state = new ReactiveDict()
instance.state.set('values', {}) // mapping values by sliderId
instance.state.set('sliders', sliders)
})
Теперь, если мы нажмем кнопку переключателя, хотим а) удалить все текущие ползунки с их событиями и т. д. и б) обновить данные sliders
до нашего нового (обращенного) состояния:
Template.MyTemplate.events({
'click .test': function (event, templateInstance) {
let sliders = templateInstance.state.get('sliders')
const values = templateInstance.state.get('values')
// remove current rendered sliders
// and their events / prevent memory leak
sliders.forEach(slider => {
const target = templateInstance.$(`#${slider.id}`).get(0)
if (target && target.noUiSlider) {
target.noUiSlider.off()
target.noUiSlider.destroy()
}
})
// assign current values as
// start values for the next newly rendered
// sliders
sliders = sliders.map(slider => {
const currentValues = values[slider.id]
if (currentValues) {
slider.options.start = currentValues.map(n => Number(n))
}
return slider
}).reverse()
templateInstance.state.set('sliders', sliders)
}
})
Поскольку у нас есть несколько значений ползунка, которые должны обновляться отдельно, нам также необходимо изменить некоторый код в функции createSlider
:
function createSliders (sliderId, options, templateInstance) {
const $target = $(`#${sliderId}`)
const target = $target.get(0)
//skip if slider is already in target
if ($target.hasClass('noUi-target')) {
return
}
noUiSlider.create(target, options)
target.noUiSlider.on('update', function (values, handle) {
// update values by sliderId
const valuesObj = templateInstance.state.get('values')
valuesObj[sliderId] = values
templateInstance.state.set('values', valuesObj)
})
}
Используя этот подход, вы получаете некоторые преимущества, а некоторыенедостатки. Шаблон
- (+) можно использовать для решения многих подобных задач.
- (+) нет
autorun
требуется - (+) отделяет состояние ползунка от значениясостояние
- (-) при повторном рендеринге рендеринг может происходить более одного раза, пользователи не обращают на это внимания, но тратят ресурсы, что может стать проблемой для мобильных устройств.
- (-) может стать чрезмернымсложный на больших шаблонах.Инкапсуляция шаблонов здесь очень важна.