7

我一直在 Electron (Chrome) 和 React 中实现一个聊天客户端。我们的首要任务是速度。因此,我们应该使用虚拟化列表组件(也称为“缓冲渲染”或“窗口渲染”)。我们已经探索了 react-virtualized、react-window 和 react-infinite 等。

所有这些组件的一个共同问题是,如果支持可变高度的列表元素,则需要提前知道高度。现在,有些聊天很长,有些很短,这对我们来说是一个挑战。(由于 EXIF 数据和 ffprobe,图像和视频很容易)。

因此,我们面临着测量高度的挑战,同时还要努力提高性能。一种明显的技术是将元素放在浏览器容器的视口外,执行测量,然后渲染列表。但这在性能要求方面伤害了我们。像 react-virtualized/CellMeasurer (不再由原作者维护)和 react-window 等软件使我们使用了这种技术,内置在库中,但性能有点慢而且不可靠。一个可能更高效的类似想法是使用背景电子浏览器窗口进行渲染和测量,但我的直觉是不会那么快。

我认为必须有一些解决方法来提前计算字符串高度,根据自动换行、最大宽度和字体规则。

我目前的想法是使用像string-pixel-width这样的库,以便在我们通过 API 获取文本数据后立即计算行高。基本上,该库使用这段代码来生成字符宽度 [*] 的映射。然后,一旦我们知道每个文本有多宽,我们就会在计算出的最大行宽达到最大值时将每一行分开,最后通过行数推断列表元素的高度。由于断词,这将需要一些算法摆弄,但有一些库可以帮助解决这个问题 - css-line-break似乎很有希望。

[*] 我们将不得不稍微修改它以考虑所有 Unicode 字符范围,但这是微不足道的。

我尚未完全探索的一些选项包括 python weasyprint 项目和 facebook-yoga 项目。我对你的想法持开放态度!

4

1 回答 1

4

使用画布功能测量文本可以以高效的方式解决此问题。

Electrons 画布文本的计算方式与常规文本相同,但在渲染方面存在一些差异,特别是在抗锯齿方面,但不影响计算

您可以从任何文本中获取 TextMetrics

const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')

// Set your font parameters
// Docs: https://developer.mozilla.org/en-US/docs/Web/CSS/font
ctx.font = "30px Arial";

// returns a TextMetrics object
// Docs: https://developer.mozilla.org/en-US/docs/Web/API/TextMetrics
const text = ctx.measureText('Hello world')

这不包括换行和自动换行,对于这个功能,我建议你使用来自 pixijs 的文本包,它已经使用了这个方法。此外,您可以通过在电子中启用实验性铬 TextMetrics 功能并利用它来分叉源代码(MIT 许可证)并对其进行修改以提高性能。

这可以在创建窗口时完成

new BrowserWindow({
  // ... rest of your window config ...

  webPreferences: {
    experimentalFeatures: true
  }
})

现在到我在评论中提到的部分,因为我不知道你的代码库、你的计算和一切都应该在渲染过程中发生。如果不是这种情况,您绝对应该将代码从主进程移动到渲染进程,如果您执行文件访问操作或任何特定于节点的操作,您仍然应该这样做,但在所谓的预加载脚本中

它是 webPreferences 中的附加参数

webPreferences: {
  preload: path.join(__dirname, 'preload.js')
  experimentalFeatures: true
}

在此脚本中,您无需使用 IPC 调用即可完全访问节点,包括本机节点模块。我不鼓励 IPC 调用任何类型的函数多次调用的原因是它本质上很慢,你需要序列化/反序列化才能使它们工作。electron 的默认行为更糟糕,因为它使用 JSON,除了你使用ArrayBuffers.

于 2019-12-28T13:55:13.963 回答