网页是否可以在不需要服务器调用的情况下动态插入来自另一个文件的数据 XMLHttpRequest()Plunker

问题描述 投票:0回答:2

网页是否可以在不需要服务器调用的情况下动态插入来自其他文件的数据?

我的意思是.html页面可以用XMLHttpRequest之类的东西更新自己,而不是这样只需要读取一个与html页面位置相同的文件即可调用服务器。

伪代码

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

背景

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

  1. 我需要删除framset因为过时而且不支持html 5
  2. iFrames不是一个合适的替代品,因为它们不是为了展示网站不可或缺的部分内容而设计的,当这样做时它们看起来很奇怪。
  3. 预加载页面的所有内容然后使用javascript来隐藏/显示用户更改选择时文件的内容是不可行的,因为单个html文件太大而且加载速度太慢。
  4. 调用服务器是不可行的,因为没有服务器,报告是由应用程序创建的,然后可以独立查看而不运行应用程序。它们也可以发送给支持以便独立查看。
  5. 我的临时解决方案是,当用户选择文件时,处理html文件显示在新的选项卡(或窗口)中,但用户不是很满意
javascript html5
2个回答
1
投票

如果我正确地阅读你的问题,所有必要的数据在一开始就是页面的一部分(因为你无法从服务器加载它,它必须已经存在 - 但是请参阅下面的行以获取更多信息在那)。但你说过:

预加载页面的所有内容然后使用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是独立的(而大多数将进行服务器调用,但仍然如上所述更新页面)。


你在评论中说过:

目前,文件是在一开始就创建的,主文件夹和文件代表每个文件夹的处理。用户可以处理1000个文件夹,这意味着主文件基本上是1000个文件夹的列表,然后有1000个其他文件,每个文件包含几页数据。很明显,如果我们将所有这些组合成一个文件,它将大约1000倍大,但用户只能查看与一个文件夹相关的处理...所以你上面的方法对我不起作用。

我担心你会尝试吃蛋糕。 :-)您可以稍后加载数据,也可以在一开始就在页面上加载数据。您在问题中说过以后无法加载数据,所以它必须在开头的页面中。

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

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

  • 使用iframes并更新src以从文件到文件。你在问题中说他们“不是为了页面的主要内容”,但这不是我的理解;而且它们很难看,但它们完全可以通过CSS设置出来。它们可以无缝地集成到主页面中。
  • 继续使用框架,更新框架的src以从一个文件移动到另一个文件。是的,frames已在HTML5中删除。它们永远不会从Web浏览器中删除,遗留下来太多。

遗憾的是,当您从XMLHttpRequest网址加载页面时,您无法可靠地使用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
投票

<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。

Demo Outline

  • 主页:index.html,导入页面:data.html
  • 在主页面上,将导入HTML的元素需要: <div data-x="data.html"... 分配data-x属性的任何类型的元素都具有导入的网页的URL的值。


Plunker

的index.html

这个Stack Snippet不起作用,因为它加载了一个外部页面,对于这个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>
© www.soinside.com 2019 - 2024. All rights reserved.