AJAX çağrısından sonra innerHTML tarafından enjekte edilen <script> çalıştırılıyor


101

"İçerik" adında bir div var:

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

Bir PHP dosyasından AJAX tarafından bir <script>etiketi dahil olmak üzere verilerle doldurulmalıdır . Ancak, bu etiketin içindeki komut dosyası çalıştırılmıyor.

<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'i nasıl yüklüyorsunuz? kullandığınız kitaplığa bağlıdır, normalde sadece ajax yükünden sonra betikleri çalıştırıp çalıştırmayacağınızı kontrol edebilirsiniz.
Bill Yang

1
Bir komut dosyası da dahil olmak üzere div içeriğini içeren başka bir (php) sayfası istemek window.onloadiçin bir XMTHttpRequestnesne oluşturduktan sonra . Bunu düz JS ile yapıyorum, kitaplık yok (kendi
lol'ım

Yanıtlar:


66

DOM metni olarak eklenen JavaScript çalışmaz. Bununla birlikte, hedefinize ulaşmak için dinamik komut dosyası modelini kullanabilirsiniz. Temel fikir, yürütmek istediğiniz komut dosyasını harici bir dosyaya taşımak ve Ajax yanıtınızı aldığınızda bir komut dosyası etiketi oluşturmaktır. Daha sonra srckomut dosyası etiketinizin ve işte özniteliğini ayarlarsınız , harici komut dosyasını yükler ve yürütür.

Bu diğer StackOverflow gönderisi de size yardımcı olabilir: Komut dosyaları innerHTML ile eklenebilir mi? .


Yüklenen tüm komut dosyalarını seçebilir ve eval () işlevi ile çalıştırabilirsiniz:$('#audit-view script').each(function (index, element) { eval(element.innerHTML); })
Jerzy Gebler

Sayfaya eklenen javascript mutlaka çalıştırılmalıdır. ( örneğin jsfiddle.net/wnn5fz3m/1 ). Soru, neden bazen olmuyor?
NoBugs

@Chocula betiğimi ayrı bir dosyaya taşıdım, yine de kısmi çalışmıyor, bu konuda yardımcı olabilir misiniz? stackoverflow.com/questions/42941856/…
Samra

Bilginize (@NoBugs bana bir ipucu veriyor). Düz javascirpt element.innerHTML = zzz ve desnt çalışmasını denedim. Sonra Jquery $ (element) .html (zzz) denedim ve çalıştım.
gtryonp

68

Bu kodu kullandım, iyi çalışıyor

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

4
Bana sorarsan, bu kabul edilenden çok daha iyi bir cevap. Bu hemen hemen JavaScript enjeksiyonudur.
Xedret

Yararlı ise, bu gerçekten komut neden sorusuna cevap vermez olmaz çalıştırın. Örneğin bkz. Jsfiddle.net/fkqmcaz7 ve jsfiddle.net/wnn5fz3m/1 Kesinlikle çalışmalı ve çalışmadığı basitleştirilmiş bir durum bulamıyorum.
NoBugs

1
@NaoiseGolden OP kelimenin tam anlamıyla komut dosyası yürütme hakkında soru soruyor, bu yüzden burada sorun olmadığını düşünüyorum. :-)
2016

1
Eval () kesinlikle tavsiye edilmez. Bunu görün - stackoverflow.com/questions/9107847/…
Kings

15

Ajax aracılığıyla div'inizde aşağıdaki gibi bir komut dosyası bloğu yüklerseniz:

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

... sadece sayfanızın DOM'unu günceller, myFunction () mutlaka çağrılmaz.

İstek bittiğinde neyin yürütüleceğini tanımlamak için jQuery'nin ajax () yöntemindekine benzer bir Ajax geri çağrı yöntemi kullanabilirsiniz .

Yaptığınız şey, başlangıçta JavaScript içeren bir sayfayı yüklemekten farklıdır (ki bu çalıştırılır).

Bazı içerikleri getirdikten sonra başarı geri aramasının ve hata geri aramasının nasıl kullanılacağına ilişkin bir örnek:

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

Diğer bir hızlı ve kirli yol, jQuery veya başka bir kitaplığı kullanmak istemiyorsanız, DOM metni olarak eklediğiniz herhangi bir komut dosyası kodunu çalıştırmak için eval () kullanmaktır.


jQuery'nin geri aramasını kullanarak, yeni <script> içindeki kodu nasıl "çalıştırabilirim"?
JCOC611


