Let the script inserted into the InnerHTML run up the implementation code _javascript tips

Source: Internet
Author: User
Tags eval script tag set time

The problem is trivial at times and can be ignored, but sometimes the problem is very serious and it is likely to leave our programs without the expected results. So we need to solve this problem.

If you've read MSDN, you'll find that not all scripts inserted into InnerHTML can be executed, IE will execute these scripts correctly if the script tag contains the defer attribute. Unfortunately, Moziila/firefox and Opera do not eat this set, regardless of whether the script tags have set defer properties, these browsers do not go to IE to perform the script inserted into the InnerHTML.

But whether or not the script is executed, one thing we can be sure of is that the scripts are actually plugged into the InnerHTML, and if you don't believe it, you can check it out. But if you are really alert, you may also find that an exception exists, that is, if the script starts with the InnerHTML content, IE will ignore the script, and Moziila/firefox and Opera will not.

Well, the problem analysis is similar, let's see how to solve it.

The solution is simply that all the scripts inserted into the InnerHTML are taken out and executed. But first we have to solve the two problems above.

Let's look at the first question, how to avoid repeatedly executing the script with the defer attribute in InnerHTML in IE. This is easy, just to determine whether the browser is IE, and then detect whether the script will be executed with the defer attribute. It should be noted that in the judgment of IE browser, we need to avoid being deceived by opera's browser recognition. That's what we'll see in the code that follows.

Next, see IE ignore InnerHTML start script of problem, this also very easy to solve. You just need to append a piece of content that is not scripted to the beginning of the content you want to insert into the InnerHTML. But do not attempt to append an empty content label, or a space, carriage return, newline, etc., which will not work, the beginning of the script will still be ignored. Do not attempt to attach, although this can make the beginning of the script is no longer ignored, but this will still affect the original content of the display, although you may not feel obvious, but for picky users, this may be intolerable. Therefore, in order for the additional content to be able to prevent the opening script from being ignored and not adversely affected, we will append this section:

Copy Code code as follows:

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

Although the above paragraph has a certain length, but it does not appear, and the inserted label has no ID and no name, so it does not conflict with the ID or name of some tags in the original content. But here is a point to be aware of, but also to determine whether it is IE, and then decide to add this paragraph, because some other browsers may not support Display:none this CSS decoration (such as Opera Mini), if you add this code will affect the final display effect.

Let's look at how to take out the script and execute it.

It's easy to take out a script, just use the InnerHTML object's getElementsByTagName method, which works for almost any container tag. After we take out the script, we have to decide whether they are an external script or an internal script.

