我可以使用JavaScript毫无问题地更新div。例如,两个div的初始值都显示在左侧的图像中,而单击测试按钮后的值则显示在右侧。
当我单击“测试”按钮时,计数器将增加1,并且div的值将如下更改:
var ela = document.getElementById("a");
var elb = document.getElementById("b");
$("#" + ela.id).html("new value " + ela.id + " ");
$("#" + elb.id).html("new value " + elb.id + " ");
到目前为止很好,但是现在我想更改div的顺序:当计数器为偶数时,我希望div a =黄色在顶部(div b =灰色在底部),而另一个计数器不平衡时会消失。
为简单起见,在示例中,我对每个可能的命令(a,b)和(b,a)使用2个小数组,并且一个助手“命令”将根据计数器值(x)返回2种情况中的1种%2是否为零)
不幸的是,结果不是我想要和期望的。 div正确更改了位置,但其文本却没有。第一次单击后,计数器从5变为6,因此黄色div从下到上移动,但是div内的文本是错误的,我希望黄色div中的'new value a'向上移动,但是我得到了取而代之的是“新值ba”(反之,与其他div相同)
当我在控制台输出中检查div时,我看到奇怪的结果,Meteor似乎对div id感到困惑?如下图所示,第一个div既是a和b,又是黄色和灰色...
有人知道这是为什么吗?我该如何解决?
我知道我可以使用助手在正确的div中获得正确的文本。但是我的最终目标不是更改div内的文本,而是要使用nouislider创建一个滑块,如下所示:
var noUiSlider = require('nouislider');
var sliderHtmlElement = document.getElementById("a");
var options = {
start: [0, 100],
range: {
'min': [0],
'max': [100]
}
};
noUiSlider.create(sliderHtmlElement, options);
我完整的测试代码:
<template name="MyTemplate">
{{x}}
<br>
<br>
{{#each order}}
<div class="{{label}}" id="{{label}}"
style="background-color: {{color}};">
start value {{label}}
</div>
<br>
{{/each}}
<button class="test">test</button>
</template>
var order1;
var order2;
Template.MyTemplate.onCreated(function() {
Session.set("x", 5);
var or0 = [];
or0["label"] = "a";
or0["color"] = "yellow";
var or1 = [];
or1["label"] = "b";
or1["color"] = "grey";
order1 = [];
order1[0] = or0;
order1[1] = or1;
order2 = [];
order2[0] = or1;
order2[1] = or0;
});
Template.MyTemplate.events({
'click .test': function(event) {
var varx = Session.get("x") + 1;
Session.set("x", varx);
createSliders();
}
});
Template.MyTemplate.helpers({
x: function() {
return Session.get("x");
},
order: function() {
if (Session.get("x") % 2 === 0) {
return order1;
} else {
return order2;
}
}
});
function createSliders() {
var ela = document.getElementById("a");
var elb = document.getElementById("b");
console.log(ela);
console.log(elb);
$("#" + ela.id).html("new value " + ela.id + " ");
$("#" + elb.id).html("new value " + elb.id + " ");
}
答案 0 :(得分:3)
使用Blaze,您还必须显式导入.css
文件才能应用样式:
// no slider without css
import 'nouislider/distribute/nouislider.css'
import noUiSlider from 'nouislider'
然后,您可以轻松地使用Template的内置jQuery获取nouislider将呈现的目标div。
请考虑以下模板:
<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渲染为id为range
的div:
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的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的内部,该目标以前仅分配了一个ID。现在有一个{{#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)
})
现在,如果我们按下切换按钮,则要a)删除所有当前滑块及其事件等,并b)将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