1
Çok teşekkür ederim! "myFunction ()"; benim kodumun dışında bıraktığım kısımdı.
Jason

11

Metindeki tüm betik etiketlerini değerlendirecek betik burada.

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'nizi sunucudan aldıktan sonra bu işlevi çağırmanız yeterlidir. Dikkat edin: kullanmak evaltehlikeli olabilir.

Demo: http://plnkr.co/edit/LA7OPkRfAtgOhwcAnLrl?p=preview


5

Bu, belgeye XHR tarafından döndürülen HTML'nin bir alt kümesini eklemeye çalışmadığınız sürece, jQuery kullanarak benim için 'sadece çalışır'. ( JQuery ile ilgili sorunu gösteren bu hata raporuna bakın .)

İşte çalıştığını gösteren bir örnek:

<!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>

İşte yukarıdakinin eşdeğeri: http://jsfiddle.net/2CTLH/


1
JQuery'nin gerçekten eski sürümünde bir hata olduğu için, şu anda sorunun çözümü bu pek olası değil.
NoBugs

3

İşte AJAX yanıtlarını ayrıştırmak için kullanabileceğiniz bir işlev, özellikle de minifiedjs kullanıyorsanız ve döndürülen Javascript'i çalıştırmasını istiyorsanız veya sadece komut dosyalarını DOM'a eklemeden ayrıştırmak istiyorsanız, istisna hatalarını da işler. Bu kodu php4sack kütüphanesinde kullandım ve kütüphane dışında kullanışlıdır.

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

Komut dosyası etiketine ihtiyaç duyan bir şey enjekte ediyorsanız, yakalanmamış bir sözdizimi hatası alabilir ve yasadışı belirteç diyebilirsiniz . Bunu önlemek için, kapanış komut dosyası etiketlerinizde eğik çizgilerden kaçtığınızdan emin olun. yani;

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

Aynı, form etiketi gibi tüm kapanış etiketleri için de geçerlidir.


1

Bu, ajax .done'dan her komut dosyası içeriğinde eval çağırarak benim için çalıştı:

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

Not: Ajax'ınıza göre ayarlamanız gereken parametreleri $ .ajax'a yazmadım.


0

Burada benzer bir gönderim vardı, jquery OLMADAN ajax yükünde addEventListener yükü

Bunu nasıl çözdüm, stateChange işlevimdeki işlevlere çağrı eklemekti. Kurduğum sayfa, contentArea'ya 3 farklı sayfa yükleyen 3 düğmeydi. 1., 2. veya 3. sayfayı yüklemek için hangi düğmeye basıldığını bilmem gerektiğinden, hangi sayfanın yüklendiğini ve ardından hangi işlevi çalıştıracağımı belirlemek için if / else ifadelerini kolayca kullanabilirdim. Yapmaya çalıştığım şey, yalnızca belirli sayfa öğe kimlikleri nedeniyle yüklendiğinde çalışacak farklı düğme dinleyicileri kaydetmekti ..

yani...

eğer (page1 yükleniyor, pageload = 1) registerListeners1 fonksiyonunu çalıştır

sonra sayfa 2 veya 3 için de aynı.


0

Sonuçum, HTML'nin NESTED SCRIPT etiketlerine izin vermediği. İçinde komut dosyası etiketleri bulunan HTML kodunu enjekte etmek için javascript kullanıyorsanız, javascript de bir komut dosyası etiketine girdiği için çalışmayacaktır. Bir sonraki kodla test edebilirsin ve işe yaramayacaksın. Kullanım örneği, AJAX veya benzeri bir hizmeti çağırmanız, HTML alıyorsunuz ve onu doğrudan HTML DOM'a enjekte etmek istemenizdir. Enjekte edilen HTML kodunun içinde SCRIPT etiketleri varsa çalışmayacaktır.

<!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

Yapılması gereken başka bir şey, sayfayı aşağıdaki gibi bir komut dosyasıyla yüklemektir:

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

Bu, sayfayı yükleyecek, ardından komut dosyasını çalıştıracak ve işlev çalıştırıldığında olay işleyicisini kaldıracaktır. Bu, bir ajax yüklemesinden hemen sonra çalışmaz, ancak kullanıcının div öğesine girmesini bekliyorsanız, bu gayet iyi çalışacaktır.

PS. Jquery gerektirir

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.