【问题标题】:How to split the browser viewport into two horizontal panes如何将浏览器视口拆分为两个水平窗格
【发布时间】:2018-07-23 23:31:55
【问题描述】:

在 HTML 4 之前,可以创建带有框架的布局,在不同的窗格中加载不同的 HTML 文件。

我想要做的是实现类似的结果,但加载并在屏幕上显示同一文档的两个不同部分

我的理想范例是 MS Word,它允许将窗口分成 2 个水平部分以显示在同一文档的每个不同部分(在比较文档的不同部分或将部分从远处移动到另一侧时非常有用其他在长文档上)或 MS Excel(甚至 LibreOffice 或 OpenOffice Calc 也有类似的功能)允许出于相同的原因将工作表的窗格拆分为 2 个(甚至 4 个)部分,或者保持顶部的某些行可见或右侧的一些列(例如行或列标题)。

如下图所示:

红色箭头表示将窗口文档分成两部分的装订线,允许单独滚动每个部分,正如您可以看到上窗格中的行数为 3 和下窗格中的 21。排水沟也可以调整大小。

是否可以使用带有 HTML 和 CSS 的 vanilla JS(请不要使用 jQuery 或其他框架)来做到这一点?

约束:

  1. 所有 2 个窗格(顶部和底部)的文档必须相同(旧框架集需要加载两个不同的文档或同一个文档两次:我已经在使用它,但如果可能的话,我想要一个更干净的方法!)
  2. 分隔符(装订线?)必须可调整大小
  3. 文档的两个不同部分完全同步,如果我在顶部(或底部)窗格中修改某些内容(使用contenteditable 属性),底部(或顶部)窗格会立即显示编辑就像 MS Word 或 Excel 一样...所以如果我在任何底部窗格表格单元格中删除某些内容,即使顶部内容也会相应调整(甚至列大小),就像 MS Word、Excel、Calc 等一样。
  4. 点击特定按钮会打开和关闭拆分视图
  5. 我不关心旧浏览器,只关心 ECMA 脚本 2015 或更新版本
  6. HTML 文件有许多事件侦听器,通过 addEventListener() 方法附加到各种 HTML 元素,如按钮、文本框、复选框、选择框等:这意味着回答的解决方案必须能够保持它们的完整性并在两者中工作窗格

我将在哪里使用它?

我在本地 HTML 文件(不涉及 Web 服务器)中有一堆表格,这些表格从 csv 文件或浏览器会话存储中加载数据,我经常需要比较来自不同点的数据或保持标题固定在滚动特定表格的其余部分时,或者在其中一个表格中插入新数据或更新旧数据时,在顶部,以不断查看我在哪个表格单元格中插入或更新数据。

情况:

目前我正在使用以下代码:

function splitView()
{
    var tgtSrc = location.href;
    var frameset =  '<frameset rows="*,*">' +
                        '<frame name="' + upFrame + '" src="' + tgtSrc + '">' +
                        '<frame name="' + dwFrame + '" src="' + tgtSrc + '">' +
                    '</frameset>';
    document.write(frameset);   
}

上述函数将当前窗口窗格水平拆分为两个框架,称为 upFrame 和 dwFrame(它们是两个变量)。拆分后,将在两个框架之间放置一个可调整大小的装订线。

加上同步文档数据的两个实例的算法:它的工作原理是在一个帧中的每次数据编辑时将数据保存到该帧的会话存储中,并将相同的数据重新加载到另一个帧中。

它有点工作,但框架不是要走的路,我想摆脱两次加载文档并同步每个实例以及所涉及的所有相对缺点的需要。所以不幸的是,这不是我正在寻找的最终答案,因为它有一些缺点:

  1. 现代 HTML5 兼容文件不支持 frame 和 frameset 标签,即使浏览器仍然支持它们
  2. 该文件必须加载两次(每帧一次),这意味着性能明显不足并且难以实时同步一帧中的任何编辑与另一帧(可能需要双向同步,因此可以在都显示了文件的一部分)。不幸的是,即使是所需的同步过程也意味着失去在每个同步循环中锁定 UI 的性能
  3. 同步过程不是实时的,它有一些延迟(几秒钟):如果我缩短它,我会严重缺乏性能,包括浏览器冻结

因此,我愿意通过更清洁、更高效的解决方案获得更好的答案。 (我什至建议 Chrome 开发者在浏览器中为其实现一个功能,因为我真的认为这是一个必须具备的功能,特别是考虑到不断扩展的在线数据管理系统。)

我在寻找什么:

我已经使用的上述代码的使用根本不是强制性的:答案也可以提出一种完全不同的方法。

所以我正在寻找的最终解决方案是类似于 Google 电子表格使用的拆分功能(如果可以,我希望我们也可以),这是带有示例的图像 p>

仔细看:有可能水平移动的装订线(也有垂直装订线,但我并不关心垂直分割,只是水平的),当电子表格向下滚动时,行消失在下面它:实际上,排水沟上方的第一行是 n。 1 排水沟的第一行是 n。 45.

