gpt4 book ai didi

javascript - nouislider 在某些事件中移动时消失

转载 作者:行者123 更新时间:2023-12-03 01:07:14 26 4
gpt4 key购买 nike

这与我关于 nousliders 的第一个问题非常相关:How to update div in Meteor without helper? (这个标题选得不好,因为它不是为了避免帮助者)

Jankapunkt 提供的答案非常有效,例如我可以有 4 个 slider ,并且重新排序不会丢失 slider 状态(例如最小/最大),如下所示:

switching slider works ok

现在我希望某些元素是非 slider 的,例如将 1 更改为下拉列表:

enter image description here

但是当我单击切换按钮时,1 个 slider 消失(移动到下拉位置的 slider ),并且我在控制台中收到错误:

Exception in template helper: Error: noUiSlider (11.1.0): create requires a single element, got: undefined

我不明白为什么添加 if/else 会产生任何影响... slider 助手正在等待准备就绪 {{#if Ready}}...{{/if}} 所以它应该可以工作?有人明白为什么不吗?以及如何修复它?

模板 onCreated 现在看起来像这样:

Template.MyTemplate.onCreated(function() {
const sliders = [{
id: 'slider-a',
prio: 1,
type: "NumberRange",
options: {
start: [0, 100],
range: {
'min': [0],
'max': [100]
},
connect: true
}
}, {
id: 'slider-b',
prio: 2,
type: "NumberRange",
options: {
start: [0, 100],
range: {
'min': [0],
'max': [100]
},
connect: true
}
}, {
id: 'dropdown-c',
prio: 3,
type: "Dropdown"
}, {
id: 'slider-d',
prio: 4,
type: "NumberRange",
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)
})

模板现在看起来像这样,有一个 if else 语句来显示 Dropdown 或 NumberRange( slider ):

<template name="MyTemplate">
{{#each sliders}}
<div class="range">
<div>
<span>id:</span>
<span>{{this.id}}</span>
</div>
{{#if $eq type 'Dropdown'}}
<select id="{{this.id}}" style="width: 200px;">
<option value="">a</option>
<option value="">b</option>
<option value="">c</option>
</select>
{{else if $eq type 'NumberRange'}}
<div id="{{this.id}}">
{{#if ready}}{{slider this}}{{/if}}
</div>
{{/if}}
{{#with values this.id}}
<div>
<span>values: </span>
<span>{{this}}</span>
</div>
{{/with}}
</div>
{{/each}}
<button class="test">Switch Sliders</button>
</template>

最佳答案

首先你应该了解一下情况:

  • 您正在将经典 ui 渲染( slider )与 Blaze 渲染(下拉列表)混合在一起。这会给你带来很多设计问题,下面的解决方案更多的是一种 hack,而不是使用 Blaze 的 API 的干净方法
  • 由于您的组件不再只是 slider ,因此您应该重命名变量。否则外国人很难解码你的变量的上下文。
  • 您的下拉列表当前未保存任何值,切换按钮会重置下拉列表。
  • 按下切换按钮时,您无法销毁下拉列表中的 noUiSlider,从而导致出现上述错误。

因此,我想先给您一些关于重构代码的建议。

1。重命名变量

您可以使用 IDE 的重构功能轻松重命名所有变量名称。如果您的 IDE/编辑器中没有此类功能,我强烈建议您启动搜索引擎来获取一个。

由于输入类型比 slider 多,因此您应该使用更通用的名称,例如 inputs,它表示更广泛的可能类型。

下拉列表中还应该有一个value条目,能够在重新渲染时恢复最后的选择状态:

Template.MyTemplate.onCreated(function () {

const inputs = [{
id: 'slider-a',
prio: 1,
type: 'NumberRange',
options: {
start: [0, 100],
range: {
'min': [0],
'max': [100]
},
connect: true
}
}, {
id: 'slider-b',
prio: 2,
type: 'NumberRange',
options: {
start: [0, 100],
range: {
'min': [0],
'max': [100]
},
connect: true
}
}, {
id: 'dropdown-c',
prio: 3,
type: 'Dropdown',
value: '', // default none
}, {
id: 'slider-d',
prio: 4,
type: 'NumberRange',
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('inputs', inputs)
})

现在您还必须重命名您的助手和模板助手调用:

<template name="MyTemplate">
{{#each inputs}}
...
{{/each}}
</template>

Template.MyTemplate.helpers({
inputs () {
return Template.instance().state.get('inputs')
},
...
})

2。处理切换事件的多种输入类型

您还应该在 switch 事件中重命名变量。此外,您需要在这里处理不同的输入类型。下拉菜单没有 .noUiSlider 属性,并且它们也接收的不是数组而是字符串变量作为值:

'click .test': function (event, templateInstance) {

let inputs = templateInstance.state.get('inputs')
const values = templateInstance.state.get('values')

// remove current rendered inputs
// and their events / prevent memory leak
inputs.forEach(input => {

if (input.type === 'Dropdown') {
// nothing to manually remove
// Blaze handles this for you
return
}

if (input.type === 'NumberRange') {
const target = templateInstance.$(`#${input.id}`).get(0)
if (target && target.noUiSlider) {
target.noUiSlider.off()
target.noUiSlider.destroy()
}
}
})

// assign current values as
// start values for the next newly rendered
// inputs
inputs = inputs.map(input => {
const currentValues = values[input.id]

if (!currentValues) {
return input
}

if (input.type === 'Dropdown') {
input.value = currentValues
}

if (input.type === 'NumberRange') {
input.options.start = currentValues.map(n => Number(n))
}

return input
}).reverse()

templateInstance.state.set('inputs', inputs)
},

3。正确渲染/更新显示列表

现在出现了将 Blaze 渲染与经典 DOM 更新混合在一起的问题:直到此时您将遇到错误。这主要是因为现在我们的createSliders函数将在渲染下拉列表的位置期望一个具有特定id的div元素在按下开关之前。它不会在那里,因为此时 Blaze 渲染失效尚未完成。

onCreatedonRendered 中使用 autorun 修复此问题很容易会增加复杂性,甚至弄乱您的代码。一个更简单的解决方案是在这里使用较短的超时:

Template.MyTemplate.helpers({
// ...
slider (source) {
const instance = Template.instance()
setTimeout(()=> {
createSliders(source.id, source.options, instance)
}, 50)
},
// ...
})

4。奖励:保存下拉菜单的状态

为了保存下拉列表的状态,您需要 Hook 它的 change 事件。因此,您需要为其分配一个类,以独立于 id 映射事件:

 <select id="{{this.id}}" class="dropdown" style="width: 200px;">...</select>

现在您可以为此创建一个事件:

'change .dropdown'(event, templateInstance) {
const $target = templateInstance.$(event.currentTarget)
const value = $target.val()
const targetId = $target.attr('id')
const valuesObj = templateInstance.state.get('values')
valuesObj[targetId] = value
templateInstance.state.set('values', valuesObj)
}

现在您已经保存了当前的下拉值,但为了在下一次渲染中恢复它,您需要扩展 html 中的 options:

<select id="{{this.id}}" class="dropdown" style="width: 200px;">
<option value="a" selected="{{#if $eq this.value 'a'}}selected{{/if}}">a</option>
<option value="b" selected="{{#if $eq this.value 'b'}}selected{{/if}}">b</option>
<option value="c" selected="{{#if $eq this.value 'c'}}selected{{/if}}">c</option>
</select>

现在还应该显示下拉列表的最后选定状态。

摘要

  • 您可以使用此模式来包含更多输入组件。
  • 请注意,将 Blaze 渲染与传统 DOM 操作混合会大大增加代码的复杂性。这同样适用于许多其他渲染系统/库/框架。
  • 当其他方法更不可行时,setTimeout 解决方案应该是最后使用的方法。
  • 变量和方法命名应始终代表其上下文。如果上下文发生变化 -> 重命名/重构变量和方法。
  • 请下次在此处再次发布完整的代码。您的其他帖子可能会被更新或删除,并且此处将无法再访问完整的代码,这使得其他人很难找到好的解决方案.

关于javascript - nouislider 在某些事件中移动时消失,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52340006/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com