网页是否可以从另一个文件动态插入数据而无需服务器调用

时间:2019-03-21 07:59:14

标签: javascript html5

网页是否可以在不需要服务器调用的情况下从另一个文件动态插入数据?

我的意思是,.html页面可以使用XMLHttpRequest之类的内容进行自身更新,但是可以仅通过读取与html页面相同位置的文件来代替对服务器的调用。

伪代码

if(userclicks on x)
{
    read and display contents of y within this div)
}

背景

我正在转换一个HTML报告,该报告当前使用一个 frameset 分为左右两个面板。左侧面板列出了一系列已处理的文件夹,右侧显示了对所选文件夹进行的处理。

  1. 我需要删除框架集,因为HTML 5已过时且不受支持
  2. iFrames不是合适的替代方案,因为它们不是为显示网站的组成部分的内容而设计的,完成后,它们看起来很奇怪。
  3. 当用户更改选择内容时,预先加载页面的所有内容然后使用javascript隐藏/显示文件的内容是不可行的,因为单个html文件太大而加载太慢。
  4. 无法调用服务器,因为没有服务器,报告由应用程序创建,然后可以在不运行应用程序的情况下独立查看。它们也可以发送给支持人员以独立查看。
  5. 我的临时解决方案是,当用户选择文件时,正在处理的html文件会显示在新的标签页(或窗口)中,但用户对此并不满意

2 个答案:

答案 0 :(得分:1)

如果我正确阅读了您的问题,则所有必要的数据一开始就是页面的一部分(由于您无法从服务器加载,因此具有< / strong>到所有已经存在的地方-但请参见下面的内容以获取更多信息。但是你说过:

  

当用户更改选择内容时,先加载页面的所有内容然后使用javascript隐藏/显示文件的内容是不可行的,因为单个html文件太大而加载太慢。

因此,这表明数据本身比数据表示形式要小得多。

您当然可以在页面上拥有一个元素(例如,div),并使用DOM通过呈现页面所保存数据的子集来进行更新。这是一个简单的示例:

const data = [
    {label: "one", a: "a one", b: "b one", c: "c one"},
    {label: "two", a: "a two", b: "b two", c: "c two"},
    {label: "three", a: "a three", b: "b three", c: "c three"},
    {label: "four", a: "a four", b: "b four", c: "c four"}
];

function populateMenu() {
    const menu = document.getElementById("menu");
    for (let i = 0; i < data.length; ++i) {
      const entry = data[i];
      const a = document.createElement("a");
      a.href = `#entry-${i}`;
      a.textContent = entry.label;
      a.addEventListener("click", event => {
          event.preventDefault();
          showEntry(entry);
      });
      menu.appendChild(a)
    }
}

function showEntry(entry) {
    const content = document.getElementById("content");
    const {a, b, c} = entry;
    content.textContent = `a: ${a}, b: ${b}, c: ${c}`;
}

populateMenu();
#menu a {
  padding: 4px;
}
<div id="menu"></div>
<div id="content"></div>

它使用ES2015 +语法,但是只有在需要针对目标环境的情况下,才可以对ES5执行相同的操作。

那里的content div当然可以是页面显示的大部分。

这是单页应用程序(SPA)的基本性质,因此使用该术语进行进一步的研究可能会有用。但是您的SPA是独立的(尽管大多数SPA会进行服务器调用,但仍会如上所述更新页面)。


在评论中您说过:

  

当前,文件是在一开始就创建的,有一个主文件夹和一个代表每个文件夹处理的文件。用户可能已经处理了1000个文件夹,这意味着主文件实际上是1000个文件夹的列表,然后还有1000个其他文件,每个文件包含几页数据。因此,很明显,如果我们将所有这些内容合并到一个文件中,则大约要大1000倍,而用户只能看到与一个文件夹相关的处理信息,因此,您的上述方法对我而言不起作用。

恐怕你想吃蛋糕并吃掉它。 :-)您可以稍后再加载数据,也可以一开始就在页面上全部加载。您在问题中说过您以后不能加载数据,因此它必须在一开始就位于页面中。

但是:您在上面使用的“文件”一词表明,没有服务器的此报告可以是文件的集,而不仅仅是单个文件。

如果HTML文件A需要从HTML文件B加载内容,则您的跨浏览器选项为:

  • 使用iframe并更新src以在文件之间移动。您在问题中说过,它们“不是为了页面的主要内容”,但这不是我的理解;而且它们很丑陋,但是可以通过CSS 完全进行样式设置。它们可以从字面上无缝地集成到主页中。
  • 继续使用框架,更新框架的src以在文件之间移动。是的,frames已在HTML5中删除。它们绝对不会从网络浏览器中删除,因为有太多遗留物。

遗憾的是,从XMLHttpRequest URL加载页面时,您无法可靠地使用file:。有些浏览器允许,其他浏览器不允许。 (您不能在其中任何一个中使用fetch,它特别不支持file:方案。)

恐怕您的限制实际上会限制您的选择。

这是一个iframe示例:

report.html

<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<title>Report</title>
<style>
#menu a {
    padding: 4px;
}
#content {
    border: none;
}
</style>
</head>
<body>
<div id="menu">
    <a href="#file-1" data-file="file1.html">File 1</a>
    <a href="#file-2" data-file="file2.html">File 2</a>
    <a href="#file-3" data-file="file3.html">File 3</a>
</div>
<iframe id="content" src="file1.html"></iframe>
<script>
document.getElementById("menu").addEventListener("click", event => {
    event.preventDefault();
    const a = event.target.closest("a");
    document.getElementById("content").src = a.getAttribute("data-file");
});
</script>
</body>
</html>

