如何在文本<input>
标签中使用这个方形光标(下图)?
6 回答
样本
我改变了它的工作方式,它似乎解决了一些问题:)
- 接受任何普通输入可以输入的文本
- 退格工作
- 理论上可以支持粘贴文字
通常的警告仍然适用,最明显的是无法直观地看到插入符号的位置。
基于它的缺点和可用性问题,我会仔细考虑这个解决方案是否值得实施。
$(function() {
var cursor;
$('#cmd').click(function() {
$('input').focus();
cursor = window.setInterval(function() {
if ($('#cursor').css('visibility') === 'visible') {
$('#cursor').css({
visibility: 'hidden'
});
} else {
$('#cursor').css({
visibility: 'visible'
});
}
}, 500);
});
$('input').keyup(function() {
$('#cmd span').text($(this).val());
});
$('input').blur(function() {
clearInterval(cursor);
$('#cursor').css({
visibility: 'visible'
});
});
});
#cmd {
font-family: courier;
font-size: 14px;
background: black;
color: #21f838;
padding: 5px;
overflow: hidden;
}
#cmd span {
float: left;
padding-left: 3px;
white-space: pre;
}
#cursor {
float: left;
width: 5px;
height: 14px;
background: #21f838;
}
input {
width: 0;
height: 0;
opacity: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="cmd">
<span></span>
<div id="cursor"></div>
</div>
<input type="text" name="command" value="" />
公认的解决方案有许多问题:
它非常缓慢,尤其是在按住键时。
真正的插入符号可以用箭头移动,但你不会看到它在哪里,因为假的正方形总是在最后。
输入需要通过单击再次手动聚焦。
无法正确选择文本,因为一旦松开鼠标按钮,选择就会丢失,并且完全不可能使用键盘选择文本。
更好的解决方案可能是使用 CSS 来确保“caret”元素始终位于contenteditable
“input”之后,并使用 JS 来确保contenteditable
元素始终处于焦点位置。autofocus
您可以尝试通过添加到contenteditable
元素并使用插入符号元素来完成最后一件事<label>
,但这不适用于contenteditable
元素。请注意,不需要键盘事件侦听器:
const input = document.getElementById('input');
const caret = document.getElementById('caret');
// Move the focus back to the input if it moves away from it:
input.addEventListener('blur', (e) => {
input.focus();
});
// Set the focus to the input so that you can start typing straight away:
input.focus();
body {
background: #000;
color: #0F0;
font-family: monospace;
height: 100vh;
box-sizing: border-box;
overflow-x: hidden;
overflow-y: scroll;
margin: 0;
padding: 16px;
}
#input {
display: inline;
word-break: break-all;
outline: none;
visibility: visible;
}
#caret {
border: 0;
padding: 0;
outline: none;
background-color: #0F0;
display: inline-block;
font-family: monospace;
}
C:\WIKIPEDIA >
<div id="input" contenteditable="true"></div><button id="caret" for="input"> </button>
在更现实的示例中,您可能希望:
避免将焦点困在
contenteditable
元素中,因为这会阻止选择以前的命令。相反,contenteditable
仅在用户按下某个键时才关注元素。根据其位置显示不同的插入符号:如果它位于输入的末尾,则为正方形,如果它在其他地方则为 line(除非使用Ins键启用了改写模式)。
添加一个新的命令/条目,如果↵</kbd> is pressed.
防止输入格式化文本并在需要时自动将其拆分为多个命令/条目。
const history = document.getElementById('history');
const input = document.getElementById('input');
const cursor = document.getElementById('cursor');
function focusAndMoveCursorToTheEnd(e) {
input.focus();
const range = document.createRange();
const selection = window.getSelection();
const { childNodes } = input;
const lastChildNode = childNodes && childNodes.length - 1;
range.selectNodeContents(lastChildNode === -1 ? input : childNodes[lastChildNode]);
range.collapse(false);
selection.removeAllRanges();
selection.addRange(range);
}
function handleCommand(command) {
const line = document.createElement('DIV');
line.textContent = `C:\\WIKIPEDIA > ${ command }`;
history.appendChild(line);
}
// Every time the selection changes, add or remove the .noCursor
// class to show or hide, respectively, the bug square cursor.
// Note this function could also be used to enforce showing always
// a big square cursor by always selecting 1 chracter from the current
// cursor position, unless it's already at the end, in which case the
// #cursor element should be displayed instead.
document.addEventListener('selectionchange', () => {
if (document.activeElement.id !== 'input') return;
const range = window.getSelection().getRangeAt(0);
const start = range.startOffset;
const end = range.endOffset;
const length = input.textContent.length;
if (end < length) {
input.classList.add('noCaret');
} else {
input.classList.remove('noCaret');
}
});
input.addEventListener('input', () => {
// If we paste HTML, format it as plain text and break it up
// input individual lines/commands:
if (input.childElementCount > 0) {
const lines = input.innerText.replace(/\n$/, '').split('\n');
const lastLine = lines[lines.length - 1];
for (let i = 0; i <= lines.length - 2; ++i) {
handleCommand(lines[i]);
}
input.textContent = lastLine;
focusAndMoveCursorToTheEnd();
}
// If we delete everything, display the square caret again:
if (input.innerText.length === 0) {
input.classList.remove('noCaret');
}
});
document.addEventListener('keydown', (e) => {
// If some key is pressed outside the input, focus it and move the cursor
// to the end:
if (e.target !== input) focusAndMoveCursorToTheEnd();
});
input.addEventListener('keydown', (e) => {
if (e.key === 'Enter') {
e.preventDefault();
handleCommand(input.textContent);
input.textContent = '';
focusAndMoveCursorToTheEnd();
}
});
// Set the focus to the input so that you can start typing straigh away:
input.focus();
body {
background: #000;
color: #0F0;
font-family: monospace;
height: 100vh;
box-sizing: border-box;
overflow-x: hidden;
overflow-y: scroll;
word-break: break-all;
margin: 0;
padding: 16px;
}
#input {
display: inline;
outline: none;
visibility: visible;
}
/*
If you press the Insert key, the vertical line caret will automatically
be replaced by a one-character selection.
*/
#input::selection {
color: #000;
background: #0F0;
}
#input:empty::before {
content: ' ';
}
@keyframes blink {
to {
visibility: hidden;
}
}
#input:focus + #caret {
animation: blink 1s steps(5, start) infinite;
}
#input.noCaret + #caret {
visibility: hidden;
}
#caret {
border: 0;
padding: 0;
outline: none;
background-color: #0F0;
display: inline-block;
font-family: monospace;
}
<div id="history"></div>
C:\WIKIPEDIA >
<div id="input" contenteditable="true"></div><button id="caret" for="input"> </button>
一般来说,侦听键盘事件 ( keydown
/ keypress
/ keyup
) 来处理文本输入或光标通常不是一个好主意,因为输入的值也可以通过将文本粘贴或拖放到其中来更新,并且存在许多边缘情况,例如箭头、删除、转义、全选、复制、粘贴等快捷方式……因此,尝试列出我们应该注意的所有键的详尽列表可能不是最好的方法。
此外,这不适用于移动设备,因为大多数键发出相同的值e.key = 'Unidentified'
,e.which== 229
和e.keyCode = 229
.
相反,通常最好依靠其他事件,例如input
并使用KeyboardEvents
来处理非常特定的键,例如↵</kbd> in this case.
如果您需要检查 KeyboardEvent 的属性值,例如e.key
, e.code
,e.which
或者e.keyCode
您可以使用https://keyjs.dev。我将很快添加有关这些跨浏览器不兼容性的信息!
免责声明:我是作者。
AFAIK,这对于 html 文本框是不可能的,您可以设置输入本身的样式,但除了应用已经可用的光标选项之外,您对光标无能为力:(
你不能。这意味着:您可以自己使用固定字体,使用闪烁的 gif als 背景,通过计算已输入文本的 with 来动态设置位置 - 但您的 gif 上方会有“正常”光标,使这个解决方案变得丑陋
对于<input>
标签,您无能为力。如果您不介意这是一个可怕的 hack,您可以随时使用 JavaScript 根据需要调整文本框的大小(设置width = *something* * count
),并<img>
在右侧设置一个光标。
我不认为有任何更少的“呃”解决方案,自己处理文本输入,这可能是矫枉过正。
您将不得不 1) 滚动您自己的文本框和 2) 通过不断地将其聚焦在其他地方来隐藏真正的光标。然后,在文档/正文级别捕获关键事件,并将该值插入到您自己的元素中。然后光标将是一个动画 GIF,它始终位于“文本框”的最右侧。
你会遇到 #2 的问题,整个事情通常是不可取的。HTML 5 开辟了一些新的可能性,但对于光标来说仍然需要大量工作。