tl; 博士 我创建了一个 React 包装器来将一组日志消息呈现到终端中,但是调整大小会给出一个奇怪的输出(参见屏幕截图)。(NPM 上有一个 React-Wrapper,但这不适用于我的用例 - 导致屏幕闪烁)
我正在为 Guppy 开发一项功能,我正在为终端输出添加Xterm.js。PR 可以在这里找到。
由于超链接扫描/解析,我添加了 xterm 并且它正在工作。
但我坚持调整大小工作。如果我在应用程序中启动 devServer 并等待一些文本,它将以正确的字母宽度显示。如果我减小尺寸,我会得到一个字母宽度不正确的输出。就像在下面的屏幕截图中一样:
它在未调整大小的状态下总是看起来正确,但在调整大小后会出现错误的显示 - 所以这将发生在放大和缩小屏幕宽度时。
输出应该类似于以下屏幕截图(可能带有一些换行):
我认为这是由Fit 插件或我使用调整大小观察者处理调整大小的方式引起的,但我不确定。
NaNpx
xterm letter 的 span 样式在以下屏幕截图中
的宽度类似于:
这是由我正在使用的媒体查询引起的吗?我还没有看到,也许我必须暂时禁用所有媒体查询,看看这是否导致了这种行为。
到目前为止我已经尝试过:
- 包裹
this.xterm.fit()
成一个setTimeout(func, 0)
但没有效果 - 修改了一些我正在使用的样式,但我没有找到原因。
代码
我正在使用的代码可以在Github 分支 feature-terminal-links上找到,但在这里我想提取我添加的部分以使 Xterm 与 React 一起工作:
- 我创建了一个样式组件
XtermContainer
作为 div,因此我可以添加 Xterm 样式和自己的样式。以下代码在里面render
,将成为我们的 xterm.js 容器(innerRef
稍后将用于使用ComponentDidMount
该容器初始化 Xterm):
<XtermContainer
width={width}
height={height}
innerRef={node => (this.node = node)}
/>
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) ... */
}
- 在也包含终端容器的包装器内添加了react-resize-observer
this.xterm.fit()
,因此我可以在大小更改时触发(在 repo 中有一个setTimeout
用于测试的包装器)。
<ResizeObserver onResize={() => this.xterm && this.xterm.fit()} />
- 如果组件正在获取新日志,则
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 引起的。