让插入到 innerHTML 中的 script 跑起来

  让插入到 innerHTML 中的 script 跑起来

在做 ajax 编程时,我们常常需要将 xmlhttp 获取到的页面内容通过 innerHTML 来赋给某个容器(比如 div、span 或者 td 等),但是这里存在一个问题,就是我们将要赋给 innerHTML 的页面内容如果包含有脚本程序,这些脚本程序不管是外部脚本,还是内部脚本,可能都不会被执行。这个问题在某些时候微不足道,甚至可以忽略,但有些时候,这个问题就非常严重,它很可能让我们的程序得不到预期的结果。因此我们需要解决这个问题。

如果你读过 MSDN,你会发现并非所有插入到 innerHTML 中的脚本都不能执行,如果这段脚本的 script 标签中包含了 defer 属性,IE 会正确的执行这些脚本程序。但不幸的是,Moziila/Firefox 和 Opera 可不吃这一套,不管 script 标签有没有设置 defer 属性,这些浏览器都不会向 IE 那样去执行插入到 innerHTML 中的脚本。

但不管脚本是否被执行了,有一点我们可以肯定,那就是这些脚本确实被插入到了 innerHTML 中,如果不相信,你可以 alert 一下看看。但如果你真的 alert 了,你也可能会发现有一种例外情况存在,那就是如果脚本在 innerHTML 内容开头的话,那么 IE 浏览器将会忽略掉这段脚本,而 Moziila/Firefox 和 Opera 却不会。

好了,问题分析的差不多了,我们来看看如何解决吧。

解决的思路其实很简单,那就是将插入到 innerHTML 中的所有脚本取出来,然后一一执行。不过我们先要解决上面的两个问题。

先来看第一个问题,如何避免在 IE 中重复执行 innerHTML 中带有 defer 属性的脚本。这个很容易,只需要先确定浏览器是否是 IE,然后再检测将要执行的脚本是否带有 defer 属性即可。需要注意的是,在判断 IE 浏览器时,我们需要避免被 opera 的浏览器识别欺骗。这一点我们在后面的代码中将会看到它是如何做的。

接下来,看 IE 忽略 innerHTML 开头脚本的问题,这个也很容易解决。只需要在要插入到 innerHTML 中的内容的开头附加一段不是脚本的内容,就可以了。但不要试图附加一个空内容的标签,或者空格、回车、换行等,这将不起作用,开头的脚本仍然会被忽略。也不要试图附加  ,虽然这可以让开头的脚本不再被忽略,但这个   仍然会影响原有内容的显示,虽然你可能觉得不明显,但是对于挑剔的用户来说,这可能是无法容忍的。因此,为了让附加的内容既可以起到避免开头脚本被忽略的功能,又不会造成不良影响,我们将附加这么一段内容:

< span style = " display: none " > hack ie </ span >

虽然上面这段内容有一定的长度,但是它并不会显示,而且这个插入的标签没有 id 也没有 name,所以也不会跟原来内容中的某些标签的 id 或者 name 产生冲突。不过这里有一点要注意,这里也要判断是否是 IE,然后再决定加不加这段内容,因为其他某些浏览器可能不支持 display: none 这个 CSS 修饰(例如 Opera Mini),如果加上这段代码会影响最终的显示效果。

下面我们来看看如何取出脚本并执行。

取出脚本很容易,只需要用 innerHTML 所在对象的 getElementsByTagName 方法就可以了,这个方法对几乎所有的容器标签都管用。取出脚本以后,我们要一一判断它们是外部脚本还是内部脚本。

先来看外部脚本,如果是外部脚本,我们选择了这样一种方法,即先创建这个外部脚本的一个副本对象,并设置它的 defer 属性为 true(这一点是为了让 IE 浏览器能正确执行),然后用 appendChild 方法将这个副本对象插入到 head 中。这里你可能会问,为什么不是插入到 innerHTML 所在的对象中呢?插入到 innerHTML 所在的对象中不是更好吗?如果你试一下就会知道,如果插入到 innerHTML 所在的对象中,在 IE 浏览器中没有问题,但是在 Mozilla/Firefox 和 Opera 浏览器中会有一些问题。问题是如果在 Firefox 上这样做,浏览器会停止响应(这是在 Firefox 1.5 上的测试结果,其他版本是否有此问题,尚不得知),而在 Opera 上,脚本会莫名其妙的执行两次(这是在 Opera 8.5 上的测试结果,其它版本的 Opera 是否由此问题,也尚不得知)。为了避免这些问题,所以我选择了插入到 head 中。

再来看内部脚本,内部脚本的内容我们可以直接用脚本对象的 text 属性来获取,这里我们使用脚本对象的 text 属性而不是 innerHTML 属性,是因为在 Opera 浏览器中,脚本对象的 innerHTML 属性是空的,只有用 text 属性才能获取到脚本内容。执行内部脚本直接用 eval 即可。但是脚本可能会被包含在 HTML 的注释标签中,因此我们需要先将注释标签去掉,不然在 IE 中会出错。

