乐趣区

关于前端:xtermjsreact的综合使用onKey以及onData的区别使用导致的光标串行问题

xterm.js 官网
借鉴学习案例

一. 筹备工作

  • npm install xterm
  • npm install xterm-addon-fit

    二. 初始引入渲染

    import {Terminal} from 'xterm'
    import {FitAddon} from 'xterm-addon-fit'
    import 'xterm/css/xterm.css'
    
    let term = new Terminal({
      // 渲染类型
      rendererType: 'canvas',
      //   是否禁用输出
      disableStdin: false,
      cursorStyle: 'underline',
      //   启用时光标将设置为下一行的结尾
      convertEol: true,
      // 终端中的回滚量
      scrollback: 10,
      fontSize: 14,
      rows: 20,
      // 光标闪动
      cursorBlink: true,
      theme: {
        //   字体
        foreground: '#ffffff',
        background: '#000000',
        // 光标
        cursor: 'help',
        lineHeight: 18,
      },
    })
    
    // 换行并输出起始符 $
    term.prompt = () => {term.write(`\r\n${terminalTitleTemplate}:`)
    }
    
    // 进行适应容器元素大小
    let fitAddon = new FitAddon()
    term.loadAddon(fitAddon)
    fitAddon.fit()
    

    三. 重点来了,onData 的应用能够输出中文且按高低键应用历史命令的时候不会光标串行笼罩之前的终端提示符

    const keyAction = (){
    // 定义变量获取整行数据
    let currentLineData = ''
    // 历史行输出数据
    let historyLineData = []
     let last = 0
      // 使其可能输出汉字
      term.onData(async key => {
       //enter 键
        if (key.charCodeAt(0) === 13) {
          // 将行数据进行增加进去
          if (currentLineData !== '') {
          // 将以后行数据传入历史命令数组中存储
            historyLineData.push(currentLineData)
              // 定义以后行命令在整个数组中的地位
            last = historyLineData.length - 1
          }
          // 当输出 clear 时清空终端内容
          if (currentLineData === 'clear') {term.clear()
          }
    
        // 在这能够进行发动申请将整行数据传入
    
          // 清空以后行数据
          currentLineData = ''
    
          term.write(`\r\n${terminalTitleTemplate}: `)
        } else if (key.charCodeAt(0) === 127) {
          // 删除键 --》以后行偏移量 x 大于终端提示符所占地位时进行删除
          if (term._core.buffer.x > terminalTitleTemplate.length + 1) {currentLineData = currentLineData.slice(0, -1)
            term.write('\b \b')
          }
        } else if (key === '\u001b[A') {
          //up 键的时候
          let len = 0
          if (historyLineData.length > 0) {len = historyLineData.length + 1}
    
          if (last < len && last > 0) {
              // 以后行有数据的时候进行删除掉在进行渲染上存储的历史数据
            for (let i = 0; i < currentLineData.length; i++) {if (term._core.buffer.x > terminalTitleTemplate.length + 1) {term.write('\b \b')
              }
            }
            let text = historyLineData[last - 1]
            term.write(text)
              // 重点,肯定要记住存储以后行命令保障下次 up 或 down 时不会光标错乱笼罩终端提示符
            currentLineData = text
    
            last--
          }
        } else if (key === '\u001b[B') {
          //down 键
          let lent = 0
          if (historyLineData.length > 0) {lent = historyLineData.length - 1}
          if (last < lent && last > -1) {for (let i = 0; i < currentLineData.length; i++) {if (term._core.buffer.x > terminalTitleTemplate.length + 1) {term.write('\b \b')
              }
            }
            let text = historyLineData[last + 1]
            term.write(text)
            currentLineData = text
            last++
          }
        } else {
          // 啥也不做的时候就间接输出
          currentLineData += key
          term.write(key)
        }
      })
    }

四. 渲染执行

useEffect(() => {
    //   创立实例
    term.open(document.getElementById('ter'))
    // 初始化
    term._initialized = true

    term.prompt()
    // 进行适应容器元素大小
    term.loadAddon(fitAddon)
    fitAddon.fit()

    term.focus()

   keyAction()
    
          


    return () => {term.dispose()
    }
  }, [])

  return (
    <>
      {/* terminal 装载容器 */}
      <div id="ter" />
    </>
  )

结尾话外题,在写这个的时候就因为应用 up/down 键的时候光标串行且输入命令还串行了。就找了特地久,始终不明确。一开始用的 onKey 来监听键盘操作,onData 来保障粘贴输出汉字。就真的间接错乱。前面发现间接 onData 监听输出就不会如此,不存在这个问题了

退出移动版