javascript - 如何正确调整 Xterm.js 的大小?

标签 javascript css reactjs xtermjs

长话短说 我创建了一个 React 包装器来将一组日志消息呈现到终端中,但调整大小会产生奇怪的输出(请参见屏幕截图)。 (NPM 上有一个 React-Wrapper,但它不适用于我的用例 - 导致屏幕闪烁)

我正在为 Guppy 开发一项功能,我在其中添加了 Xterm.js用于终端输出。 可以找到PR here .

由于超链接扫描/解析,我已经添加了 xterm,并且可以正常工作。

但我一直坚持调整大小才能工作。如果我在应用程序中启动 devServer 并等待一些文本,它将以正确的字母宽度显示。 如果我减小尺寸,我得到的输出字母宽度不正确。 就像下面的截图: Messed output

它在未调整大小的状态下总是看起来正确,但在调整大小后它会得到错误的显示 - 所以这会发生在放大和缩小屏幕宽度时。

输出应该类似于下面的截图(可能有一些换行): Correct output

我认为这是由 Fit addon 引起的或者我使用调整大小观察器处理调整大小的方式,但我不确定。

xterm 字母的跨度样式的宽度为 NaNpx就像下面的截图: CSS with width NaNpx 这是由我使用的媒体查询引起的吗?我还没有看到,也许我必须暂时禁用所有媒体查询以查看是否是导致该行为的原因。

到目前为止我尝试了什么:

  • 包装this.xterm.fit()进入setTimeout(func, 0)但没有效果
  • 修改了一些我正在使用的样式,但我还没有找到原因。

代码

我正在使用的代码可以在 Github branch feature-terminal-links 上找到但在这里我想提取我为使 Xterm 与 React 一起工作而添加的部分:

  1. 我创建了一个样式组件 XtermContainer作为一个 div,所以我可以添加 Xterm 样式和自己的样式。以下代码在render里面并将成为我们的 xterm.js 容器(innerRef 稍后将在 ComponentDidMount 中使用以使用该容器初始化 Xterm):
<XtermContainer
    width={width}
    height={height}
    innerRef={node => (this.node = node)}
/>
  1. componentDidMount 中初始化 xterm使用上面的容器:
componentDidMount() {
    Terminal.applyAddon(webLinks);
    Terminal.applyAddon(localLinks);
    Terminal.applyAddon(fit);

    this.xterm = new Terminal({
      convertEol: true,
      fontFamily: `'Fira Mono', monospace`,
      fontSize: 15,
      rendererType: 'dom', // default is canvas
    });

    this.xterm.setOption('theme', {
      background: COLORS.blue[900],
      foreground: COLORS.white,
    });

    this.xterm.open(this.node);
    this.xterm.fit();

    /* ... some addon setup code here (not relevant for the problem) ... */
}
  1. 已添加 react-resize-observer在也包含终端容器的包装器内部,因此我可以触发 this.xterm.fit()如果大小发生变化(在 repo 协议(protocol)中有一个 setTimeout 包装用于测试)。
<ResizeObserver onResize={() => this.xterm && this.xterm.fit()} />
  1. 使用 componentDidUpdate(prevProps, prevState)如果组件正在获取新日志,则更新终端并将终端滚动到底部:
componentDidUpdate(prevProps, prevState) {
    if (prevProps.task.logs !== this.state.logs) {
      if (this.state.logs.length === 0) {
        this.xterm.clear();
      }
      for (const log of this.state.logs) {
        /*
        We need to track what we have added to xterm - feels hacky but it's working.
        `this.xterm.clear()` and re-render everything caused screen flicker that's why I decided to not use it.
        Todo: Check if there is a react-xterm wrapper that is not using xterm.clear or 
              create a wrapper component that can render the logs array (with-out flicker).
        */
        if (!this.renderedLogs[log.id]) {
          this.writeln(log.text);
          this.xterm.scrollToBottom();
          this.renderedLogs[log.id] = true;
        }
      }
    }
}

我要找原因的思路:

  • 检查 ResizeObserver 代码。(请参阅下面的更新)
  • 尝试找出 xterm css 宽度为 NaN 的原因。 Xterm.js 是否使用容器的样式宽度?如果是,则可能设置不正确。

更新

好的,可能不需要调整大小的观察服务器,因为我在注释掉 <ResizeObserver/> 后得到了相同的行为。在渲染中。所以我认为这是由 xterm.js 或 Guppy 中的 css 引起的。

最佳答案

我已经解决了这个问题。它现在在上述功能分支中工作。不确定是否有更好的解决方案,但它对我有用。

我想解释一下我是如何解决调整大小问题的:

问题出在 DevelopmentServerPane 中使用的 OnlyOn 组件。它总是呈现两个 TerminalOutput 组件。一个终端使用 display: none 隐藏,另一个终端使用 display: inline 显示 - 样式更改是通过 styled-component 中的媒体查询处理的。

OnlyOn 替换为 React-responsive 后并使用渲染 Prop 检查 mdMin 断点是否按预期工作。 React-responsive 正在从 DOM 中删除未显示的媒体查询组件,因此 DOM 中同时只有一个终端。

我仍然不知道为什么字母宽度有问题,但可能这两个实例以某种方式发生了冲突。我无法创建最小的复制品。我试图在此 Codesandbox 中重现该问题但我一次只调整了一个终端的大小,所以我没有遇到问题。

修复问题的代码(上述 repo 的简化版本):

import MediaQuery from 'react-responsive';

const BREAKPOINT_SIZES = {
  sm: 900,
};

const BREAKPOINTS = {
  mdMin: `(min-width: ${BREAKPOINT_SIZES.sm + 1}px)`,
};

const DevelopmentServerPane = () => (
  <MediaQuery query={BREAKPOINTS['mdMin']}>
    {matches =>
      matches ? (
        <div>{/* ... render Terminal for matching mdMin and above */}</div>
      ) : (
        <div> {/* ... render Terminal for small screens */}</div>
      )
    }
  </MediaQuery>
);

关于javascript - 如何正确调整 Xterm.js 的大小?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55322629/

相关文章:

javascript - 如何将数据从可观察的主题推送到组件中的数组?

html - 聚合物-进纸 float 标签颜色

javascript - 如何保护我对 Devise/CanCan/JavaScript 的使用?

javascript - 特征标签上的 OpenLayers 矢量层 z 排序

html - IE浏览器检查条件语句

javascript - Spread 运算符无法与 setState 一起使用(React、Typescript 和 Material-ui)

javascript - 通过 qwest 的 REST Firebase 请求

reactjs - 我需要将浏览器路由器一分为二

javascript - DIV中的滚动音频

css - C# MVC - 渲染部分不加载 CSS