Let's look at the external script, and if it's an external script, we chose a method that first creates a replica object of this external script and sets its Defer property to True (this is to allow IE to execute correctly) and then inserts the replica object into the AppendChild method. Head. Here you may ask, why not insert into the object of InnerHTML? Is it better to insert into the object that InnerHTML is in? If you try it, you will know that if you insert into the object of InnerHTML, there is no problem in IE browser, but there are some problems in the Mozilla/firefox and Opera browsers. The problem is that if you do this on Firefox, the browser stops responding (this is the test result on Firefox 1.5, the other version is not yet known), and in opera, the script will be inexplicably executed two times (this is the test results on Opera 8.5, the other version of the O Pera Whether this problem, also not yet known. To avoid these problems, I chose to insert it into the head.

Looking at the internal script, the contents of the internal script can be obtained directly with the Text property of the script object, where we use the Text property of the script object instead of the InnerHTML property, because in the Opera browser, the InnerHTML property of the Script object is empty, only the text property to get the script content. Execute internal scripts directly with Eval. However, the script may be included in the HTML annotation tag, so we need to remove the annotation tag first, otherwise there will be an error in IE.

The above analysis looks perfect, but in fact there are still problems, one is document.write and document.writeln problem, the problem in Blueidea, Bound0 gave a thought, is to replace the default Document.Write and Document.writeln methods, but he used string substitution, so only for internal scripts, not for external script, so I think a more general way, is directly to the document.write and Document.writeln, so that both internal script and external script execution are the document.write and Document.writeln we define ourselves. However, there are side effects, that is, these two functions in the current page can not be used as the original, but these two functions after the page load is generally not used again, so there is a redefinition of the side effects of their impact is very small. But the other problem is that, despite this, we still can't guarantee that the contents of the document.write or Document.writeln output will be displayed in the most appropriate place, it just attaches the content to the container where we put the content.

Another problem is that eval causes problems, one is the scope of Hutia on Blueidea, and the other is that if an internal script is executed with Eval, the internal script will start executing before the external script loads. To solve the two problems you can use the Window.settimeout function, so that each script can be deferred after a period of execution, the external script delay time may be set longer to ensure that it can be fully loaded, and the internal script can be set to very short, because a script execution time is usually very short, This guarantees that the scope will not be changed, you can basically guarantee that the execution order of the scripts will not change (this method is not necessarily 100% effective in the order of execution, and if the network is very busy, the external script may not load over the set time, but at least it is much better than when you directly use eval).

If implemented in the previous way, it works for most scripts. But if the script has defer attribute, IE will run the code itself (mentioned earlier), so it will disrupt the order of execution. In addition, the code written by document.write and Document.writeln is added to the last side, not the location of the script, so this is also a problem.

To solve these two problems, we need to make some changes to the previous solution. First of all, we can't assign the content to InnerHTML, and then take the script through it, we need to directly to the content analysis to take out the script. In addition, the HTML part of the script can not be directly assigned to the InnerHTML, you need to execute the script, the original HTML content and Document.write\writeln write in order to combine the contents and then assign to InnerHTML, here to note that, We can't part of the connection to the InnerHTML, because there may be half the content of the tag, in which case the browser is prone to errors. And you will see the page repeatedly refresh the situation appears. If you put the buffer first and give it to InnerHTML for the last time, this problem will not occur.

In addition, the advantage of putting in a buffer is that when the script is finished, you can check that there are new scripts in the buffer, and if so, then recursively execute them, which solves the problem that scripts written by document.write and Document.writeln can be executed.

2006-6-4 Update:

Fixed that the script inserted into InnerHTML could not get the problem of inserting objects into InnerHTML. (Thanks to the Netizen DE reminder).

Adds a shared lock to the content set in the same container, so that when the same container is set continuously, no more conflicts occur. (Thanks to the Singaporean netizen Jason Li's reminder).

2006-5-29 Update:

Increased use of external script caching to increase the speed at which the same external scripts are loaded for the second time.

2006-5-23 Update:

With the enthusiastic user Johnzen, a shared lock is added so that when the contents of multiple containers are set at the same time, no conflict occurs.

Under the reminder of Netizen udbjatwfn, fixed the problem that the internal script of IE exists to execute scope error.

The following is the final implementation of my Code:
Copy Code code as follows:

/* Innerhtml.js
* Copyright Ma Bingyao <andot@ujn.edu.cn>
* version:1.9
* lastmodified:2006-06-04
* This library are free. You can redistribute it and/or modify it.
* http://www.coolcode.cn/?p=117
*/

var global_html_pool = [];
var global_script_pool = [];
var global_script_src_pool = [];
var global_lock_pool = [];
var innerhtml_lock = null;
var document_buffer = "";

function set_innerhtml (obj_id, HTML, time) {
if (Innerhtml_lock = = null) {
Innerhtml_lock = obj_id;
}
else if (typeof (Time) = "undefined") {
global_lock_pool[obj_id + "_html"] = html;
Window.settimeout ("set_innerhtml (' + obj_id +" ', global_lock_pool[' "+ obj_id +" _html ']); ", 10;
Return
}
else if (Innerhtml_lock!= obj_id) {
global_lock_pool[obj_id + "_html"] = html;
Window.settimeout ("set_innerhtml" + obj_id + "', global_lock_pool['" + obj_id + "_html ')," + Time + ");", 10;
Return
}

function get_script_id () {
Return "Script_" + (new Date ()). GetTime (). ToString (36)
+ Math.floor (math.random () * 100000000). toString (36);
}

Document_buffer = "";

document.write = function (str) {
Document_buffer + + str;
}
Document.writeln = function (str) {
Document_buffer + = str + "\ n";
}

Global_html_pool = [];

var scripts = [];
html = html.split (/<\/script>/i);
for (var i = 0; i < html.length; i++) {
Global_html_pool[i] = Html[i].replace (/<script[\s\s]*$/ig, "");
Scripts[i] = {text: ', src: '};
Scripts[i].text = Html[i].substr (global_html_pool[i].length);
SCRIPTS[I].SRC = scripts[i].text.substr (0, Scripts[i].text.indexof (' > ') + 1);
SCRIPTS[I].SRC = Scripts[i].src.match (/src\s*=\s* ([^\ "]*) \ |\" ([^\ ']*) \ ' | ( [^\s]*) [\s>])/I);
if (SCRIPTS[I].SRC) {
if (Scripts[i].src[2]) {
SCRIPTS[I].SRC = scripts[i].src[2];
}
else if (Scripts[i].src[3]) {
SCRIPTS[I].SRC = scripts[i].src[3];
}
else if (Scripts[i].src[4]) {
SCRIPTS[I].SRC = scripts[i].src[4];
}
else {
SCRIPTS[I].SRC = "";
}
Scripts[i].text = "";
}
else {
SCRIPTS[I].SRC = "";
Scripts[i].text = Scripts[i].text.substr (Scripts[i].text.indexof (' > ') + 1);
Scripts[i].text = Scripts[i].text.replace (/^\s*<\!--\s*/g, "");
}
}

var s;
if (typeof (Time) = "undefined") {
s = 0;
}
else {
s = time;
}

var script, Add_script, Remove_script;

for (var i = 0; i < scripts.length; i++) {
var add_html = "Document_buffer + + global_html_pool[" + i + "];\n";
Add_html + + document.getElementById (' + obj_id + '). InnerHTML = document_buffer;\n ";
Script = document.createelement ("script");
if (SCRIPTS[I].SRC) {
SCRIPT.SRC = SCRIPTS[I].SRC;
if (typeof (Global_script_src_pool[script.src]) = = "undefined") {
GLOBAL_SCRIPT_SRC_POOL[SCRIPT.SRC] = true;
s + + 2000;
}
else {
s + + 10;
}
}
else {
Script.text = Scripts[i].text;
s + + 10;
}
Script.defer = true;
Script.type = "Text/javascript";
Script.id = get_script_id ();
Global_script_pool[script.id] = script;
Add_script = add_html;
Add_script + + document.getelementsbytagname (' head '). Item (0) ";
Add_script + = "appendchild (global_script_pool['" + script.id + "']); \ n";
Window.settimeout (Add_script, s);
Remove_script = "document.getElementsByTagName (' head '). Item (0)";
Remove_script + = ". RemoveChild (document.getElementById (' + script.id +")); \ n ";
Remove_script + = "Delete global_script_pool['" + script.id + "'];\n";
Window.settimeout (Remove_script, S + 10000);
}

var end_script = "if (Document_buffer.match (/<\\/script>/i)) {\ n";
End_script + = "set_innerhtml (' + obj_id +" ', Document_buffer, "+ S +"); \ n ";
End_script + = "}\n";
End_script + = "Else {\ n";
End_script + + document.getElementById (' + obj_id + '). InnerHTML = document_buffer;\n ";
End_script + = "Innerhtml_lock = null;\n";
End_script + = "}";
Window.settimeout (End_script, s);
}

JS Call Method:
JavaScript code
Copy Code code as follows:

set_innerhtml (' ID name to insert InnerHTML ', ' Code to insert ');

Scenario 2: innerHTML simple version from ajaxwing
But the problem with this implementation is that the document.write and Document.writeln abbreviations in the script are not in the right place.

Call Method:
JavaScript code
Setinnerhtml (' node in DOM tree ', ' Code to insert ');
JavaScript code
Copy Code code as follows:

/*
* Description: Cross-browser settings InnerHTML method
* Allow inserted HTML code to contain script and style
* Author: Kenxu <ken@ajaxwing.com>
* Date: 2006-03-23
Parameters
* El: Nodes in a legitimate DOM tree
* Htmlcode: Legitimate HTML code
* Tested Browsers: ie5+, firefox1.5+, opera8.5+
*/
var setinnerhtml = function (el, Htmlcode) {
var ua = Navigator.userAgent.toLowerCase ();
if (Ua.indexof (' msie ') >= 0 && ua.indexof (' opera ') < 0) {
Htmlcode = ' <div style= ' display:none ' >for ie</div> ' + htmlcode;
Htmlcode = Htmlcode.replace (/<script ([^>]*) >/gi,
' <script$1 defer> ');
el.innerhtml = Htmlcode;
El.removechild (El.firstchild);
} else {
var el_next = el.nextsibling;
var el_parent = El.parentnode;
El_parent.removechild (EL);
el.innerhtml = Htmlcode;
if (El_next) {
El_parent.insertbefore (el, El_next)
} else {
El_parent.appendchild (EL);
}
}
}

Based on the original author of the reprint, resulting in all the test code is gone, should have left a copy. Alas
However, the cloud-Habitat community for everyone to create an example, after everyone can use the entire station JS control ads, reduce the number of connections.
Http://www.jb51.net/article/20068.htm

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.