上面的分析看上去很完美了,但是实际上还是有问题,一个是 document.write 和 document.writeln 的问题,这个问题在 Blueidea 上,bound0 给出了一个思路,就是替换掉默认的 document.write 和 document.writeln 方法,不过他用的是字符串替换,因此只对内部脚本有效,对外部脚本就没办法了,因此我想了个更通用的办法,就是直接把 document.write 和 document.writeln 重新定义,这样不管内部脚本还是外部脚本执行的就都是我们我们自己定义的 document.write 和 document.writeln 了。不过也有副作用,就是这两个函数在当前页面中就不能再像原来一样使用了,不过这两个函数在页面加载完之后一般是不会再用到了,因此这里重新定义它们所带来的副作用影响很小。但是还有个问题是,尽管这样,我们仍然无法保证 document.write 或 document.writeln 输出的内容会显示在最合适的位置,它只是把内容附加到了我们放置内容的容器中。

另一个问题是 eval 引起的问题,一个是 Blueidea 上的 hutia 说的作用域的问题,另一个问题是如果用 eval 执行的内部脚本的话,内部脚本会在外部脚本加载完之前就开始执行了。要解决这个两个问题可以采用 window.setTimeout 这个函数,让每个脚本都延时一段后再执行,外部脚本延时时间可以设的较长,以保证其能够完全加载,而内部脚本则可以设置为很短,因为一个脚本执行的时间通常是很短的,这样既可以保证不会改变作用域,又可以基本保证脚本执行顺序不会改变了(这种方法对于保证执行顺序上也不一定会 100% 有效,如果网络非常繁忙,外部脚本可能在设置的时间内加载不完,但至少比直接用 eval 的时候好多了)。

### 回答1: 可以在使用highlight.js之前先对代码进行处理去除多余的缩进。可以使用javascript的replace()方法将每一行前面的缩进都去掉。 具体代码如下: ``` var code = document.getElementById("code").innerHTML; code = code.replace(/^\s+/gm, ""); document.getElementById("code").innerHTML = code; ``` 在这段代码中,首先通过getElementById()方法获取到代码所在的标签,再使用replace()方法将其中每一行前面的缩进都替换为空字符。最后再将处理后的代码重新赋值给标签。 ### 回答2: 在使用highlight.js时,如果code标签前面有很多缩进,导致高亮的代码跑到展示框的右边,可以通过以下方法解决: 首先,在需要使用highlight.js的页面中添加CSS样式,将code标签的padding设置为0,并设置white-space属性为pre-wrap。这样可以去除代码块前面的缩进,并保持代码在展示框内部显示。 ```css <style> code { padding: 0; white-space: pre-wrap; } </style> ``` 接下来,在使用highlight.js的代码块中加入自定义的CSS类名,例如"code-highlight": ```html <pre><code class="code-highlight"> <!-- 在此处插入需要高亮的代码 --> </code></pre> ``` 最后,使用highlight.js的JavaScript库来对该代码块进行高亮处理: ```html <script src="path/to/highlight.min.js"></script> <script> // 引入其他需要高亮的语言库 hljs.registerLanguage('language', languageModule); // 对所有带有class="code-highlight"的代码块进行高亮处理 document.querySelectorAll('code.code-highlight').forEach((block) => { hljs.highlightBlock(block); }); </script> ``` 通过上述方法,将代码块前面的缩进去除,并保持高亮的代码在展示框内显示,解决了高亮代码跑到展示框右边的问题。 ### 回答3: 在使用highlight.js时,code标签前面出现很多的缩进是由于使用了pre标签或某个父级容器添加了额外的缩进或样式。这个问题可以通过设置CSS样式来解决。 首先,要确保代码嵌套在正确的HTML结构中。需要使用pre标签将代码包裹起来,并在pre标签内使用code标签。例如: ```html <pre> <code class="language-javascript"> // 你的代码 </code> </pre> ``` 接下来,我们可以在CSS中定义样式来调整代码的缩进。通过对pre和code标签应用样式来解决这个问题。例如: ```css pre { margin: 0; /* 移除pre标签的外边距 */ padding: 0; /* 移除pre标签的内边距 */ } pre code { display: block; /* 将code标签显示为块级元素 */ white-space: pre; /* 保持代码中的空白符和换行符原样显示 */ margin: 0; /* 移除code标签的外边距 */ padding: 1em; /* 添加适当的内边距来调整代码缩进 */ background-color: #f7f7f7; /* 可选:设置代码块的背景颜色 */ } ``` 通过以上样式,我们可以将代码块的缩进问题解决掉,确保代码在展示框中正确显示。根据需要可以调整padding的数值以达到适当的缩进效果,也可以根据喜好设置代码块的背景颜色。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值