在网页中模拟DOS或终端屏幕的最佳方法是什么?

Ter*_*ich 8 html javascript php jquery

我发现这很难概念化.简单的方法是让一个大textarea元素占据屏幕的大部分,input下面有一个小文本元素.玩家将输入命令,输出将显示在textarea.

问题是,我希望输入完全集成.想想DOS屏幕.有一个括号提示符,>然后输入一个命令.按Enter键,输出显示在它下面,然后是另一个>提示输入下一个命令.视觉上输入与输出不是分开的.我可以在这里看到我想要完成的一个示例:http://www.youtube.com/watch?v = UC_FrikiZdE(除了使用鼠标选择命令,它们可以输入).

我将如何在HTML中执行此操作(使用JavaScript/jQuery处理输入/输出)?我想也许一切都是在可编辑的情况下完成的textarea,但Backspace按钮不能从>提示中删除任何内容,只能输入已输入的文本.

最简单的方法是什么?我无法在线找到任何演示或教程.任何人都能指出我可能错过的任何东西吗?谢谢.

小智 12

您可以通过Google在线查看这些JavaScript终端:

此外,我的一些法国朋友正在研究这个问题:


Dan*_*ger 8

如果您想自己构建解决方案而不是使用库,则可以使用一个contenteditable元素并在其后使用一个假的方形插入符。如果插入符号移动到另一个位置,则该假插入符号将被隐藏,并显示真正的垂直线。

\n

但是,您可以调整此代码以始终选择一个字符,即使禁用改写模式也是如此,以便插入符号始终是一个字符宽的正方形。

\n

我只显示命令,但以不同的方式处理它们是很简单的:

\n

\r\n
\r\n
const history = document.getElementById(\'history\');\nconst input = document.getElementById(\'input\');\nconst cursor = document.getElementById(\'cursor\');\n\nfunction focusAndMoveCursorToTheEnd(e) {  \n  input.focus();\n  \n  const range = document.createRange();\n  const selection = window.getSelection();\n  const { childNodes } = input;\n  const lastChildNode = childNodes && childNodes.length - 1;\n  \n  range.selectNodeContents(lastChildNode === -1 ? input : childNodes[lastChildNode]);\n  range.collapse(false);\n\n  selection.removeAllRanges();\n  selection.addRange(range);\n}\n\nfunction handleCommand(command) {\n  const line = document.createElement(\'DIV\');\n  \n  line.textContent = `> ${ command }`;\n  \n  history.appendChild(line);\n}\n\n// Every time the selection changes, add or remove the .noCursor\n// class to show or hide, respectively, the bug square cursor.\n// Note this function could also be used to enforce showing always\n// a big square cursor by always selecting 1 chracter from the current\n// cursor position, unless it\'s already at the end, in which case the\n// #cursor element should be displayed instead.\ndocument.addEventListener(\'selectionchange\', () => {\n  if (document.activeElement.id !== \'input\') return;\n  \n  const range = window.getSelection().getRangeAt(0);\n  const start = range.startOffset;\n  const end = range.endOffset;\n  const length = input.textContent.length;\n  \n  if (end < length) {\n    input.classList.add(\'noCaret\');\n  } else {\n    input.classList.remove(\'noCaret\');\n  }\n});\n\ninput.addEventListener(\'input\', () => {    \n  // If we paste HTML, format it as plain text and break it up\n  // input individual lines/commands:\n  if (input.childElementCount > 0) {\n    const lines = input.innerText.replace(/\\n$/, \'\').split(\'\\n\');\n    const lastLine = lines[lines.length - 1];\n    \n    for (let i = 0; i <= lines.length - 2; ++i) {\n      handleCommand(lines[i]);\n    }\n  \n    input.textContent = lastLine;\n    \n    focusAndMoveCursorToTheEnd();\n  }\n  \n  // If we delete everything, display the square caret again:\n  if (input.innerText.length === 0) {\n    input.classList.remove(\'noCaret\');  \n  }  \n});\n\ndocument.addEventListener(\'keydown\', (e) => {   \n  // If some key is pressed outside the input, focus it and move the cursor\n  // to the end:\n  if (e.target !== input) focusAndMoveCursorToTheEnd();\n});\n\ninput.addEventListener(\'keydown\', (e) => {    \n  if (e.key === \'Enter\') {\n    e.preventDefault();\n        \n    handleCommand(input.textContent);    \n    input.textContent = \'\';\n    focusAndMoveCursorToTheEnd();\n  }\n});\n\n// Set the focus to the input so that you can start typing straigh away:\ninput.focus();
Run Code Online (Sandbox Code Playgroud)\r\n
body {\n  background: #000;\n  color: #0F0;\n  font-family: monospace;\n  height: 100vh;\n  box-sizing: border-box;\n  overflow-x: hidden;\n  overflow-y: scroll;\n  word-break: break-all;\n  margin: 0;\n  padding: 16px;\n}\n\n#input {\n  display: inline;\n  outline: none;\n  visibility: visible;\n}\n\n/*\n  If you press the Insert key, the vertical line caret will automatically\n  be replaced by a one-character selection.\n*/\n#input::selection {\n  color: #000;\n  background: #0F0;\n}\n\n#input:empty::before {\n  content: \' \';\n}\n\n@keyframes blink {\n  to {\n    visibility: hidden;\n  }\n}\n\n#input:focus + #caret {\n  animation: blink 1s steps(5, start) infinite;\n}\n\n#input.noCaret + #caret {\n  visibility: hidden;\n}\n\n#caret {\n  border: 0;\n  padding: 0;\n  outline: none;\n  background-color: #0F0;\n  display: inline-block;\n  font-family: monospace;\n}
Run Code Online (Sandbox Code Playgroud)\r\n
<div id="history"></div>\n\n> \n\n<div id="input" contenteditable="true"></div><button id="caret" for="input">&nbsp;</button>
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n

请注意,此解决方案主要依赖于inputselectionchange事件,而不是键盘事件 ( keydown/ keypress/ keyup)。使用它们来处理文本输入或光标通常是一个坏主意,因为输入的值也可以通过粘贴或删除文本来更新,并且存在许多边缘情况,例如箭头、删除、转义、诸如全选、复制、粘贴等快捷方式...因此,尝试列出我们应该处理的所有键的详尽列表可能不是最好的方法。

\n

此外,这在移动设备上不起作用,因为大多数键都会发出相同的值e.key = \'Unidentified\'e.which== 229e.keyCode = 229

\n

相反,通常最好依赖其他事件,例如input和 useKeyboardEvents来处理非常特定的键,就像\xe2\x86\xb5在本例中一样。

\n

如果您需要检查 KeyboardEvent\ 的属性值,例如e.keye.codee.which或者e.keyCode您可以使用https://keyjs.dev。我将很快添加有关此类跨浏览器不兼容性的信息!

\n

Key.js \\ JavaScript KeyboardEvent\ 的按键代码和按键标识符

\n

免责声明:我是作者。

\n