Übergabe von Parametern an JavaScript-Dateien

163

Oft habe ich eine JavaScript-Datei, die ich verwenden möchte und für die bestimmte Variablen auf meiner Webseite definiert werden müssen.

Der Code sieht also ungefähr so ​​aus:

<script type="text/javascript" src="file.js"></script>
<script type="text/javascript">
   var obj1 = "somevalue";
</script>

Aber was ich tun möchte ist:

<script type="text/javascript" 
     src="file.js?obj1=somevalue&obj2=someothervalue"></script>

Ich habe verschiedene Methoden ausprobiert und die beste ist, die Abfragezeichenfolge wie folgt zu analysieren:

var scriptSrc = document.getElementById("myscript").src.toLowerCase();

Und dann nach meinen Werten suchen.

Ich frage mich, ob es einen anderen Weg gibt, dies zu tun, ohne eine Funktion zum Parsen meiner Zeichenfolge zu erstellen.

Kennen Sie alle andere Methoden?

RaduM
quelle
9
Dies ist eine doppelte Frage ( stackoverflow.com/questions/1017424/… ) und meiner Meinung nach ein fehlgeleitetes Design. Es ist viel einfacher, entweder Ihre erste Variablenlösung zu verwenden (okay) oder das Skript eine Funktion definieren zu lassen, die dann mit den Variablen aufgerufen wird (besser).
Matthew Flaschen
Ich suche nach einer aktualisierten Lösung, die die neue ECMAScript 6-Funktionalität
nutzt
Die Verwendung eines internen Skripts löst CSP-Berichte aus, wenn die Site HTTPS ist und CSP vollständig aktiviert ist. Der im CSP-Dokument angegebene Grund ist, dass das Zulassen interner Elemente die Injektion erleichtern kann.
David Spector

Antworten:

207

Ich würde empfehlen, wenn möglich keine globalen Variablen zu verwenden. Verwenden Sie einen Namespace und OOP, um Ihre Argumente an ein Objekt weiterzuleiten.

Dieser Code gehört in file.js:

var MYLIBRARY = MYLIBRARY || (function(){
    var _args = {}; // private

    return {
        init : function(Args) {
            _args = Args;
            // some other initialising
        },
        helloWorld : function() {
            alert('Hello World! -' + _args[0]);
        }
    };
}());

Und in Ihrer HTML-Datei:

<script type="text/javascript" src="file.js"></script>
<script type="text/javascript">
   MYLIBRARY.init(["somevalue", 1, "controlId"]);
   MYLIBRARY.helloWorld();
</script>
Naeem Sarfraz
quelle
4
@Naeem - wird file.js 100% der Zeit geladen, wenn MYLIBRARY.init (["somevalue", 1, "controlId"]); wird hingerichtet? Vielleicht brauchen wir ein Dokument, das bereit ist, es abzulegen?
Darius.V
2
1) Wenn MYLIBRARY vorhanden ist, verwenden Sie es oder definieren Sie ein neues Objekt. Die Absicht ist, einen globalen Namespace zu erstellen. Normalerweise verwende ich Sub-Namespaces, damit diese Zeile verhindert, dass der Namespace der obersten Ebene neu definiert wird. 2) Ja, es wurde ein Singleton erstellt.
Naeem Sarfraz
1
Ich habe ein Beispiel für diese Idee gemacht: http://plnkr.co/edit/iE0Vr7sszfqrrDIsR8Wi?p=preview
robe007
1
Was bedeutet dieser Ausdruck? var MYLIBRARY = MYLIBRARY || (function(){}());? Warum sollte MYLIBRARYein boolescher Wert festgelegt werden?
Alex
1
@ Alexander, siehe meinen Kommentar oben stackoverflow.com/questions/2190801/…
Naeem Sarfraz
79

Sie können Parameter mit beliebigen Attributen übergeben. Dies funktioniert in allen aktuellen Browsern.

<script type="text/javascript" data-my_var_1="some_val_1" data-my_var_2="some_val_2" src="/js/somefile.js"></script>

