【问题标题】:Including the rendering of an HTML document into another HTML document包括将 HTML 文档呈现到另一个 HTML 文档中
【发布时间】:2010-10-19 15:48:30
【问题描述】:

我有一个字符串代表一个独立的(和有效的 XHTML 1.0 Strict)HTML 文档,类似于

var html = "<?xml ... <!DOCTYPE ... <html><head><style>...</style></head>
                  <body><table>...</table></body></html>";

此 HTML 文档的正文包含一个表格,其 CSS 样式 在 HTML 文档的头部描述。

我还有另一个 HTML 文档的 DOM 树。 如何将具有正确样式(如 HTML 字符串中所述)的表格的 DOM 树包含到此 DOM 树中?

我对基于 jQuery 的解决方案特别感兴趣。

编辑:更具体地说,我正在谈论的 HTML 字符串示例 嵌入到this XML-document

【问题讨论】:

    标签: javascript jquery html css


    【解决方案1】:

    在同一页面上拥有两个完整的 DOM 树是没有意义的,因此您需要提取出您想要的内容并仅使用它。

    将字符串转换为 jQuery 对象并解析出您需要的内容,如下所示:

    var html = "<html><head><style>...</style></head>
                <body><table>...</table></body></html>";
    
    // Not sure if you are a trying to merge to DOMs together or just
    // trying to place what you want on the page so, I'm going to go
    // with the former as it may be more tricky.
    var other_html = "<html><head><style>...</style></head>
                       <body><!-- some stuff --></body></html>";
    
    var jq_html = $(html);
    var jq_other_html = $(other_html);
    
    var style = jq_html.find('head').find('style');
    var table_and_stuff = jq_html.find('body').html();
    
    jq_other_html.find('head').append(style).end().append(table_and_stuff);
    

    这应该可以做到。将 CSS 插入页面后,浏览器应该会自动识别它。

    注意:
    要让新的 CSS 样式表仅添加新样式而不覆盖当前样式,您必须将表单添加到 head 标签,而不是 添加它。所以,最后一行应该是这样的:

    jq_other_html.find('head').prepend(style).end().append(table_and_stuff);
    

    【讨论】:

    • 谢谢,我有类似的工作。现在的问题是,将 CSS 样式附加到主文档的头部可能会覆盖主文档元素正在使用的某些样式。有没有办法解决这个问题?
    • 是的,您可以“前置”CSS(与我描述的方式相同,但使用“前置(样式)”而不是“附加(样式)”。这样,您拥有的当前 CSS 将覆盖新附加的 CSS 中的 CSS,只有新的 CSS 表提供的新内容才会起作用。记住,CSS 代表“层叠样式表”。意思是,最后列出的最具体的内容都会被使用。
    • 好吧,如果我添加到头部,那么主文档中的现有样式(现在排在最后)可能会覆盖包含位的样式。所以在头部添加任何东西都不是一个好的解决方案。理想情况下,包含的 DOM 树的样式应该是 DOM 树的本地样式,并且没有其他样式应该影响包含的树。这可能吗?
    【解决方案2】:

    与其改进我的其他答案,我宁愿制作一个新答案,因为我基本上需要重新编写它以符合您的要求,而旧答案可能会出于其他原因对人们有所帮助...

    因此,在从您链接到的 XML 中提取 HTML 字符串后,您可以像这样继续使用它:

    // First we'll extract out the parts of the HTML-string that we need.
    var jq_html = $(html_from_xml);
    var style = jq_html.find('head').find('style').html();
    var style_string = style.toString();
    var table_and_stuff = jq_html.find('body').html();
    
    // If you want to place it into the existing page's DOM,
    // we need to place it inside a new DIV with a known ID...
    $('body').append('<div id="new_stuff"></div>');
    $('#new_stuff').html(table_and_stuff);
    
    // Now, we need to re-write the styles so that they only
    // affect the content of the 'new_stuff' DIV:
    styles_array = style_string.split('}');
    var new_styles = '';
    $.each(styles_array,function(i) { 
        if(i<(styles_array.length-1)) { 
            new_styles += "#new_stuff "+styles_array[i]+"}"; 
        }
    })
    $('head').append('<style type="text/css">'+new_styles+'</style>');
    

    这确实应该做到。诀窍是 CSS 将为案例选择最具体的样式。因此,如果您在“newstuff”div 中有&lt;td&gt;,它将从新样式表中获取样式。如果您在“newstuff” div 之外有一个&lt;td&gt;,它将采用旧样式。

    我希望这能解决你的问题。

    【讨论】:

      【解决方案3】:

      我可能错过了重点,但为什么不将字符串加载到 IFRAME 中进行渲染 - 这解决了我拥有两个单独的 DOM 树和两组单独的 CSS 规则的所有问题。

      这段代码可以做到:

      $(function() {
              var $frame = $('<iframe style="width:200px; height:100px; border: 0px;">');
              $('body').html( $frame );
              setTimeout( function() {
                      var doc = $frame[0].contentWindow.document;
                      var $body = $('body',doc);
                      $body.html(your_html);
              }, 1 );
      });
      

      (我从这里提取的:putting html inside an iframe (using javascript)

      那么如果你关心 IFRAME 的大小,你可以这样设置:

      $frame[0].style.height = $frame[0].contentWindow.document.body.offsetHeight + 'px';
      $frame[0].style.width = $frame[0].contentWindow.document.body.offsetWidth + 'px';
      

      【讨论】:

      • 谢谢,这看起来很干净。我需要测试它是否适合我。
      • @HermanD iframe 似乎是显而易见的解决方案......我推测,看似不正确,Kaarel 决定不使用这个。哦,好吧...您认为将内容放入 iframe 有什么缺点吗?就像访问 iframe 的 DOM 而不是仅仅在主 DOM 中增加了访问难度?例如,我认为您不能使用 jQuery 将事件侦听器绑定到 iframe 内的元素。只是一个想法......
      • @KyleFarris - 我认为根据定义,有两个不同的 DOM,保持它而不是弄乱它是最简单的解决方案。但是,这种方法必然存在一些缺点。取决于OP的意图是什么。 IFRAME DOM 当然可以通过 jQuery 访问,但我没有尝试附加事件侦听器。如果日常工作不碍事,可以在今天晚些时候尝试。
      • 错字:offsetwidth -> offsetWidth
      • 好吧,代码示例是从我链接到的另一个答案中借来的——但会尽我所能回答您的问题:(1) 我认为这一定是某种 Javascript 评估顺序的事情。也许是为了跨浏览器兼容性。 IFRAME 的 DOM 元素在实例化后似乎不会立即可用。 (2) 见stackoverflow.com/questions/205853 - 如果你喜欢,你可以删除它们 (3)jQuery 总是返回一个数组,即使是单个元素。
      【解决方案4】:

      将其插入内联框架中。

      使用question I asked earlier,我有这样的解决方案:

      首先,有一个 iframe,有一些 id

      <iframe id="preview" src="/empty.html"></iframe>
      

      然后设置样式:

      iframe#preview
      {
          margin: 30px 10px;
          width: 90%;
          height: 800px;
      }
      

      这是一个将 html 文本插入该框架的函数(使用 jquery)

      function preview( html )
      {
          var doc = $("#preview")[0].contentWindow.document
          var body = $('body',doc)
          body.html( html );    
      }
      

      我用它成功地渲染了 html 的内容,包括它可能包含的任何嵌入式 css。

      【讨论】:

      • 这不是和我一个小时前的回答基本一样吗?
      • 你的回答甚至引用了你自己的问题,和我的一样scratches head
      • 是的,除了它更干净(我认为)更直接=P
      • 谢谢。虽然理想情况下我不想为这些 iframe 分配 ID,也不想设置它们的大小和边距。我有多个要包含的 HTML 字符串,并且包含它们的位置最初不存在,它们也是动态生成的。
      【解决方案5】:

      这里有一些测试代码演示了我将如何做到这一点。该代码从传递的 HTML 中提取 &lt;style&gt; 元素,并将自定义 ID 添加到所有选择器,然后将 HTML 注入具有该 ID 的 &lt;div&gt;。这样,HTML 传递的所有 CSS 将仅适用于注入的表:

      <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
      <html xmlns="http://www.w3.org/1999/xhtml">
      <head>
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
      <title>Untitled Document</title>
      <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
      <script type="text/javascript">
      $(document).ready(function() {
          var html = '<?xml version="1.0" encoding="UTF-8"?>\n\
          <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\n\
          <html xmlns="http://www.w3.org/1999/xhtml">\n\
          <head>\n\
          <title></title>\n\
          <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>\n\
          <style type="text/css">\n\
          div.dom { background-color: #ace; margin-bottom: 0.5em } table.drs { font-family: monospace; padding: 0.4em 0.4em 0.4em 0.4em; border: 1px solid black; margin-bottom: 2em; background-color: #eee; border-collapse: collapse }\n\
          td { vertical-align: top; padding: 0.3em 0.3em 0.3em 0.3em; border: 1px solid black }\n\
          td.op { vertical-align: middle; font-size: 110%; border: none }\n\
          </style>\n\
          </head>\n\
          <body><table class="drs"><tr><td><div class="dom">[]</div></td></tr></table></body>\n\
          </html>';
      
          var style = html.match(/<style([^>]*)>([^<]*)<\/style>/);
          var modifiedStyle = style[2].replace(/\s*(} |^|\n)\s*([^{]+)/g, " $1 #inserthere $2");
      
          $(document).find('head').prepend("<style" + style[1] + ">" + modifiedStyle + "</style");
          $("#inserthere").append($(html).children());
          });
      </script>
      </head>
      <body>
      <div id="inserthere">
      </div>
      </body>
      </html>
      

      显然,您必须根据自己的情况进行修改,但这是一个起点。

      【讨论】:

        【解决方案6】:

        这是我的代码,符合您的描述。 有两点需要注意

        1. 由于某种原因,find() 在我从 jquery 对象获得的“on-the-fly”dom 上不起作用,可能有人可以找出我在那里做错了什么
        2. 出于说明目的,我已将此新 dom 附加到“body”元素。您可以轻松地将其附加到您的第二个 dom

           var insertStr = "your string here";
        
           var newDom = $(insertStr); // getting [meta style table.drs]
        
           // I had to use the array as newDom.find would not work for me which I was expecting would work
           var styleText = $(newDom[1]).text();
           var tableElm = $(newDom[2]);
           $(newDom[2]).appendTo('body');
        
           var selectors = styleText.split(/{[\s\w\.\(\)':;"#%=/-]*}/);
        
           var styles = styleText.match(/{[\s\w\.\(\)':;"#%=/-]*}/g);
        
        
        
           for ( var i =0; i < styles.length; i++ ) {
               var style = styles[i];
        
               style = style.replace("{","");
        
           style = style.replace("}","");
        
           if ( selectors[i].indexOf("table.drs") > -1 ) { // identify top-level elm
               // apply to self
               tableElm.attr('style',style);
        
           } else {
        
               // apply to its children
               tableElm.find(selectors[i]).attr('style',style);
        
           }
        

        }

        【讨论】:

          猜你喜欢
          • 2013-07-28
          • 2023-03-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-01-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多