如何在一个页面上高效地拥有多个只读的Monaco Diff视图?

9
我的理解是Monaco专为编辑优化,仅显示一个文件,并带有自己的滚动条。相反,我想构建一个页面,将多个文件的差异显示在彼此下面:
- 允许显示/隐藏每个文件,最多可达约100个文件。 - 隐藏未更改的文件部分(如果需要,可以作为上下文显示)。 - 不是每个文件都拥有自己的滚动条,而是整个页面只有一个滚动条。 - 文件通常仅用于查看,但是应支持一次编辑一个文件。
我意识到这与Monaco的设计目的大不相同,但最终似乎使用相同的视口和虚拟渲染技巧也可以实现,所以这是否可能呢?
我尝试为每个文件创建一个Monaco实例,但当实例数量超过30时,性能开始变得非常缓慢。
另一个比较丑陋的解决方法可能是拥有单个Monaco实例,将所有文件都连接起来,然后使用ViewZones、自定义行号提供程序和代码折叠提供程序来实现多个文件的效果。这听起来像是疯了吗?还是说这实际上可以实现?
还有其他建议吗?为什么IStandaloneDiffEditor中有“standalone”这个词?这是否意味着有一种更有效的方法来创建多个差异编辑器呢?
1个回答

8

引用您的问题: 我尝试为每个文件创建一个 Monaco 实例,但是在大约 30 个实例时会变得非常缓慢。

您的问题的解决方案

正如您所提到的,性能很低下。这是因为您的服务器或客户端没有足够的内存。您需要为服务器或客户端添加更多内存以获得更好的性能。因为我没有足够的信息,所以我无法确定是服务器还是客户端的问题。但是这种方法是不高效的。

引用您的问题: IStandaloneDiffEditor 在名称中有“standalone”一词的原因是什么?是否有其他更有效的方法来创建多个 diff 编辑器?

这与此无关。在维基百科中,我找到了“standalone”一词的含义:

独立软件可以指:

  • 可以离线工作的计算机软件,即无需网络连接即可运行。
  • 不是一些捆绑软件的一部分的软件。
  • 作为单独计算机进程运行的程序,而不是现有进程的附加组件。
  • 独立程序,不需要操作系统的服务即可运行。
  • 便携式应用程序,可以在不需要安装过程的情况下运行。

这意味着“standalone”与单个实例无关,您可以拥有此编辑器的多个实例。但是,您需要在计算机上拥有更多内存才能从此编辑器创建 100 个实例。这不是高效的,因为您的内存中有 100 个大型 JavaScript 对象。

在其他显示更改文件之间的差异的服务中,他们仅使用 DOM 对象或使用 DOM 对象 + 一个大的 JavaScript 对象实例来创建这些对象,而不是额外的 100 个大的 JavaScript 对象实例。

根据这个原则,在这种情况下,您可以使用下面我推荐的解决方案中的代码,并在后台仅创建此差异编辑器的一个实例。然后,您必须将所有 100 个文件依次放入此实例中,并在每种情况下从一个文件复制以下 DOM 对象:

  • <div class="editor original showUnused" ...
  • <div class="editor modified showUnused" ...

例如,您可以使用以下代码执行此操作:

var diffPartContainars = document.querySelector('#container').querySelectorAll('.showUnused'),
    editorOriginalPartHTML,
    editorModifiedPartHTML;

for(var i = diffPartContainars.length; i--;)
{
    var obj = diffPartContainars[i],
        cln = obj.className;

    if(cln.indexOf('editor original') > -1)
    {
        obj.removeAttribute('style');
        editorOriginalPartHTML = obj.outerHTML;
    }
    if(cln.indexOf('editor modified') > -1)
    {
        obj.removeAttribute('style');
        editorModifiedPartHTML = obj.outerHTML;
    }
}

然后您需要从每个editorOriginalPartHTML和editorModifiedPartHTML中删除以下DOM对象:

  • <div class="invisible scrollbar horizontal" ...
  • <canvas class="decorationsOverviewRuler" ...
  • <div class="visible scrollbar vertical" ...

以及您无法使用的所有其他对象。当您将editorOriginalPartHTML和editorModifiedPartHTML添加到DOM时,可以执行此操作。然后,您可以在每个对象周围添加一个div对象,具有适当的宽度,高度和style ="overflow:auto"。还有一件事情可以做:对于这些div对象中的每个对象,您可以添加一个onclick或onmouseover监听器,然后将此div对象视图替换为差异编辑器实例。

在我看来,这只是更有效率的一种方式。祝你好运!

推荐的高效解决方案

快速、舒适且高效的方法是仅有一个此编辑器实例并在单击文件名时加载新源代码,如下所示。

var diffEditor = null;
var filesContent =
{
    'SomeJavaScriptFile.js':
    {
        originalContent: 'alert("heLLo world!")',
        modifiedContent: 'alert("hello everyone!")',
        type: 'text/javascript'
    },
    'AnotherJavaScriptFile.js':
    {
        originalContent: 'function open(str)\n{\n\talert(str)\n}',
        modifiedContent: 'function output(value)\n{\n\tconsole.log(value)\n}',
        type: 'text/javascript'
    }
};

document.querySelector('#files').addEventListener('change', function(e)
{
    var fileName = this.options[this.selectedIndex].text,
        file = filesContent[fileName];

    openInDiffEditor(file);
});

function openInDiffEditor(file)
{
    if(!diffEditor)
        diffEditor = monaco.editor.createDiffEditor(document.querySelector('#container'));

    diffEditor.setModel({
        original: monaco.editor.createModel(file.originalContent, file.type),
        modified: monaco.editor.createModel(file.modifiedContent, file.type)
    });
}

//open the first file in select list:
var firstFileName = document.querySelector('#files').options[0].text;
openInDiffEditor(filesContent[firstFileName]);

<p>Please select one file on the left list to see the file differences after changes.</p>
<select id="files" size="3">
    <option selected>SomeJavaScriptFile.js</option>
    <option>AnotherJavaScriptFile.js</option>
</select>

<div id="container" style="height:100%;"></div>

你需要通过 AJAX 加载文件内容。如果你不知道如何加载,请问我,我会为你编写。

推荐解决方案的截图

enter image description here


感谢您的详细解释。然而,那不是我想要的用户体验。我想要更像Github的Pull Request>文件视图,将多个文件依次显示在同一页下方。无论如何,还是非常感谢! - Ole
@Ole,也许今天是你的幸运日,或者更多地是我的幸运日,但我有一个好主意解决你的问题。请查看我的更新答案。 - Bharata
抱歉,我正在度假。感谢您为此付出了如此多的工作。在Monaco渲染后复制DOM可能会起作用,并且可能会使CPU使用量保持稳定(我稍微研究了一下性能,我的机器还有很多内存,但其中一个核心被限制在100%-似乎Monaco并没有充分利用其他核心)。我一直希望有一些更低级别的API可以让我处理多个文件,而不必自己进行DOM复制等操作,但显然没有。再次感谢您的建议。 - Ole

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接