tl; dr 我已经创建了一个React包装器,以将一系列日志消息呈现到终端中,但是调整大小给出了一个奇怪的输出(请参见屏幕截图)。 (NPM上有一个React-Wrapper,但在我的用例中不起作用-导致屏幕闪烁)
我正在为Guppy开发一项功能,其中我在终端输出中添加了Xterm.js。 可以在here中找到PR。
由于超链接扫描/解析,我添加了xterm,并且有效。
但是我一直坚持调整大小才能正常工作。如果我在应用程序中启动devServer并等待一些文本,它将以正确的字母宽度显示。 如果减小尺寸,则会得到字母宽度不正确的输出。 如以下屏幕截图所示:
在未调整大小的状态下,它始终看起来正确,但是在调整大小后,它将显示错误的显示-因此,这会放大和缩小屏幕宽度。
输出应类似于以下屏幕截图(可能带有一些换行):
我认为这是由Fit addon引起的,或者是我使用调整大小的观察器处理调整大小的方式引起的,但是我不确定。
xterm字母的跨度样式的宽度为NaNpx
,如以下屏幕截图所示:
这是由我使用的媒体查询引起的吗?我还没有看到,也许我必须暂时禁用所有媒体查询,以查看是否是这种行为。
到目前为止,我已经尝试过:
this.xterm.fit()
包装为setTimeout(func, 0)
,但没有效果我正在使用的代码可以在Github branch 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) ... */
}
this.xterm.fit()
(在仓库中有一个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;
}
}
}
}
想法,我必须找到原因:
更新
好的,可能不需要调整大小的obeserver,因为注释掉渲染中的<ResizeObserver/>
后,我得到了相同的行为。因此,我认为这是由xterm.js或Guppy中的CSS引起的。
答案 0 :(得分:1)
我已解决此问题。现在可以在上述功能分支中使用。不确定是否有更好的解决方案,但对我有用。
我想解释一下我如何解决调整大小的问题:
问题是OnlyOn
中使用的DevelopmentServerPane
组件。它始终呈现两个TerminalOutput
组件。一个终端被display: none
隐藏,另一终端被display: inline
显示-样式更改是通过样式组件内部的媒体查询来处理的。
将OnlyOn
替换为React-responsive,并使用渲染道具检查mdMin
断点后,它工作正常。反应响应式正在从DOM中删除未显示的mediaquery组件,因此在DOM中只能同时有一个终端。
我仍然不知道为什么字母宽度有问题,但是两个实例可能以某种方式发生了冲突。我无法创建最小的复制品。我试图在此Codesandbox中重新创建问题,但是一次只调整了一个终端的大小,所以我没有那里的问题。
解决该问题的代码(上述存储库的简化版本):
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>
);