2008-10-14 16 views
12

Tengo una función JS que ocasionalmente se puede usar en algunas páginas. Depende de otro archivo JS (swfObject.js), pero me gustaría evitar tener que incluir este archivo por todas partes, ya que es una solicitud desaprovechada la mayor parte del tiempo.¿Usar javascript para inyectar referencias de scripts según sea necesario?

En su lugar, me gustaría crear una función genérica que pueda inyectar una referencia de script en la página DOM según sea necesario, por lo que si se llama a esta función, buscaría la secuencia de comandos y, si no existe, cargará en.

Estoy bastante seguro de que esto es posible (y no voy a usar document.write), pero antes de aventurarme en territorio inexplorado, alguien lo ha hecho antes, y si es así, cualquier apuntador ?

EDIT: Ok, lo intenté, y funciona en IE6 y FF, todavía no he probado otros navegadores.

Aquí está mi código (Rev 2.0, ahora con devoluciones de llamada opcional):

function loadJSInclude(scriptPath, callback) 
{ 
    var scriptNode = document.createElement('SCRIPT'); 
    scriptNode.type = 'text/javascript'; 
    scriptNode.src = scriptPath; 

    var headNode = document.getElementsByTagName('HEAD'); 
    if (headNode[0] != null) 
     headNode[0].appendChild(scriptNode); 

    if (callback != null)  
    { 
     scriptNode.onreadystagechange = callback;    
     scriptNode.onload = callback; 
    } 
} 

y en el método con una dependencia:

var callbackMethod = function() 
{ 
    // Code to do after loading swfObject 
} 

// Include SWFObject if its needed 
if (typeof(SWFObject) == 'undefined')  
    loadJSInclude('/js/swfObject.js', callbackMethod); 
else 
    calbackMethod(); 

¿Alguna sugerencia?

+0

No entiendo por qué esto es necesario - una vez que ha sido solicitado para cualquier página de su sitio web/aplicación, se almacena en caché en su mayoría probablemente de todos modos, entonces realmente no está lastimando nada. Parece mucho esfuerzo extra por tan poco a cambio. –

+0

Jason, tenemos cientos de archivos donde podría usarse este fragmento, por lo que preferiría tener la capacidad de hacerlo en el cliente (a través de nuestro sistema CMS) en lugar de tener que reconstruir el sitio para agregar la referencia del script en el Archivo .CS – FlySwat

Respuesta

4

Si está utilizando un marco de nivel superior como jQuery, se puede consultar la función $.getScript(url, callback).

3

Si desea que su código en la siguiente línea y el gusto de escribir algo como:

if (iNeedSomeMore){ 
    Script.load("myBigCodeLibrary.js"); // includes code for myFancyMethod(); 
    myFancyMethod();      // cool, no need for callbacks! 
} 

Hay una manera inteligente para inyectar secuencias de comandos dependencias sin la necesidad de las devoluciones de llamada. Simplemente tiene que extraer el script a través de una solicitud AJAX síncrona y evaluar el script a nivel global.

Si utiliza el método del prototipo Script.load se parece a esto:

var Script = { 
    _loadedScripts: [], 
    include: function(script){ 
    // include script only once 
    if (this._loadedScripts.include(script)){ 
     return false; 
    } 
    // request file synchronous 
    var code = new Ajax.Request(script, { 
     asynchronous: false, method: "GET", 
     evalJS: false, evalJSON: false 
    }).transport.responseText; 
    // eval code on global level 
    if (Prototype.Browser.IE) { 
     window.execScript(code); 
    } else if (Prototype.Browser.WebKit){ 
     $$("head").first().insert(Object.extend(
     new Element("script", {type: "text/javascript"}), {text: code} 
    )); 
    } else { 
     window.eval(code); 
    } 
    // remember included script 
    this._loadedScripts.push(script); 
    } 
}; 
+0

Sí, prefiero mi método, además de que mi método funciona para scripts de dominio cruzado. – FlySwat

+1

¿Qué pasa con todos los olfatear el navegador? – kangax

+0

¡Tienes razón, kangax! Pero no pude evaluar el código devuelto dentro del alcance de la "ventana" global. Especialmente WebKit estropeó algunas cosas. – aemkei

0

Ninguno de estos métodos, incluyendo document.writing una etiqueta de script, trabajar si el guión en sí tiene una document.write en ella.

0

