五年前,有人问了一个像我今天要问的问题,但显然没有发布可以解决问题的答案。现在我遇到了同样的问题。到目前为止,这是我所做的。
#cellHandlers = {
lvCell: null,
outerDiv: null,
td: null,
span: null,
input: null,
commitChanges: undefined,
beginEdit: (td, cell) => {
this.#cellHandlers.lvCell = cell;
this.#cellHandlers.td = td;
this.#cellHandlers.outerDiv = td.firstChild;
this.#cellHandlers.span = td.querySelector('span');
if (this.#cellHandlers.input == null) {
this.#cellHandlers.input = document.createElement('input');
this.#cellHandlers.input.type = 'text';
//this.#cellHandlers.input.setAttribute('autofocus', 'true');
}
this.#cellHandlers.outerDiv.remove();
this.#cellHandlers.td.appendChild(this.#cellHandlers.input);
this.#cellHandlers.td.focus();
this.#cellHandlers.input.select();
// using setTimeout is a work around. The original code was
//this.#cellHandlers.hookEvents(true);
//this.#cellHandlers.input.focus();
window.setTimeout(() => {
this.#cellHandlers.hookEvents(true);
this.#cellHandlers.input.focus();
}, 10);
//this.#cellHandlers.input.focus();
},
filterKey: e => {
e.stopPropagation();
const result = typeof this.#cellKeyFilter == 'function' &&
this.#cellKeyFilter({
cell: this.#cellHandlers.cell,
key: e.key || e.data,
value: this.#cellHandlers.input.value,
pos: this.#cellHandlers.input.selectionStart
});
if (result)
return true;
e.preventDefault();
return false;
},
hookEvents: a => {
for (let h in this.#cellHandlers) {
if (h[0] != '_')
continue;
if (a)
this.#cellHandlers.input.addEventListener(h.substr(1), this.#cellHandlers[h])
else
this.#cellHandlers.input.removeEventListener(h.substr(1), this.#cellHandlers[h])
}
},
endEdit: e => {
if (e !== undefined) {
e.stopPropagation();
}
if (this.#cellHandlers.outerDiv) {
this.#cellHandlers.hookEvents(false);
}
if (this.#cellHandlers.commitChanges) {
this.#cellHandlers.commitChanges = false;
if (this.#cellHandlers.span.textContent != this.#cellHandlers.input.value) {
this.#cellHandlers.span.textContent = this.#cellHandlers.input.value;
this.dispatchEvent(ListView.#evCellValueChanged);
}
}
try {
this.#cellHandlers.input.remove();
}
catch {
}
this.#cellHandlers.td.appendChild(this.#cellHandlers.outerDiv);
this.#cellHandlers.outerDiv = null;
this.focus();
},
_blur: e => {
this.#cellHandlers.endEdit(e);
},
_input: e => {
return this.#cellHandlers.filterKey(e);
},
_keydown: e => {
e.stopPropagation();
switch (e.key) {
case 'Escape':
this.#cellHandlers.commitChanges = false;
this.#cellHandlers.endEdit();
break;
case 'Tab':
case 'Enter':
this.#cellHandlers.input.removeEventListener('blur', this.#cellHandlers._blur);
if (e.key == 'Tab') {
let index = this.#cellHandlers.lvCell.columnIndex + 1;
const cells = this.#cellHandlers.td.parentElement.cells;
if (index == cells.length)
index = 0;
this.#setActiveCell(cells[index]);
}
this.#cellHandlers.commitChanges = true;
this.#cellHandlers.endEdit();
break;
}
}
}
#cellHandlers 是 HTMLElement 子类的类的属性。它作用/模仿 c# 的 DataGridView 的一些功能。当单击此类中的单元格并且该单元格的 editable 属性为 true 时,将调用 #cellHandlers.beginEdit,在输入元素尚未创建并添加到单元格时创建输入元素。该单元格是存储在#cellHandlers.td 中的表格单元格(td)。连接事件并将焦点设置在输入上后,blur 事件立即触发,并且该事件的处理程序调用 #cellHandlers.endEdit,这显然会结束单元格的编辑状态。为什么会出现这种行为以及如何防止它?
顺便说一句,我希望没有人建议类似 jQuery 的解决方案,尽管它可能是最后的手段。
创建输入元素并将其添加到父元素后,我这样做了:
window.setTimeout(()=>input.focus(), 1);
请注意,autofocus 属性仅在新创建输入元素时起作用,而不是在将其保存为变量中的节点时起作用。所以这个工作对我来说是必要的。
当您删除元素并希望将焦点返回到其父元素时,也是如此。我用了同样的逻辑。
大多数时间尝试和错误都是有效的(在把你搞砸了太多之后)。