file1.htmlfile2.htmlfile3.html是相同的,只是名称和数字不同):

<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<title>File 1</title>
</head>
<body>
This is file 1.
</body>
</html>

答案 1 :(得分:1)

<template>

如果文件上有本地内容,请尝试使用<iframe><template>。我们将考虑后者。 <template>是惰性的,浏览器会忽略它,因此无论您的多余内容有多大,这都不是问题。

演示

<!DOCTYPE html>
<html>

<head>
  <title>Page 1</title>
  <style>
    html {
      font: 400 16px/1.5 'Consolas';
      background: #000;
      color: #fc0;
    }
    
    fieldset {
      border-color: goldenrod;
      border-radius: 8px;
    }
    
    input,
    output {
      display: block;
      font: inherit;
    }
    
    [type=submit] {
      float: right;
      background: none;
      color: gold;
      border: 1px solid gold;
      border-radius: 4px;
      margin-top: 4px;
      cursor: pointer;
    }
  </style>
</head>

<body>
  <form id='import'>
    <fieldset>
      <legend>Import data.html by <b>XMLHttpRequest()</b></legend>
      <output id='content'></output>
    </fieldset>
    <input type="submit">
  </form>

  <template id='data'>
<style>{margin: 30px auto}table{table-layout: fixed;border: 3px solid cyan;width: 99%;border-radius: 6px}caption{font-size:1.2rem;color:gold}th{width: 33%;background: rgba(0,11,187,0.3);border: 1px solid rgba(0,11,187,0.7);color:#fc3}td{min-height: 30px;border: 2px ridge cornflowerblue;;color: yellow;background: none}
</style><section><table><caption>DATA</caption><thead><tr><th>TH</th><th>TH</th><th>TH</th></tr></thead><tbody><tr><td>TD</td><td>TD</td><td>TD</td></tr><tr><td>TD</td><td>TD</td><td>TD</td></tr><tr><td>TD</td><td>TD</td><td>TD</td></tr></tbody></table></section>
</template>
  <script>
    document.forms.import.onsubmit = getContent;

    function getContent(e) {
      e.preventDefault();
      const destination = document.querySelector('#content');
      const template = document.querySelector('#data');
      const clone = document.importNode(template.content, true);
      destination.appendChild(clone);
    }
  </script>
</body>

</html>


XMLHttpRequest()

假设与目标网页位于相同域中的单独网页是可行的,则可以使用XMLHttpRequest()从另一个网页(无论是来自服务器还是相同域)导入HTML。

演示大纲

  • 主页: index.html ,导入页面: data.html
  • 在首页上,要导入HTML的元素需要这样做:

      <div data-x="data.html"...
    

    为任何类型的元素分配了data-x属性,并带有导入的网页URL的值。


Plunker

index.html

此堆栈摘录无法正常运行,因为它加载了外部页面,有关有效的演示,请查看此Plunker

<!DOCTYPE html>
<html>

<head>
  <title>Page 1</title>
  <style>
    html {
      font: 400 16px/1.5 'Consolas';
      background: #000;
      color: #fc0;
    }
    
    fieldset {
      border-color: goldenrod;
      border-radius: 8px;
    }
    
    input,
    output {
      display: block;
      font: inherit;
    }
    
    [type=submit] {
      float: right;
      background: none;
      color: gold;
      border: 1px solid gold;
      border-radius: 4px;
      margin-top: 4px;
      cursor: pointer;
    }
  </style>
</head>

<body>
  <form id='import'>
    <fieldset>
      <legend>Import data.html by <b>XMLHttpRequest()</b></legend>
      <output data-x="data.html"></output>
    </fieldset>
    <input type="submit">
  </form>

  <script>
    function xhr(e) {
      e.preventDefault();
      const tags = document.querySelectorAll("*");
      let clone, file, xh;
      for (let i = 0; i < tags.length; i++) {
        if (tags[i].dataset.x) {
          clone = tags[i].cloneNode(false);
          file = tags[i].dataset.x;
          xh = new XMLHttpRequest();
          xh.onreadystatechange = function() {
            if (xh.readyState == 4 && xh.status == 200) {
              clone.innerHTML = xh.responseText;
              tags[i].parentNode.replaceChild(clone, tags[i]);
              xhr();
            }
          };
          xh.open("GET", file, true);
          xh.send();
          return;
        }
      }
    }
    document.forms.import.addEventListener('submit', xhr);
  </script>
</body>

</html>

data.html

这只是导入到index.html的纯网页,有关有效的演示,请查看此Plunker

<style>
  section {
    margin: 30px auto;
  }
  
  table {
    table-layout: fixed;
    border: 3px solid cyan;
    width: 99%;
    border-radius: 6px;
  }
  caption {
    font-size:1.2rem;
    color:gold;
  }
  th {
    width: 33%;
    background: rgba(0,11,187,0.3);
    border: 1px solid rgba(0,11,187,0.7);
    color:#fc3;
  }
  
  td {
    min-height: 30px;
    border: 2px ridge cornflowerblue;;
    color: yellow;
    background: none;
  }
</style>
<section>
  <table>
    <caption>DATA</caption>
    <thead>
      <tr>
        <th>TH</th>
        <th>TH</th>
        <th>TH</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>TD</td>
        <td>TD</td>
        <td>TD</td>
      </tr>
      <tr>
        <td>TD</td>
        <td>TD</td>
        <td>TD</td>
      </tr>
      <tr>
        <td>TD</td>
        <td>TD</td>
        <td>TD</td>
      </tr>
    </tbody>
  </table>
</section>