Javascript 在元素中保存超时

Javascript 在元素中保存超时,javascript,settimeout,Javascript,Settimeout,我创建了一个带有下拉菜单的(如果您对完整的代码感兴趣:或在底部的代码片段)和一个辅助函数(下面的简化版本)来处理模糊事件(输入的焦点丢失或单击其他地方): 它创建一个超时并将其存储在元素的内部。由于此属性仅接受字符串,因此在清除上一个计时器时,它由toString()转换,并由eval()转换回。当不进行这样的转换和评估时,这是不必要的,因为它工作得非常好: function blur(element) { clearTimeout(element.dataset.timer);

我创建了一个带有下拉菜单的
(如果您对完整的代码感兴趣:或在底部的代码片段)和一个辅助函数(下面的简化版本)来处理模糊事件(输入的焦点丢失或单击其他地方):

它创建一个超时并将其存储在元素的内部。由于此属性仅接受字符串,因此在清除上一个计时器时,它由
toString()
转换,并由
eval()
转换回。当不进行这样的转换和评估时,这是不必要的,因为它工作得非常好:

function blur(element) {
    clearTimeout(element.dataset.timer);
    element.dataset.timer = setTimeout(() => {
        if (activeElement !== el)
            el.style.display = "none";
    }, 200);
}
无论哪种方式,它都感觉像是黑客攻击,我也知道不应该使用
eval()
,这就是为什么我想知道应该如何解决这个问题。我已经特别提到了这个功能,但是没有人抱怨它。这不可能是正确的方法,对吗

以下是完整代码的片段(如果相关):

convertSelect(“001”、“选项”);
函数convertSelect(el_id,name){
设el=document.getElementById(el_id),
opts=数组。从(el。选项);
让input_el=document.createElement('input');
input_el.setAttribute('id',el_id+''u input');
输入_el.setAttribute('type','text');
输入_el.setAttribute('autocomplete','off');
输入_el.setAttribute('readonly','readonly');
输入_el.setAttribute('style','width:${el.offsetWidth}px`);
input_el.addEventListener('focus',()=>document.getElementById(el_id+'u span').style.display=“”);
输入加法器列表器('blur',()=>blur(el_id));
el.parentNode.insertBefore(输入,el.nextSibling);
设span_el=document.createElement('span');
span_el.setAttribute('id',el_id+''u span');
span_el.setAttribute('style',`min width:${(input_el.offsetWidth+50)}px;页边距顶部:${input_el.offsetHeight}px;页边距左侧:-${input_el.offsetWidth}px;位置:绝对;边框:1px纯灰;显示:无;z索引:9999;文本对齐:左侧;背景:白色;最大高度:130px;溢出-y:自动;溢出-x:隐藏;`);
span_el.addEventListener('mouseout',()=>blur(el_id));
span_el.addEventListener('click',()=>document.getElementById(el_id+'u input').focus());
input_el.parentNode.insertBefore(span_el,input_el.nextSibling);
opts.forEach(opt=>{
设i=opts.indexOf(opt);
让temp_label=document.createElement('label');
temp_label.setAttribute('for',el_id+'''.+i');
让temp_input=document.createElement('input');
temp_input.setAttribute('style','width:auto;');
temp_input.setAttribute('type','checkbox');
temp_input.setAttribute('id',el_id+'.+i);
temp_input.checked=opt.selected;
temp_input.disabled=opt.disabled | | el.disabled;
temp_input.addEventListener('change',()=>check(el_id,name));
临时标签追加子项(临时输入);
temp_label.appendChild(document.createTextNode(opt.textContent));
span_el.appendChild(临时标签);
});
el.style.display='none';
支票(el_id,姓名);
}
函数模糊(el_id){
设el=document.getElementById(el_id);
clearTimeout(el.dataset.timer);
el.dataset.timer=设置超时(()=>{
if(document.activeElement.id!==el_id+'''u input'&&document.activeElement.id!==el_id+''u span')
document.getElementById(el_id+''''u span').style.display=“无”;
}, 200);
}
功能检查(el_id,名称){
设el=document.getElementById(el_id),
opts=阵列起始(el.选项),
选择数量=0,
选择_名称;
opts.forEach(opt=>{
设i=opts.indexOf(opt),
checkbox=document.getElementById(`${el_id}{i}`);
el.options[i]。选中=复选框。选中;
如果(复选框。选中){
选中\u name=checkbox.parentElement.childNodes[1].textContent;
选择_数量++;
}
document.getElementById(`${el\u id}}{u input`).value=select\u qty<1?“”:(select\u qty>1?`${select\u qty}${name}`:select\u name);
});
el.dispatchEvent(新事件('change',{'bubbles':true}));
}
标签{
显示:块;
}
输入[type=“text”]:悬停{
游标:默认值;
}

选择二
选择四
选择六
禁用选项

您是否可以创建一个全局计时器对象,在其中使用连续键存储超时,并仅在数据集中存储键? 有点像:

var timersObj = {};
//store timeout in object
timersObj["timerIndex_0"] = setTimeout(() => {
        if (activeElement !== el)
            el.style.display = "none";
    }, 200)
element.dataset.timer = "timerIndex_0";
//clear timeout by key
clearTimeout(timersObj[element.dataset.timer])

如果您来自一种静态编译语言,那么有时候JavaScripts松散的装箱/拆箱类型可能会让人觉得陌生。不过,您的示例不应该有任何问题

但是,在元素上存储数据还有其他方法,如果数据变得更复杂,那么在数据属性上存储可能不是最好的方法


一个选项,只是数据属性思想的扩展。您可以使用JSON序列化数据:

element.dataset.options = JSON.stringify({timerId: setTimeout(....)});
上述方法的一个缺点是,可以存储的类型仅限于JSON可以序列化的类型,但字符串/整数/数组等可以很好地工作


JavaScript中的元素与任何其他对象一样。因此,从理论上讲,您可以将其存储为属性:

element._mytimerid = setTimeout(...`, 
使用这种方法,您必须小心您所称的属性


闭包是一种流行的选择:

function setupBlur() {
  var timerId = null;
  element.onBlur = function () {
    clearTimeout(timerId);
    timerId = setTimeout(.....
  }
}

setupBlur();
您还可以在iLife中使用上述命令来保存调用设置模糊:

(function () { 
  var timerId = null;
  element.onBlur = function () {
  clearTimeout(timerId);
  timerId = setTimeout(.....
}());

在元素上存储数据的更现代的方法是使用WeakMap:

const timerIds = new WeakMap();
.....
const timerId = timerIds.get(element);
clearTimeout(timerId);
timerIds.set(element, setTimer(.....));

不知道为什么你觉得第二个版本是黑客,。。但是,如果您想确保它是一个整数,而不是
eval
,请使用
parseInt
。@Keith
setTimeout().toString()
对我来说似乎是信息丢失。你说得对:
parseInt()
在这里更好。感谢您的建议无需删除问题,对于来自静态编译语言的人来说,Javascript松散的装箱和拆箱真的让人感到陌生
const timerIds = new WeakMap();
.....
const timerId = timerIds.get(element);
clearTimeout(timerId);
timerIds.set(element, setTimer(.....));