ดำเนินการ <script> ฉีดโดย innerHTML หลังจากการเรียก AJAX


101

มี div ชื่อ "Content":

<div id="content"></div>

ควรกรอกข้อมูลจากไฟล์ PHP โดย AJAX รวมถึง<script>แท็ก อย่างไรก็ตามสคริปต์ภายในแท็กนี้จะไม่ถูกเรียกใช้งาน

<div id="content"><!-- After AJAX loads the stuff that goes here -->
   <script type="text/javascript">
     //code
   </script>
   <!-- More stuff that DOES work here -->
</div>

คุณกำลังโหลด div อย่างไร ขึ้นอยู่กับไลบรารีที่คุณใช้โดยปกติคุณสามารถควบคุมได้ว่าคุณต้องการเรียกใช้สคริปต์หลังจากการโหลด ajax หรือไม่
Bill Yang

1
หลังจากที่window.onloadฉันสร้างXMTHttpRequestอ็อบเจ็กต์เพื่อขอเพจ (php) อื่นที่มีเนื้อหาของ div รวมถึงสคริปต์ ฉันกำลังทำสิ่งนี้ด้วย JS ธรรมดาไม่มีไลบรารี (นอกจากฉันเอง lol)
JCOC611

คำตอบ:


66

JavaScript ที่แทรกเป็นข้อความ DOM จะไม่ทำงาน อย่างไรก็ตามคุณสามารถใช้รูปแบบสคริปต์แบบไดนามิกเพื่อบรรลุเป้าหมายของคุณ แนวคิดพื้นฐานคือการย้ายสคริปต์ที่คุณต้องการเรียกใช้งานไปยังไฟล์ภายนอกและสร้างแท็กสคริปต์เมื่อคุณได้รับการตอบสนอง Ajax จากนั้นคุณตั้งค่าsrcแอตทริบิวต์ของแท็กสคริปต์และ voila ของคุณมันจะโหลดและดำเนินการสคริปต์ภายนอก

โพสต์ StackOverflow อื่น ๆ นี้อาจเป็นประโยชน์กับคุณเช่นกัน: สามารถแทรกสคริปต์ด้วย innerHTML ได้หรือไม่ .


คุณสามารถเลือกสคริปต์ที่โหลดทั้งหมดและดำเนินการได้โดยฟังก์ชัน eval ():$('#audit-view script').each(function (index, element) { eval(element.innerHTML); })
Jerzy Gebler

Javascript ที่เพิ่มเข้ามาในเพจควรดำเนินการอย่างแน่นอน ( jsfiddle.net/wnn5fz3m/1เป็นต้น) คำถามคือทำไมบางครั้งถึงไม่?
NoBugs

@ Chocula ฉันย้ายสคริปต์ของฉันไปยังไฟล์แยกต่างหาก แต่มันยังใช้งานไม่ได้จากบางส่วนคุณช่วยเรื่องนี้ได้ไหม stackoverflow.com/questions/42941856/…
Samra

FYI (@NoBugs ให้เบาะแส) ฉันลอง javascirpt element.innerHTML = zzz และไม่ทำงาน จากนั้นฉันลอง Jquery $ (element) .html (zzz) และใช้งานได้
gtryonp

68

ฉันใช้รหัสนี้มันใช้งานได้ดี

var arr = MyDiv.getElementsByTagName('script')
for (var n = 0; n < arr.length; n++)
    eval(arr[n].innerHTML)//run script inside div

4
ถ้าคุณถามฉันนี่เป็นคำตอบที่ดีกว่าคำตอบที่ยอมรับ นี่เป็นการฉีด JavaScript ที่ค่อนข้างมาก
Xedret

แม้ว่าจะมีประโยชน์ แต่สิ่งนี้ไม่ได้ตอบคำถามว่าทำไมสคริปต์จึงไม่ทำงาน ดูตัวอย่างเช่นjsfiddle.net/fkqmcaz7และjsfiddle.net/wnn5fz3m/1มันควรจะรันอย่างแน่นอนและฉันไม่พบกรณีที่เรียบง่ายที่มันใช้ไม่ได้
NoBugs

1
@NaoiseGolden OP กำลังถามอย่างแท้จริงเกี่ยวกับการเรียกใช้สคริปต์ดังนั้นฉันคิดว่ามันโอเคที่นี่ :-)
59

1
ไม่แนะนำให้ใช้ Eval () ดูสิ่งนี้ - stackoverflow.com/questions/9107847/…
คิงส์

15

หากคุณโหลดบล็อกสคริปต์ภายใน div ของคุณผ่าน Ajax เช่นนี้:

<div id="content">
    <script type="text/javascript">
    function myFunction() {
      //do something
    }
    myFunction();
    </script>
</div>

... เพียงแค่อัปเดต DOM ของเพจของคุณ myFunction () ไม่จำเป็นต้องถูกเรียก

