AWo*_*olf 5 javascript css reactjs xtermjs
tl;dr 我创建了一个 React 包装器来将日志消息数组渲染到终端中,但调整大小会产生奇怪的输出(参见屏幕截图)。(NPM 上有一个 React-Wrapper,但它不适用于我的用例 - 导致屏幕闪烁)
我正在为 Guppy 开发一项功能,其中我为终端输出添加Xterm.js 。该 PR 可以在这里找到。
由于超链接扫描/解析,我添加了 xterm,并且它正在工作。
但我一直坚持调整大小才能工作。如果我在应用程序中启动 devServer 并等待一些文本,它将以正确的字母宽度显示。如果减小尺寸,我会得到字母宽度不正确的输出。就像下面的截图一样:

在未调整大小的状态下它看起来总是正确的,但调整大小后它会得到错误的显示 - 因此放大和缩小屏幕宽度时会发生这种情况。
输出应类似于以下屏幕截图(可能带有一些换行):

我认为这是由Fit 插件或我使用调整大小观察器处理调整大小的方式引起的,但我不确定。
xterm 字母的跨度样式的宽度NaNpx如下图所示:
这是由我正在使用的媒体查询引起的吗?我还没有看到这一点,也许我必须暂时禁用所有媒体查询,看看这是否导致了这种行为。
到目前为止我已经尝试过:
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)}
/>
Run Code Online (Sandbox Code Playgroud)
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) ... */
}
Run Code Online (Sandbox Code Playgroud)
this.xterm.fit()该包装器也包含终端容器,这样我就可以在大小发生变化时触发(在存储库中有一个setTimeout用于测试的包装器)。<ResizeObserver onResize={() => this.xterm && this.xterm.fit()} />
Run Code Online (Sandbox Code Playgroud)
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;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
我的想法必须找到原因:
更新
好的,可能不需要调整大小观察者,因为在注释掉渲染后我得到了相同的行为<ResizeObserver/>。所以我认为这是由 xterm.js 或 Guppy 中的 css 引起的。
我有一个解决这个问题的方法。它现在正在上述功能分支中工作。不确定是否有更好的解决方案,但它对我有用。
我想解释一下我是如何解决调整大小问题的:
问题在于OnlyOn中使用的组件DevelopmentServerPane。它总是呈现两个TerminalOutput组件。一个终端被隐藏display: none,另一个终端被显示display: inline- 样式更改是通过样式组件内的媒体查询来处理的。
替换为OnlyOn后React-responsive并使用 render props 检查mdMin断点后,它按预期工作。React-responsive 正在从 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>
);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
12559 次 |
| 最近记录: |