Возможно ли для веб-страницы динамически вставлять данные из другого файла без необходимости обращения к серверу? - PullRequest
0 голосов
/ 21 марта 2019

Возможно ли для веб-страницы динамически вставлять данные из другого файла без необходимости обращения к серверу?

Под этим я подразумеваю, что .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 ]

1 голос
/ 21 марта 2019

<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 ()

Предполагая, что возможна отдельная веб-страница в том же домене, что и целевая веб-страница, можно импортировать HTML с другой веб-страницы (с сервера или из того же домена) с помощью XMLHttpRequest ().

Демо-план

  • Главная страница: 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>
1 голос
/ 21 марта 2019

Если я правильно читаю ваш вопрос, все необходимые данные изначально являются частью страницы (поскольку вы не можете загрузить ее с сервера, она имеет чтобы все уже были там - но смотрите под строкой ниже для получения дополнительной информации об этом).Но вы сказали:

Невозможно предварительно загрузить все содержимое страницы, а затем использовать 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, являются:

  • Используйте iframe s и обновите src для перехода от файла к файлу.Вы сказали в вопросе, что они «не для основного содержания страницы», но это не мое понимание;и что они уродливы, но они полностью , стилизованные через CSSОни могут быть буквально интегрированы в главную страницу.
  • Продолжайте использовать фреймы, обновите src фрейма для перехода от файла к файлу.Да, frames были удалены в HTML5.Они никогда не будут удалены из веб-браузеров, слишком много устаревших.

К сожалению, вы не можете надежно использовать XMLHttpRequest, когда ваша страница загружена с file: URL.Некоторые браузеры позволяют это, другие нет.(Вы не можете использовать 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.html (file2.html и file3.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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...