如何将浏览器视口拆分为两个水平窗格

wil*_*nka 18 html javascript css window

在HTML 4之前,可以使用在不同窗格中加载不同HTML文件的框架来创建布局.

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

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

如下图所示: 拆分相同的窗口文档example.png

红色箭头表示将窗口文档分成两部分的装订线,允许分别滚动每个部分,如您所见,查看上部窗格中的行数为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()Method 附加到各种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);   
}
Run Code Online (Sandbox Code Playgroud)

上面的函数将当前窗口窗格水平分割为两个帧,称为upFrame和dwFrame(这是两个变量).在分割之后,将可调整大小的沟槽放置在两个框架之间.

加上同步文档数据的两个实例的算法:它通过在一帧中将每个数据编辑保存到该帧的会话存储中并将相同的数据重新加载到另一帧中来工作.

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

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

因此,我愿意用更清洁,更有效的解决方案来获得更好的答案.(我甚至建议Chrome开发人员在浏览器中实现它的功能,因为我真的认为这是一个必备功能,特别是考虑到不断扩展的在线数据管理系统.)

我在找什么:

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

所以我正在寻找的最终解决方案类似于Google Spreadsheet使用的分割功能(如果可以,我希望我们也可以),这是一个带有示例的图像

在此输入图像描述

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

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

我尝试研究Google电子表格方法来对其进行逆向工程并提取显着特征并使相同的"哲学"适应我的本地应用程序,但我不能很好地理解他们做了什么:我怀疑是当"表"时排在排水沟上"只是隐藏在它后面,但我不确定.

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

注意:

CSS属性

position: sticky;
Run Code Online (Sandbox Code Playgroud)

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

sam*_*amu 2

可能有比我想出的黑客更好的解决方案,但让我们尝试一下。

如果您想获取整个页面并将其拆分,您可以使用框架集解决方案,但不必让浏览器加载资源两次,您只需复制其 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>
Run Code Online (Sandbox Code Playgroud)

不过,您需要小心页面内执行的 JavaScript 代码。正如您所看到的,我还必须检查页面是否已经不在框架内,否则它将永远向文档附加框架集(或者至少直到浏览器阻止它为止)。