In somefile.js können Sie folgende Variablenwerte übergeben:

........

var this_js_script = $('script[src*=somefile]'); // or better regexp to get the file name..

var my_var_1 = this_js_script.attr('data-my_var_1');   
if (typeof my_var_1 === "undefined" ) {
   var my_var_1 = 'some_default_value';
}
alert(my_var_1); // to view the variable value

var my_var_2 = this_js_script.attr('data-my_var_2');   
if (typeof my_var_2 === "undefined" ) {
   var my_var_2 = 'some_default_value';
}
alert(my_var_2); // to view the variable value

...etc...

Vlado
quelle
1
Sehr schöne Lösung, dies funktioniert sogar mit dem asynchronen Attribut.
ViRuSTriNiTy
2
alt, aber für diejenigen, die googeln: Dies ist großartig, wenn Sie einen CSP (Content Security Policy) umgehen müssen. Wir verwenden viele Skripte, bei denen wir Zeichenfolgen, die aus Sprachressourcen, API-Schlüsseln usw. bestimmt wurden, an JS-Dateien übergeben.
monkeySeeMonkeyDo
2
Beachten Sie, dass Sie auch die Kompatibilität verwenden können ( document.currentScriptsiehe caniuse.com/#feat=document-currentscript) (oder eine Polyfüllung verwenden können)
Yves M.
Die $(..)Syntax ist jquery, vergessen Sie nicht, sie einzuschließen.
Timo vor
48

Eine andere Idee, auf die ich stieß, war, iddem <script>Element ein zuzuweisen und die Argumente als data-*Attribute zu übergeben. Das resultierende <script>Tag würde ungefähr so ​​aussehen:

<script id="helper" data-name="helper" src="helper.js"></script>

Das Skript könnte dann die ID verwenden, um sich programmgesteuert zu lokalisieren und die Argumente zu analysieren. Mit dem vorherigen <script>Tag könnte der Name folgendermaßen abgerufen werden:

var name = document.getElementById("helper").getAttribute("data-name");

Wir bekommen name=helper

Nalini Wanjale
quelle
4
Wenn Sie nicht vom ID-Attribut abhängig sein möchten, können Sie Ihr helper.jsSkript auch dazu bringen, alle scriptTags auf der Seite zu durchlaufen , nach dem mit zu suchen scr="helper.js"und dann zu extrahieren data-name.
Jvannistelrooy
1
@jvannistelrooy Ich habe es nicht versucht, aber ich glaube, man sollte in der Lage sein, über jquery und einen cleveren Selektor wie folgt zum Skript zu gelangen: var this_js_script = $('script[src*=somefile]');(von oben kopiert )
LosManos
19

Überprüfen Sie diese URL. Es funktioniert perfekt für die Anforderung.

http://feather.elektrum.org/book/src.html

Vielen Dank an den Autor. Zum schnellen Nachschlagen habe ich die folgende Hauptlogik eingefügt:

var scripts = document.getElementsByTagName('script');
var myScript = scripts[ scripts.length - 1 ];

var queryString = myScript.src.replace(/^[^\?]+\??/,'');

var params = parseQuery( queryString );

function parseQuery ( query ) {
  var Params = new Object ();
  if ( ! query ) return Params; // return empty object
  var Pairs = query.split(/[;&]/);
  for ( var i = 0; i < Pairs.length; i++ ) {
    var KeyVal = Pairs[i].split('=');
    if ( ! KeyVal || KeyVal.length != 2 ) continue;
    var key = unescape( KeyVal[0] );
    var val = unescape( KeyVal[1] );
    val = val.replace(/\+/g, ' ');
    Params[key] = val;
  }
  return Params;
}
user378221
quelle
1
Ich mochte diese Lösung, habe sie aber leicht modifiziert, um die Fragment-ID zu verwenden, damit keine Caches kaputt gehen: var frag = myScript.src.replace (/ ^ [^ \ #] + \ #? /, '') ;;
Mark Nottingham
Oh, und ich habe festgestellt, dass das Einfügen von JSON funktioniert, solange Sie es urlencodieren.
Mark Nottingham
@ user378221 - Sind Sie sicher, dass dies immer die richtige Datei erhält? Ich meine, dies setzt voraus, dass diese Datei zuletzt ist. Was ist, wenn mehr Skript-Tags geladen werden, bevor dies ausgeführt wird? Ich weiß nicht, ob dies möglich ist, aber ich gehe davon aus, dass das Dokument nicht darauf wartet, dass die Codeausführung abgeschlossen ist, um andere Tags zu laden.
Darius.V
Verwenden Sie besser decodeURI () oder decodeURIComponent () anstelle von unescape, da diese Funktion veraltet ist.
Steve Childs
@ Darius.V Dies funktioniert für nicht asynchrone Skripte. Ich bevorzuge Option 1 mit Option 5 als Fallback .
Luke
14

Sie verwenden globale Variablen :-D.

So was:

<script type="text/javascript">
   var obj1 = "somevalue";
   var obj2 = "someothervalue";
</script>
<script type="text/javascript" src="file.js"></script">

Der JavaScript-Code in 'file.js' kann problemlos auf obj1und zugreifen obj2.

EDIT Ich will nur hinzufügen , dass , wenn ‚file.js‘ will , wenn überprüfen obj1und obj2haben sogar schon erklärt Ihnen die folgende Funktion verwenden können.

function IsDefined($Name) {
    return (window[$Name] != undefined);
}

Hoffe das hilft.

NawaMan
quelle
Dadurch wird ein nicht referenzierter Fehler im IE ausgelöst. Der bevorzugte Körper dieser Funktion ist return typeof window[$Name] !== 'undefined';. Bitte beachten Sie, dass Sie dieser Funktion eine Zeichenfolge übergeben würden, die den Namen der Variablen enthält. Es ist wahrscheinlich einfacher, einfach zu überprüfen, ob die Variable im aufrufenden Code vorhanden ist (dies kann nicht als Funktion implementiert werden) über if (typeof var !== 'undefined').
Anthony DiSanti
2
Oh, benutze niemals IE. Es tut uns leid.
NawaMan
Ja, aber nach meiner Erfahrung mit JavaScript würde ich globale Variablen nur für Modul-Namespaces verwenden und genau so viel verfügbar machen, wie benötigt wird (wie Init-Code, einige Eigenschaften), wie hier gezeigt . Es ist zu einfach, Namenskonflikte in komplexen Projekten zu bekommen. Sie verbringen Stunden Ihrer Zeit damit, herauszufinden, dass Sie die Variable bereits an einer anderen Stelle im Projekt verwendet haben.
Matt
Sie können das weglassen var.
Timo vor
12

Hier ist ein sehr überstürzter Proof of Concept.

Ich bin mir sicher, dass es mindestens zwei Stellen gibt, an denen Verbesserungen möglich sind, und ich bin mir auch sicher, dass dies in freier Wildbahn nicht lange überleben würde. Jedes Feedback, um es präsentabler oder benutzerfreundlicher zu machen, ist willkommen.

Der Schlüssel ist das Festlegen einer ID für Ihr Skriptelement. Der einzige Haken ist, dass Sie das Skript nur einmal aufrufen können, da es nach dieser ID sucht, um die Abfragezeichenfolge abzurufen. Dies könnte behoben werden, wenn das Skript stattdessen alle Abfrageelemente durchläuft, um festzustellen, ob eines von ihnen darauf verweist, und wenn ja, die letzte Instanz eines solchen Skriptelements verwendet. Wie auch immer, weiter mit dem Code:

Skript wird aufgerufen:

window.onload = function() {
//Notice that both possible parameters are pre-defined.
//Which is probably not required if using proper object notation
//in query string, or if variable-variables are possible in js.
var header;
var text;

//script gets the src attribute based on ID of page's script element:
var requestURL = document.getElementById("myScript").getAttribute("src");

//next use substring() to get querystring part of src
var queryString = requestURL.substring(requestURL.indexOf("?") + 1, requestURL.length);

//Next split the querystring into array
var params = queryString.split("&");

//Next loop through params
for(var i = 0; i < params.length; i++){
 var name  = params[i].substring(0,params[i].indexOf("="));
 var value = params[i].substring(params[i].indexOf("=") + 1, params[i].length);

    //Test if value is a number. If not, wrap value with quotes:
    if(isNaN(parseInt(value))) {
  params[i] = params[i].replace(value, "'" + value + "'");
 }

    // Finally, use eval to set values of pre-defined variables:
 eval(params[i]);
}

//Output to test that it worked:
document.getElementById("docTitle").innerHTML = header;
document.getElementById("docText").innerHTML = text;
};

Skript über folgende Seite aufgerufen:

<script id="myScript" type="text/javascript" 
        src="test.js?header=Test Page&text=This Works"></script>

<h1 id="docTitle"></h1>
<p id="docText"></p>
Anthony
quelle
also wird eval den Wert tatsächlich als globale Variable festlegen ... ziemlich cool.
Rodmjay
1
Eval ist böse weglaufen
Barry Chapman
@barrychapman - oh man, 2010. Ich bin überrascht, dass dort nicht 10 andere rote Fahnen waren.
Anthony
9

könnte sehr einfach sein

beispielsweise

<script src="js/myscript.js?id=123"></script>
<script>
    var queryString = $("script[src*='js/myscript.js']").attr('src').split('?')[1];
</script>

Sie können dann die Abfragezeichenfolge wie unten beschrieben in json konvertieren

var json = $.parseJSON('{"' 
            + queryString.replace(/&/g, '","').replace(/=/g, '":"') 
            + '"}');

und kann dann gerne verwenden

console.log(json.id);
Tofeeq
quelle
6

Dies ist einfach möglich, wenn Sie ein Javascript-Framework wie jQuery verwenden. Wie so,

var x = $('script:first').attr('src'); //Fetch the source in the first script tag
var params = x.split('?')[1]; //Get the params

Jetzt können Sie diese Parameter verwenden, indem Sie sie als variable Parameter aufteilen.

Der gleiche Vorgang kann ohne Framework ausgeführt werden, erfordert jedoch einige weitere Codezeilen.

GeekTantra
quelle
2
Es gibt auch ein jQuery-Plugin namens parseQuery, das dies noch einfacher macht: plugins.jquery.com/project/parseQuery
Jimmy Cuadra
@ JimmyCuadra - leider ist der von Ihnen angegebene Link defekt. Aber ich fand einen ähnlichen Ansatz in jQuery selbst: jQuery.param ()
Matt
1

Nun, Sie könnten die Javascript-Datei von einer der Skriptsprachen erstellen lassen und Ihre Variablen bei jeder Anforderung in die Datei einfügen. Sie müssten Ihrem Webserver mitteilen, dass er js-Dateien nicht statisch austeilen soll (die Verwendung von mod_rewrite würde ausreichen).

Beachten Sie jedoch, dass Sie das Caching dieser js-Dateien verlieren, da sie ständig geändert werden.

Tschüss.

aefxx
quelle
1
Ich kann nicht verstehen, warum dies abgelehnt wurde. Es ist eine absolut gültige Lösung, die auf serverseitige Logik zurückgreift. Meines Erachtens erfordert das OP keine vollständige Javascript-Lösung.
Anoyz
@aefxx - Du hast recht. Innerhalb des <script>Blocks können Sie etwas verwenden, MyModule.Initialize( '<%: Model.SomeProperty%>', '<%: Model.SomeOtherProperty%>', ...);das auf dem Server gerendert wird. Achtung: Entkommt <%:dem Wert, während <%=der Wert nicht entkommen wird. MyModulewäre ein Namespace (dh eine Variable in der .js-Datei, die selbst aufgerufen wird und die Funktion verfügbar macht Initialize). Ich habe Ihre Antwort positiv bewertet, da dies ein hilfreicher Beitrag ist.
Matt
Hinweis: Das Konzept zum Erstellen eines Moduls, das eine exponierte Eigenschaft enthält, wird hier auf dieser Seite ausführlicher beschrieben .
Matt
1

Schöne Fragen und kreative Antworten, aber mein Vorschlag ist, Ihre Methoden zu parametrisieren, und das sollte alle Ihre Probleme ohne Tricks lösen.

wenn Sie Funktion haben:

function A()
{
    var val = external_value_from_query_string_or_global_param;
}

Sie können dies ändern in:

function B(function_param)
{
    var val = function_param;
}

Ich denke, dies ist der natürlichste Ansatz. Sie müssen keine zusätzliche Dokumentation über 'Dateiparameter' erstellen und erhalten dieselbe. Dies ist besonders nützlich, wenn Sie anderen Entwicklern erlauben, Ihre js-Datei zu verwenden.

dzida
quelle
0

Nein, Sie können dies nicht wirklich tun, indem Sie dem Querystring-Teil der JS-Datei-URL Variablen hinzufügen. Wenn es darum geht, den Teil des Codes zu schreiben, um die Zeichenfolge zu analysieren, die Sie stört, besteht eine andere Möglichkeit darin, Ihre Variablen durch json zu codieren und sie in etwas wie das rel-Attribut des Tags einzufügen? Ich weiß nicht, wie gültig dies in Bezug auf die HTML-Validierung ist, wenn Sie sich darüber große Sorgen machen. Dann müssen Sie nur noch das rel-Attribut des Skripts finden und dann json_decode.

z.B

<script type='text/javascript' src='file.js' rel='{"myvar":"somevalue","anothervar":"anothervalue"}'></script>
Dal Hundal
quelle
2
Sie können es mit dem gefälschten Querystring tun. Es ist einfach keine gute Idee. Aber das ist es auch nicht. Das rel-Attribut soll eine Art von Verknüpfungsbeziehung angeben und keine zufälligen Daten in ein Skript-Tag packen.
Matthew Flaschen
1
^^ stimmte zu. Ich kann keine Probleme damit sehen, es einfach so zu lassen, wie es ist, und den <script> var obj1 = "somevalue" </ script> -Ansatz zu verwenden, ist der beste Weg, und ich glaube - der richtige Weg.
Dal Hundal
0

Es ist kein gültiges HTML (glaube ich nicht), aber es scheint zu funktionieren, wenn Sie ein benutzerdefiniertes Attribut für das Skript-Tag auf Ihrer Webseite erstellen :

<script id="myScript" myCustomAttribute="some value" ....>

Greifen Sie dann auf das benutzerdefinierte Attribut im Javascript zu:

var myVar = document.getElementById( "myScript" ).getAttribute( "myCustomAttribute" );

Ich bin mir nicht sicher, ob dies besser oder schlechter ist als das Parsen der Skriptquellzeichenfolge.

Cor
quelle
0

Wenn Sie eine Methode benötigen, die die CSP-Prüfung besteht (die unsichere Inline-Prüfung verhindert), müssen Sie die nonce-Methode verwenden, um sowohl dem Skript als auch der CSP-Direktive einen eindeutigen Wert hinzuzufügen, oder Ihre Werte in den HTML-Code schreiben und erneut lesen.

Nonce-Methode für express.js:

const uuidv4 = require('uuid/v4')

app.use(function (req, res, next) {
  res.locals.nonce = uuidv4()
  next()
})

app.use(csp({
  directives: {
    scriptSrc: [
      "'self'",
      (req, res) => `'nonce-${res.locals.nonce}'`  // 'nonce-614d9122-d5b0-4760-aecf-3a5d17cf0ac9'
    ]
  }
}))

app.use(function (req, res) {
  res.end(`<script nonce="${res.locals.nonce}">alert(1 + 1);</script>`)
})

oder schreiben Sie Werte in die HTML-Methode. in diesem Fall mit Jquery:

<div id="account" data-email="{{user.email}}"></div>
...


$(document).ready(() => {
    globalThis.EMAIL = $('#account').data('email');
}
David Dehghan
quelle