【问题标题】:How to use square cursor in a HTML input field?如何在 HTML 输入字段中使用方形光标?
【发布时间】:2011-04-15 01:18:45
【问题描述】:

如何在文本<input> 标签中使用这个方形光标(下图)?

【问题讨论】:

    标签: javascript html css text-cursor


    【解决方案1】:

    示例

    我有changed how it works,它似乎解决了一些问题:)

    • 接受任何普通输入可以输入的文本
    • 退格有效
    • 理论上可以支持粘贴文字

    通常的警告仍然适用,最明显的是无法直观地看到插入符号的位置。

    我认为漫长而艰难这个解决方案是否值得实施,基于它的缺点和可用性问题。

    $(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="" />

    【讨论】:

    • +1 一个很酷的小例子……想到更多注意事项,例如支持多个元素、标签索引问题、可访问性等。
    • 非常好的解决方案。现在只有两个问题:1)只有大写字符 2)退格和回车不起作用。
    • 是的,它确实有一些严重的限制。可以添加 Backspace 和 Enter。查找他们的密钥代码并提交表单或substr(str, -1)。这完全取决于您愿意走多远,以及您希望这种输入有多糟糕。
    • 三个更根本的问题:一、光标不能放在文本末尾以外的任何地方;第二,keyup(或keydown)事件的keyCode 属性不是字符代码,不应被视为字符代码。仅使用keypress 事件处理文本输入;第三,这不是表单输入,因此无法提交到服务器。您需要一个自动与您的 div 内容保持同步的隐藏输入。
    • 在现代浏览器中,您可以使用 selectionEnd 属性来确定光标的位置。我这里有一个支持任意光标定位的小提琴:jsfiddle.net/HugeHugh/gZMSQ
    【解决方案2】:

    公认的解决方案有很多问题:

    • 速度非常慢,尤其是在按住键时。

    • 真正的插入符号可以用箭头移动,但你不会看到它在哪里,因为假的正方形总是在最后。

    • 输入需要通过单击再次手动聚焦。

    • 无法正确选择文本,因为一旦松开鼠标按钮,选择就会丢失,并且完全无法使用键盘选择文本。

    更好的解决方案可能是使用 CSS 确保“插入符号”元素始终位于 contenteditable“输入”之后,并使用 JS 确保 contenteditable 元素始终处于焦点位置。您可以尝试通过将autofocus 添加到contenteditable 元素并使用&lt;label&gt; 作为插入符号元素来完成最后一件事,但这不适用于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">&nbsp;</button>

    在一个更现实的例子中,您可能想要:

    • 避免在contenteditable 元素中捕获焦点,因为这会阻止选择以前的命令。相反,只有在用户按下某个键时才关注contenteditable 元素。

    • 根据位置显示不同的插入符号:如果它在输入的末尾,则为正方形,如果在其他位置则为 line(除非使用 Ins 键启用了改写模式)。

    • 如果按下 ,则添加新的命令/条目。

    • 防止输入格式化文本,并在需要时自动将其拆分为多个命令/条目。

    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">&nbsp;</button>

    一般来说,监听键盘事件 (keydown / keypress / keyup) 来处理文本输入或光标通常是个坏主意,因为输入的值也可以通过粘贴或删除来更新文本进入其中,并且有许多边缘情况,例如箭头,删除,转义,全选,复制,粘贴等快捷方式......所以试图提出我们应该注意的所有键的详尽列表可能是不是最好的方法。

    此外,这不适用于移动设备,因为大多数键发出相同的值 e.key = 'Unidentified'e.which== 229e.keyCode = 229

    相反,通常最好依靠input 等其他事件并使用KeyboardEvents 来处理非常具体的键,如本例中的

    如果您需要检查键盘事件的属性值,例如e.keye.codee.whiche.keyCode,您可以使用https://keyjs.dev。我会尽快添加有关这些跨浏览器不兼容的信息!

    免责声明:我是作者。

    【讨论】:

      【解决方案3】:

      AFAIK,这对于 html 文本框是不可能的,您可以设置输入本身的样式,但除了应用已经可用的光标选项之外,您对光标无能为力:(

      【讨论】:

      • 没错。可以操纵鼠标光标。文本光标不能。
      【解决方案4】:

      你不能。这意味着:您可以自己使用固定字体,使用闪烁的 gif als 背景,通过计算已键入文本的 with 来动态设置位置 - 但会有“ normal" 光标在你的 gif 上方,使这个解决方案变得丑陋

      【讨论】:

        【解决方案5】:

        对于&lt;input&gt; 标签,您无能为力。如果您不介意这是一个可怕的 hack,您可以随时使用 JavaScript 来根据需要调整文本框的大小(设置 width = *something* * count),并在光标右侧设置 &lt;img&gt;

        我认为没有任何“呃”的解决方案,自己处理文本输入,这可能是矫枉过正。

        【讨论】:

          【解决方案6】:

          您必须 1) 滚动您自己的文本框,以及 2) 通过不断将光标聚焦在其他地方来隐藏真正的光标。然后,在文档/正文级别捕获关键事件,并将该值插入到您自己的元素中。然后光标将是一个动画 GIF,始终位于“文本框”的最右侧。

          您会遇到#2 的问题,整个事情通常是不可取的。 HTML 5 开辟了一些新的可能性,但对于光标来说仍然需要大量工作。

          【讨论】:

            猜你喜欢
            • 2015-11-20
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-08-12
            • 1970-01-01
            相关资源
            最近更新 更多