Escribí un módulo simple que automatiza el trabajo de importar/incluir scripts de módulo en JavaScript. Pruébalo y por favor, ¡deja un comentario! :) Para una explicación detallada del código se refieren a esta entrada del blog: http://stamat.wordpress.com/2013/04/12/javascript-require-import-include-modules/

// ----- USAGE ----- 

require('ivar.util.string'); 
require('ivar.net.*'); 
require('ivar/util/array.js'); 
require('http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js'); 

ready(function(){ 
    //do something when required scripts are loaded 
}); 

    //-------------------- 

var _rmod = _rmod || {}; //require module namespace 
_rmod.LOADED = false; 
_rmod.on_ready_fn_stack = []; 
_rmod.libpath = ''; 
_rmod.imported = {}; 
_rmod.loading = { 
    scripts: {}, 
    length: 0 
}; 

_rmod.findScriptPath = function(script_name) { 
    var script_elems = document.getElementsByTagName('script'); 
    for (var i = 0; i < script_elems.length; i++) { 
     if (script_elems[i].src.endsWith(script_name)) { 
      var href = window.location.href; 
      href = href.substring(0, href.lastIndexOf('/')); 
      var url = script_elems[i].src.substring(0, script_elems[i].length - script_name.length); 
      return url.substring(href.length+1, url.length); 
     } 
    } 
    return ''; 
}; 

_rmod.libpath = _rmod.findScriptPath('script.js'); //Path of your main script used to mark the root directory of your library, any library 


_rmod.injectScript = function(script_name, uri, callback, prepare) { 

    if(!prepare) 
     prepare(script_name, uri); 

    var script_elem = document.createElement('script'); 
    script_elem.type = 'text/javascript'; 
    script_elem.title = script_name; 
    script_elem.src = uri; 
    script_elem.async = true; 
    script_elem.defer = false; 

    if(!callback) 
     script_elem.onload = function() { 
      callback(script_name, uri); 
     }; 

    document.getElementsByTagName('head')[0].appendChild(script_elem); 
}; 

_rmod.requirePrepare = function(script_name, uri) { 
    _rmod.loading.scripts[script_name] = uri; 
    _rmod.loading.length++; 
}; 

_rmod.requireCallback = function(script_name, uri) { 
    _rmod.loading.length--; 
    delete _rmod.loading.scripts[script_name]; 
    _rmod.imported[script_name] = uri; 

    if(_rmod.loading.length == 0) 
     _rmod.onReady(); 
}; 

_rmod.onReady = function() { 
    if (!_rmod.LOADED) { 
     for (var i = 0; i < _rmod.on_ready_fn_stack.length; i++){ 
      _rmod.on_ready_fn_stack[i](); 
     }); 
     _rmod.LOADED = true; 
    } 
}; 

_.rmod = namespaceToUri = function(script_name, url) { 
    var np = script_name.split('.'); 
    if (np.getLast() === '*') { 
     np.pop(); 
     np.push('_all'); 
    } 

    if(!url) 
     url = ''; 

    script_name = np.join('.'); 
    return url + np.join('/')+'.js'; 
}; 

//you can rename based on your liking. I chose require, but it can be called include or anything else that is easy for you to remember or write, except import because it is reserved for future use. 
var require = function(script_name) { 
    var uri = ''; 
    if (script_name.indexOf('/') > -1) { 
     uri = script_name; 
     var lastSlash = uri.lastIndexOf('/'); 
     script_name = uri.substring(lastSlash+1, uri.length); 
    } else { 
     uri = _rmod.namespaceToUri(script_name, ivar._private.libpath); 
    } 

    if (!_rmod.loading.scripts.hasOwnProperty(script_name) 
    && !_rmod.imported.hasOwnProperty(script_name)) { 
     _rmod.injectScript(script_name, uri, 
      _rmod.requireCallback, 
       _rmod.requirePrepare); 
    } 
}; 

var ready = function(fn) { 
    _rmod.on_ready_fn_stack.push(fn); 
}; 
0

considerar el uso de require.js. Esto podría necesitar una nueva revisión de su framework de frontend, pero vale la pena.Con requerir, sólo podía hacer lo siguiente en su fileUsedOccasionally.js:

 
define(['swfObject', 'someOtherDependency'], function (swfObject, someOtherDependency) { 
    // you can now use swfObject as a JS object! you can call it whatever you want 
    // you'll have to write a swfObject.js to wrap it with require 
    // but that's trivial 
}); 
Cuestiones relacionadas