xterm.js+react的综合使用(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装载容器 */}
      
)

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

你可能感兴趣的:(前端)