คุณสามารถใช้เมธอดการโทรกลับ Ajax เช่นวิธีการajax ()ของ jQuery เพื่อกำหนดสิ่งที่จะดำเนินการเมื่อคำขอเสร็จสิ้น

สิ่งที่คุณกำลังทำแตกต่างจากการโหลดหน้าเว็บที่มี JavaScript รวมอยู่ด้วยจาก get-go (ซึ่งจะถูกเรียกใช้งาน)

ตัวอย่างวิธีใช้การโทรกลับสำเร็จและการเรียกกลับข้อผิดพลาดหลังจากดึงเนื้อหาบางส่วน:

  $.ajax({
    type: 'GET',
    url: 'response.php',
    timeout: 2000,
    success: function(data) {
      $("#content").html(data);
      myFunction();
    },
    error: function (XMLHttpRequest, textStatus, errorThrown) {
      alert("error retrieving content");
    }

อีกวิธีที่รวดเร็วและสกปรกคือการใช้eval ()เพื่อรันโค้ดสคริปต์ใด ๆ ที่คุณแทรกเป็นข้อความ DOM หากคุณไม่ต้องการใช้ jQuery หรือไลบรารีอื่น ๆ


โดยใช้การเรียกกลับของ jQuery ฉันจะ "รัน" โค้ดภายใน <script> ใหม่ได้อย่างไร
JCOC611

ฉันเพิ่มตัวอย่างของการใช้การโทรกลับที่ประสบความสำเร็จ:
Christopher Tokar

1
ขอบคุณมาก! "myFunction ();" ส่วนหนึ่งคือสิ่งที่ฉันทิ้งไว้จากรหัสของฉัน
Jason

11

นี่คือสคริปต์ที่จะประเมินแท็กสคริปต์ทั้งหมดในข้อความ

function evalJSFromHtml(html) {
  var newElement = document.createElement('div');
  newElement.innerHTML = html;

  var scripts = newElement.getElementsByTagName("script");
  for (var i = 0; i < scripts.length; ++i) {
    var script = scripts[i];
    eval(script.innerHTML);
  }
}

เพียงเรียกใช้ฟังก์ชันนี้หลังจากที่คุณได้รับ HTML จากเซิร์ฟเวอร์ ขอเตือน: การใช้evalอาจเป็นอันตรายได้

การสาธิต: http://plnkr.co/edit/LA7OPkRfAtgOhwcAnLrl?p=preview


5

สิ่งนี้ 'ใช้ได้ผลสำหรับฉันโดยใช้ jQuery หากคุณไม่พยายามต่อท้ายส่วนย่อยของ HTML ที่ส่งคืน XHR เข้ากับเอกสาร (ดูรายงานข้อบกพร่องที่แสดงปัญหาเกี่ยวกับ jQuery)

นี่คือตัวอย่างที่แสดงให้เห็นว่ามันใช้งานได้:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> 
<html lang="en"> 
<head> 
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 
    <title>test_1.4</title> 
    <script type="text/javascript" charset="utf-8" src="jquery.1.4.2.js"></script> 
    <script type="text/javascript" charset="utf-8"> 
        var snippet = "<div><span id='a'>JS did not run<\/span><script type='text/javascript'>" +
        "$('#a').html('Hooray! JS ran!');" +
        "<\/script><\/div>";
        $(function(){
            $('#replaceable').replaceWith($(snippet));
        });
    </script> 
</head> 
<body> 
    <div id="replaceable">I'm going away.</div> 
</body> 
</html>

นี่คือสิ่งที่เทียบเท่ากับด้านบน: http://jsfiddle.net/2CTLH/


1
ไม่น่าเป็นไปได้สูงว่านี่จะเป็นวิธีแก้ปัญหาในขณะนี้เนื่องจากเป็นข้อบกพร่องของ jQuery เวอร์ชันเก่าจริงๆ
NoBugs

3

นี่คือฟังก์ชั่นที่คุณสามารถใช้เพื่อแยกวิเคราะห์การตอบสนอง AJAX โดยเฉพาะอย่างยิ่งหากคุณใช้ minifiedjs และต้องการให้เรียกใช้ Javascript ที่ส่งคืนหรือเพียงแค่ต้องการแยกวิเคราะห์สคริปต์โดยไม่ต้องเพิ่มเข้าไปใน DOM มันจะจัดการข้อผิดพลาดข้อยกเว้นด้วย ฉันใช้รหัสนี้ในไลบรารี php4sack และมีประโยชน์นอกไลบรารี

function parseScript(_source) {
    var source = _source;
    var scripts = new Array();

    // Strip out tags
    while(source.toLowerCase().indexOf("<script") > -1 || source.toLowerCase().indexOf("</script") > -1) {
        var s = source.toLowerCase().indexOf("<script");
        var s_e = source.indexOf(">", s);
        var e = source.toLowerCase().indexOf("</script", s);
        var e_e = source.indexOf(">", e);

        // Add to scripts array
        scripts.push(source.substring(s_e+1, e));
        // Strip from source
        source = source.substring(0, s) + source.substring(e_e+1);
    }

    // Loop through every script collected and eval it
    for(var i=0; i<scripts.length; i++) {
        try {
          if (scripts[i] != '')
          {         
            try  {          //IE
                  execScript(scripts[i]);   
      }
      catch(ex)           //Firefox
      {
        window.eval(scripts[i]);
      }   

            }  
        }
        catch(e) {
            // do what you want here when a script fails
         // window.alert('Script failed to run - '+scripts[i]);
          if (e instanceof SyntaxError) console.log (e.message+' - '+scripts[i]);
                    }
    }
// Return the cleaned source
    return source;
 }

2

หากคุณกำลังฉีดบางสิ่งบางอย่างที่ต้องแท็กสคริปต์ที่คุณอาจจะได้รับการผิดพลาดทางไวยากรณ์ไม่ถูกตรวจจับและพูดว่าโทเค็นที่ผิดกฎหมาย เพื่อหลีกเลี่ยงปัญหานี้อย่าลืมหลีกเลี่ยงเครื่องหมายทับในแท็กสคริปต์ปิดของคุณ ได้แก่ ;

var output += '<\/script>';

เช่นเดียวกันกับแท็กปิดใด ๆ เช่นแท็กแบบฟอร์ม


1

สิ่งนี้ใช้ได้ผลสำหรับฉันโดยการเรียก eval ในเนื้อหาสคริปต์แต่ละรายการจาก ajax .done:

$.ajax({}).done(function (data) {      
    $('div#content script').each(function (index, element) { eval(element.innerHTML); 
})  

หมายเหตุ: ฉันไม่ได้เขียนพารามิเตอร์เป็น $ .ajax ซึ่งคุณต้องปรับเปลี่ยนตาม ajax ของคุณ


0

ฉันมีโพสต์ที่คล้ายกันที่นี่โหลด addEventListener ในการโหลด ajax โดยไม่มี jquery

วิธีแก้ไขคือการแทรกการเรียกไปยังฟังก์ชันภายในฟังก์ชัน stateChange ของฉัน หน้าที่ฉันตั้งค่าคือปุ่ม 3 ปุ่มที่จะโหลดหน้าต่างๆ 3 หน้าลงใน contentArea เนื่องจากฉันต้องรู้ว่ากำลังกดปุ่มใดเพื่อโหลดหน้า 1, 2 หรือ 3 ฉันจึงสามารถใช้คำสั่ง if / else เพื่อตรวจสอบว่ากำลังโหลดหน้าใดแล้วจึงจะเรียกใช้ฟังก์ชันใด สิ่งที่ฉันพยายามทำคือลงทะเบียนตัวรับฟังปุ่มต่างๆที่จะใช้ได้เฉพาะเมื่อโหลดเพจที่ระบุเนื่องจาก ID องค์ประกอบ ..

ดังนั้น...

ถ้า (กำลังโหลด page1, pageload = 1) เรียกใช้ฟังก์ชัน registerListeners1

จากนั้นเหมือนกันสำหรับหน้า 2 หรือ 3


0

ข้อสรุปของฉันคือ HTML ไม่อนุญาตให้ใช้แท็ก NESTED SCRIPT หากคุณใช้จาวาสคริปต์ในการแทรกโค้ด HTML ที่มีแท็กสคริปต์อยู่ภายในจะไม่ทำงานเนื่องจากจาวาสคริปต์ไปอยู่ในแท็กสคริปต์ด้วย คุณสามารถทดสอบด้วยรหัสถัดไปและคุณจะพบว่ามันจะไม่ทำงาน กรณีการใช้งานคือคุณกำลังเรียกใช้บริการด้วย AJAX หรือคล้ายกันคุณกำลังได้รับ HTML และคุณต้องการที่จะฉีดเข้าไปใน HTML DOM ทันที หากโค้ด HTML ที่แทรกเข้าไปมีอยู่ในแท็ก SCRIPT จะไม่ทำงาน

<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"></head><body></body><script>document.getElementsByTagName("body")[0].innerHTML = "<script>console.log('hi there')</script>\n<div>hello world</div>\n"</script></html>

-3

สิ่งที่ต้องทำอีกอย่างคือการโหลดหน้าเว็บด้วยสคริปต์เช่น:

<div id="content" onmouseover='myFunction();$(this).prop( 'onmouseover', null );'>
<script type="text/javascript">
function myFunction() {
  //do something
}
myFunction();
</script>
</div>

สิ่งนี้จะโหลดหน้าจากนั้นเรียกใช้สคริปต์และลบตัวจัดการเหตุการณ์เมื่อเรียกใช้ฟังก์ชัน สิ่งนี้จะไม่ทำงานทันทีหลังจากโหลด ajax แต่หากคุณกำลังรอให้ผู้ใช้ป้อนองค์ประกอบ div สิ่งนี้จะใช้ได้ดี

ปล. ต้องใช้ Jquery

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.