gpt4 book ai didi

javascript - 在元素中保存超时

转载 作者:行者123 更新时间:2023-11-30 14:02:15 24 4
gpt4 key购买 nike

我创建了一个 <select multiple>带有下拉菜单(如果您对完整代码感兴趣:Codepen 或底部的代码片段)带有辅助功能(下面的简化版本)处理模糊事件(输入失去焦点,也就是点击其他地方):

function blur(element) {
clearTimeout(eval(element.dataset.timer));
element.dataset.timer = setTimeout(() => {
if (activeElement !== el)
el.style.display = "none";
}, 200).toString();
}

它创建一个超时并将其存储在 dataset-property 中的元素。由于此属性只接受字符串,因此它由 toString() 转换并通过 eval() 转换回来清除前一个计时器时。这不是必需的,因为它在不进行转换和评估时工作得很好:

function blur(element) {
clearTimeout(element.dataset.timer);
element.dataset.timer = setTimeout(() => {
if (activeElement !== el)
el.style.display = "none";
}, 200);
}

无论哪种方式,它都感觉像是一个 hack,我也知道 eval()不应该使用这就是为什么我想知道我应该如何解决这个问题。我已经showed my code to CodeReview特别提到了该功能,但没有人提示它。这不可能是执行此操作的正确方法,对吗?

如果相关,这里是完整代码的片段:

convertSelect("001", "Options");

function convertSelect(el_id, name) {
let el = document.getElementById(el_id),
opts = Array.from(el.options);

let input_el = document.createElement('input');
input_el.setAttribute('id', el_id + '_input');
input_el.setAttribute('type', 'text');
input_el.setAttribute('autocomplete', 'off');
input_el.setAttribute('readonly', 'readonly');
input_el.setAttribute('style', `width:${el.offsetWidth}px`);
input_el.addEventListener('focus', () => document.getElementById(el_id + '_span').style.display = "");
input_el.addEventListener('blur', () => blur(el_id));
el.parentNode.insertBefore(input_el, el.nextSibling);

let span_el = document.createElement('span');
span_el.setAttribute('id', el_id + '_span');
span_el.setAttribute('style', `min-width:${(input_el.offsetWidth + 50)}px;margin-top:${input_el.offsetHeight}px;margin-left:-${input_el.offsetWidth}px;position:absolute;border:1px solid grey;display:none;z-index:9999;text-align:left;background:white;max-height:130px;overflow-y:auto;overflow-x:hidden;`);
span_el.addEventListener('mouseout', () => blur(el_id));
span_el.addEventListener('click', () => document.getElementById(el_id + '_input').focus());
input_el.parentNode.insertBefore(span_el, input_el.nextSibling);

opts.forEach(opt => {
let i = opts.indexOf(opt);

let temp_label = document.createElement('label');
temp_label.setAttribute('for', el_id + '_' + i);

let 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(temp_input);
temp_label.appendChild(document.createTextNode(opt.textContent));
span_el.appendChild(temp_label);
});
el.style.display = 'none';
check(el_id, name);
}


function blur(el_id) {
let el = document.getElementById(el_id);
clearTimeout(el.dataset.timer);
el.dataset.timer = setTimeout(() => {
if (document.activeElement.id !== el_id + '_input' && document.activeElement.id !== el_id + '_span')
document.getElementById(el_id + '_span').style.display = "none";
}, 200);
}

function check(el_id, name) {
let el = document.getElementById(el_id),
opts = Array.from(el.options),
select_qty = 0,
select_name;

opts.forEach(opt => {
let i = opts.indexOf(opt),
checkbox = document.getElementById(`${el_id}_${i}`);

el.options[i].selected = checkbox.checked;
if (checkbox.checked) {
select_name = checkbox.parentElement.childNodes[1].textContent;
select_qty++;
}
document.getElementById(`${el_id}_input`).value = select_qty < 1 ? '' : (select_qty > 1 ? `${select_qty} ${name}` : select_name);
});

el.dispatchEvent(new Event('change', { 'bubbles': true }));
}
label {
display: block;
}

input[type="text"]:hover {
cursor: default;
}
<select id="001" multiple>
<option value="2">Option Two</option>
<option value="4">Option Four</option>
<option value="6">Option Six</option>
<option value="8" disabled>Disabled Option</option>
</select>

最佳答案

如果您使用过静态编译语言,有时 JavaScript 类型的松散装箱/拆箱会让人感到陌生。不过,您的示例应该没有任何问题。

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


一个选项,只是您数据属性想法的扩展。您可以使用 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();

您还可以在 IIFE 中使用上面的代码,以节省调用 setupBlur 的时间:

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

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

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

关于javascript - 在元素中保存超时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56129512/

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