还要注意图片最左边的红色大箭头所指示的小双头白色箭头。

我尝试研究 Google 电子表格方法对其进行逆向工程并提取显着特征并将相同的“哲学”适应我的本地应用程序,但我还不足以理解他们做了什么确切地说:我的怀疑是,当“表格行撞到排水沟”时,它只是隐藏在它后面,但我不确定。

恕我直言,这是每个浏览器(甚至是便携式设备的浏览器)都必须在本地实现的功能,并且不使用 html 5 中不再支持的旧框架技术。不幸的是,这种可能性拆分相同文档 来显示和编辑它的不同部分(例如,作为一个非常长的表格)保持每个窗格相互更新,不是(还)浏览器功能,所以同时......它需要一个解决方法.

注意:

CSS 属性

position: sticky;

也可用于解决部分问题(在编辑或将数据插入 tbody 时保持 thead 卡住),但不幸的是,它似乎无法在 thead 元素上按预期工作,至少在某些浏览器上.它也只解决了部分问题:事实上,如果需要将来自同一个表或不同表的不同部分的数据比较到同一个文档中,这个解决方案根本就不好。所以需要别的东西。

【问题讨论】:

  • mac 命令行也可以这样做,非常方便.. 不幸的是,如果不在 2 个 iframe 中两次加载同一页面,我真的看不出有任何方法可以做到这一点。
  • @Iwrestledabearonce。不幸的是,在 2 个 iframe 中两次加载同一页面无法正常工作,因为它们必须保持同步,以防其中一个或另一个发生数据更改。当然,我希望浏览器开发人员能够添加一种简单的方法来执行诸如 window.splitableV = true window.splitableH = true...之类的操作。但与此同时...
  • 我认为构建起来不会太难,但它将是特定于实现的..换句话说,您放入框架的页面必须构建才能进入框架。我认为不会有一个简单的即插即用选项..
  • @Occam'sRazor 具体实现对我来说很好
  • 您将如何更改文档的内容?通过外部编辑器或在浏览器中使用contenteditable 属性或...?

标签: javascript html css window


【解决方案1】:

我认为您可以使用 div 来实现。

首先创建两个 div 来保存上下视图。

然后将主要内容克隆到每个 div。

通过调整每个 div 的尺寸和位置,您可以将一个 div 分成两部分的视图

您也可以创建调整大小的脚本来管理每个视图 div 的高度

用于跨多个视图的级联操作。您可以使用上视图上的事件来对下视图进行更改。 并在下视图上对上视图进行更改。

最后抱歉解释不好。

我做了jsfiddle来解释方法

[1]:https://jsfiddle.net/EmadElpurgy/r9w93zo7/sample code

【讨论】:

  • 抱歉,这不起作用,因为该文件中有很多事件侦听器,这些事件侦听器链接到通过其 HTML ID 获取的 DOM HTML 元素。如果我实施您的答案,复制的内容将被破坏并且没有任何听众。此外,您的代码似乎有问题,因为单击一次拆分按钮是可以的,但单击两次会使两个窗格中的表格消失。窗格也不能通过排水沟调整大小
  • 很抱歉您提到的错误。但我专注于方法。因为我没有建立完整的解决方案。我只是尝试提供可能会有所帮助的想法。祝你好运
【解决方案2】:

我只会部分解决您的问题,因为我没有完整的解决方案。

现代 HTML5 兼容文件不支持 frame 和 frameset 标签,即使它们仍受浏览器支持

Frame 已弃用,取而代之的是 iframe。这应该以几乎相同的方式运行。

为了保证两个窗格之间的同步与您设置的约束,您将不得不编写自定义 JS,尤其是因为您不喜欢框架/包。

【讨论】:

  • 恕我直言,您的回答有些不准确:iframe 和 frame 的行为不同:例如 iframe 没有任何可调整大小的装订线,而 frame 有。 iframe 是一个内部框架,这意味着它嵌套在父元素的主体元素中,而框架是“父”元素,而文档是“嵌套元素”。我同意我将不得不编写自定义 JS
  • @willywonka iframe 中的“i”用于内联,而不是内部。我没有解决可调整大小的排水沟,因为它看起来微不足道并且可以由 CSS 处理。如果你再看一遍,我在描述他们的行为时从未使用过精确的语言。 :)
  • sorry you're right iframe 表示内联框架,谢谢指正。
  • @Samir 如何使用 css 制作排水沟?
【解决方案3】:

只是好奇,如果它是您计算机上的本地文件,为什么您要尝试在浏览器中编辑 csv 文件中的表格数据,而不是仅使用您上面提到的 Excel 等程序的本机功能?或者,如果您想在浏览器中执行此操作,谷歌表格是否允许分屏?没有不尊重我只是不明白为什么不使用专门针对此类工作进行优化的程序。

如果您想继续使用框架,您应该能够将文件重新加载到一个框架中,然后将 innerHTML 从一个框架复制到另一个框架,如下所示。如果您正在使用会话存储,虽然它应该(?)更快地保存对该文件和 csv 文件的编辑,但从会话存储而不是文件加载。

window.frames[upFrame].document.body.innerHTML = window.frames[dwFrame].document.body.innerHTML;

您可以将 DIV 用作容器,而不是使用框架,按照您的建议加载到本地存储中并从那里填充两个 DIV。保存将像框架解决方案一样进入 csv 文件和本地存储。 Javascript 可以跟踪滚动顶部,因此一旦从本地存储重新加载,您就可以将这两个部分“弹出”到它们所在的行。

一个更快的解决方案虽然可能是将 csv 数据保存在内存(数组)中并保存到 csv,但理论上从内存更新会比文件快得多 :)

【讨论】:

  • 嗨 Viking NM,您的好奇心是合法的,没有不尊重:动机是:我喜欢谷歌电子表格为此使用的解决方案,我想了解它是如何工作的,因为它是最接近我的目标。我正在开发一种我希望通过这里的平台和操作系统尽可能便携的应用程序(我也想在桌面系统和便携式设备上使用它),没有限制;出于隐私原因,我还想将数据仅保存在本地驱动器或便携式数据存储驱动器中,例如笔式驱动器。每条记录还附有一个文件,允许不同的格式...
  • ...浏览器可以预览excel没有的附件。现代浏览器还可以打开更多附加文件(每个标签页一个)。此外,并非所有人都在他们的系统或任何电子表格软件上安装了 excel,并非所有人的系统上都有窗口,所以在我看来,html css js 似乎是我想要实现的最通用的解决方案。当然也有一些缺点......另外我认为拆分窗口功能也是浏览器必须具备的,因为在线数据管理解决方案增加了它们的存在......
  • ...即使只是为了在编辑或将数据添加到 tbody 时保持“位置固定”表头:恕我直言,拆分功能是每个浏览器默认必须具备的必备功能,就像 calc 或 excel 或 google 电子表格一样,不依赖于网站自定义非标准实现
  • 另外,我不能使用 div 来制作“虚拟窗格”,因为这样的操作会复制 HTML 元素 ID,破坏一些 js 以在两个“窗格”上正确操作。
  • 我很想试一试。您能否将至少 1 兆字节的随机数据的演示代码片段工作示例实现到具有自动和双向(从任何帧到另一个帧)同步的多列表布局中?所以评估不同浏览器的性能会很有趣。提前致谢。
【解决方案4】:

可能有比我想出的破解方法更好的解决方案,但让我们试一试。

如果您想获取 整个 页面并将其拆分,您可以使用框架集解决方案,但您可以复制其 HTML 并将其写入,而不是让浏览器加载资源两次框架:

<html>
  <head>
    <style type="text/css">
        body { color: red; } /* Only used to test if CSS is copied as well
    </style>
  </head>
  <body>
      Hello world!
  </body>

  <script type="text/javascript">
    function inFrame () {
      try {
    return window.self !== window.top;
      } catch (e) {
        return true;
      }
    }


    function buildFrames() {
      const documentHTML = document.documentElement.innerHTML;

      const frameset = document.createElement('frameset');
      frameset.rows = '*,*';

      const frame1 = document.createElement('frame');
      const frame2 = document.createElement('frame');

      document.documentElement.innerHTML = '<html><body></body></html>';

      frameset.appendChild(frame1);
      frameset.appendChild(frame2);

      document.body.appendChild(frameset);

      frame1.src = 'data:text/html;charset=utf-8,' + encodeURI(documentHTML);
      frame2.src = 'data:text/html;charset=utf-8,' + encodeURI(documentHTML);
    }

    if (!inFrame()) {
        buildFrames();
    }
  </script>
</html>

您需要小心在您的页面内执行的 javascript 代码。如您所见,我还必须检查页面是否尚未在框架内,否则它将永远将框架集附加到文档(或至少直到浏览器阻止它)。

【讨论】:

  • 您好,感谢您的回答。传递给 frame.src = ... 的 URL 或 URI 的字符串长度是否有任何限制?我在其他地方读到浏览器的限制范围在 2kb - 8kb 或多或少。不幸的是,这不行,因为我的场景中的 html + 数据甚至可能超过 1 MB。会导致html文件损坏吗?
  • 根据developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/… - Firefox 支持无限长度,而 Opera 将 data-uri 链接限制为 65535 个字符(不管 data-uri 中的实际内容如何)。至于其他浏览器 - 不幸的是我不知道。
  • 即使 Chrome 也有限制。抱歉,恕我直言,他们太狭窄了
  • 我很想试一试。您能否将至少 1 兆字节的随机数据的演示代码片段工作示例实现到具有自动和双向(从任何帧到另一个帧)同步的多列表布局中?所以评估不同浏览器的性能会很有趣。提前致谢。
  • 还有一个问题:HTML 文件有很多事件侦听器:此解决方案是否将它们保留在两个框架中?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-24
  • 1970-01-01
  • 2013-02-28
相关资源
最近更新 更多