Comment passer des paramètres à une balise Script?

89

J'ai lu le tutoriel DIY widgets - Comment intégrer votre site sur un autre site pour XSS Widgets par Dr. Nic.

Je cherche un moyen de transmettre des paramètres à la balise de script. Par exemple, pour faire fonctionner les éléments suivants:

<script src="http://path/to/widget.js?param_a=1&amp;param_b=3"></script>

Y a-t-il un moyen de faire cela?


Deux liens intéressants:

Tomer Lichtash
la source

Réponses:

118

Je m'excuse d'avoir répondu à une question très ancienne, mais après avoir passé une heure à lutter avec les solutions ci-dessus, j'ai opté pour des choses plus simples.

<script src=".." one="1" two="2"></script>

À l'intérieur du script ci-dessus:

document.currentScript.getAttribute('one'); //1
document.currentScript.getAttribute('two'); //2

Beaucoup plus facile que l'analyse de jquery OU d'url.

Vous pourriez avoir besoin du polyfil pour doucment.currentScript de la réponse de @Yared Rodriguez pour IE:

document.currentScript = document.currentScript || (function() {
  var scripts = document.getElementsByTagName('script');
  return scripts[scripts.length - 1];
})();
Richard Fox
la source
5
Notez que currentScript ne fonctionne pas dans IE. Détails
Dehli
J'ai ajouté un polyfill pour IE dans la réponse. Le polyfill ne fonctionne-t-il pas?
Richard Fox
2
le polyfill ne fonctionne plus, document.currentScript est en lecture seule et ne peut pas être affecté s'il existe déjà. peut-être une vérification différente comme si (! document.currentScript) {*** la fonction polyfill ***} fonctionnerait mieux
fadomire
2
Mes excuses David, je fais toujours mes réponses génériques afin que d'autres puissent utiliser la solution sans que les détails de mise en œuvre initiale ne viennent s'ajouter aux problèmes. Dans mon exemple ci-dessus, vous pouvez voir src="..."Ceci est censé signifier, N'IMPORTE QUEL src, n'a pas d'importance :)
Richard Fox
1
@RichardFox merci pour la réponse, mais j'ai juste dû commenter que "Ne répond pas à la question originale: n'utilise pas le chemin / vers / widget.js" est probablement la chose la plus drôle que j'ai lue toute la semaine! Je ne peux pas croire que vous ayez répondu aussi bien que vous l'avez fait.
Skintest
63

Il est préférable d'utiliser la fonctionnalité dans les attributs de données html5 5

<script src="http://path.to/widget.js" data-width="200" data-height="200">
</script>

Dans le fichier de script http://path.to/widget.js, vous pouvez obtenir les paramètres de cette manière:

<script>
function getSyncScriptParams() {
         var scripts = document.getElementsByTagName('script');
         var lastScript = scripts[scripts.length-1];
         var scriptName = lastScript;
         return {
             width : scriptName.getAttribute('data-width'),
             height : scriptName.getAttribute('data-height')
         };
 }
</script>
OBender
la source
Et si l'id = "myAwesomeWigretNo1" n'est pas toujours comme ça mais myAwesomeWigretNo2, ou myAwesomeWigretNo681??? Comment puis-je résoudre ce problème pour accepter une variable réelle?
Pathros
9
Pour ce que cela vaut, il existe d'autres moyens de référencer le script à la place, comme document.currentScript(ne fonctionne que pour les scripts qui ne sont pas dans leur propre fichier) et en plaçant un idsur la <script>balise et en le trouvant par là.
Thunderforge
Et si l'ID était changé par un autre programmeur de votre équipe qui n'avait aucune idée que vous l'utilisiez?
OBender le
1
Si vous chargez des scripts de manière asynchrone, l'utilisation d'un ID est la seule option fiable que je recommanderais. Merci @Thunderforge ... De plus, tout programmeur devrait s'abstenir de refactoriser un code sans un plan de sprint approprié aperçu par quelqu'un qui a une idée de ce qui se passe;)
Luca Borrione
Bien sûr, vous pouvez exiger une éthique forte de la part des développeurs, mais cela ne fonctionnera pas sur le long terme ... Les gens oublient des choses .... Dans une bonne conception de logiciel, chaque bloc doit être isolé, awesome-pixels.tumblr.com/post/101930002170 /… En.wikipedia.org/wiki/SOLID_(object-oriented_design) Donc je ne dis pas que c'est une bonne ou une mauvaise solution, il est juste plus complexe de maintenir les ID que de ne pas maintenir :-) Vous n'avez pas l'intention de charger le script Async Je ne vois aucune raison de charger en utilisant ID
OBender
17

Je l'ai. Une sorte de hack, mais cela fonctionne plutôt bien:

var params = document.body.getElementsByTagName('script');
query = params[0].classList;
var param_a = query[0];
var param_b = query[1];
var param_c = query[2];

Je passe les paramètres dans la balise script en tant que classes:

<script src="http://path.to/widget.js" class="2 5 4"></script>

Cet article a beaucoup aidé.

Tomer Lichtash
la source
1
L'article est génial!
Bartek Skwira le
14
Les classes doivent être utilisées pour styliser l'élément pour ne pas transmettre de paramètres.
kspacja
5
@kspacja Ouais et HTML ne devrait contenir que du contenu sans style, sauf que nous devons commander précisément nos balises DIV pour les mises en page flottantes et colonnes parce que CSS ne peut pas réellement faire le travail, et nous sommes en quelque sorte d'accord avec cela. Hack, dis-je. Mais vous pouvez utiliser les attributs "data-" si vous voulez éviter les conflits ou si vous êtes du genre à perdre le sommeil.
Jason C
13

Une autre façon consiste à utiliser des balises meta. Toutes les données censées être transmises à votre JavaScript peuvent être attribuées comme suit:

<meta name="yourdata" content="whatever" />
<meta name="moredata" content="more of this" />

Les données peuvent ensuite être extraites des balises meta comme ceci (mieux fait dans un gestionnaire d'événements DOMContentLoaded):

var data1 = document.getElementsByName('yourdata')[0].content;
var data2 = document.getElementsByName('moredata')[0].content;

Absolument aucun problème avec jQuery ou autres, aucun hacks et solutions de contournement nécessaires, et fonctionne avec n'importe quelle version HTML qui prend en charge les balises meta ...

Robidu
la source
Je pensais que cette méthode était de loin la méthode la plus simple de tous. Cela fonctionne comme un charme et me donne exactement ce dont j'ai besoin. Excellente question et solution fantastique!
arios
10

JQuery a un moyen de passer des paramètres de HTML à javascript:

Mettez ceci dans le myhtml.htmlfichier:

<!-- Import javascript -->
<script src="//code.jquery.com/jquery-1.11.2.min.js"></script>
<!-- Invoke a different javascript file called subscript.js -->
<script id="myscript" src="subscript.js" video_filename="foobar.mp4">/script>

Dans le même répertoire, créez un subscript.jsfichier et placez-le ici:

//Use jquery to look up the tag with the id of 'myscript' above.  Get 
//the attribute called video_filename, stuff it into variable filename.
var filename = $('#myscript').attr("video_filename");

//print filename out to screen.
document.write(filename);

Analyser le résultat:

Le chargement de la page myhtml.html affiche «foobar.mp4» à l'écran. La variable appelée video_filename a été passée du html au javascript. Javascript l'a imprimé à l'écran, et il est apparu comme intégré dans le html du parent.

jsfiddle preuve que ce qui précède fonctionne:

http://jsfiddle.net/xqr77dLt/

Eric Leschinski
la source
7

Si vous utilisez jquery, vous voudrez peut-être considérer leur méthode de données.

J'ai utilisé quelque chose de similaire à ce que vous essayez dans votre réponse, mais comme ceci:

<script src="http://path.to/widget.js" param_a = "2" param_b = "5" param_c = "4">
</script>

Vous pouvez également créer une fonction qui vous permet de saisir directement les paramètres GET (c'est ce que j'utilise fréquemment):

function $_GET(q,s) {
    s = s || window.location.search;
    var re = new RegExp('&'+q+'=([^&]*)','i');
    return (s=s.replace(/^\?/,'&').match(re)) ? s=s[1] : s='';
}

// Grab the GET param
var param_a = $_GET('param_a');
rg88
la source
4

c'est un fil très ancien, je sais, mais cela pourrait aussi aider si quelqu'un arrive ici une fois qu'il cherche une solution.

Fondamentalement, j'ai utilisé le document.currentScript pour obtenir l'élément à partir duquel mon code s'exécute et je filtre en utilisant le nom de la variable que je recherche. Je l'ai fait en étendant currentScript avec une méthode appelée "get", nous pourrons donc récupérer la valeur à l'intérieur de ce script en utilisant:

document.currentScript.get('get_variable_name');

De cette façon, nous pouvons utiliser l'URI standard pour récupérer les variables sans ajouter d'attributs spéciaux.

Ceci est le code final

document.currentScript.get = function(variable) {
    if(variable=(new RegExp('[?&]'+encodeURIComponent(variable)+'=([^&]*)')).exec(this.src))
    return decodeURIComponent(variable[1]);
};

J'oubliais IE :) Cela ne pourrait pas être plus simple ... Eh bien, je n'ai pas mentionné que document.currentScript est une propriété HTML5. Il n'a pas été inclus pour différentes versions d'IE (j'ai testé jusqu'à IE11, et ce n'était pas encore là). Pour la compatibilité IE, j'ai ajouté cette partie au code:

document.currentScript = document.currentScript || (function() {
  var scripts = document.getElementsByTagName('script');
  return scripts[scripts.length - 1];
})();

Ce que nous faisons ici est de définir un code alternatif pour IE, qui renvoie l'objet de script actuel, qui est requis dans la solution pour extraire les paramètres de la propriété src. Ce n'est pas la solution parfaite pour IE car il existe certaines limitations; Si le script est chargé de manière asynchrone. Les navigateurs plus récents doivent inclure la propriété ".currentScript".

J'espère que cela aide.

Yared Rodriguez
la source
3

Grâce à jQuery, une solution simple compatible HTML5 consiste à créer une balise HTML supplémentaire, comme div, pour stocker les données.

HTML :

<div id='dataDiv' data-arg1='content1' data-arg2='content2'>
  <button id='clickButton'>Click me</button>
</div>

JavaScript :

$(document).ready(function() {
    var fetchData = $("#dataDiv").data('arg1') + 
                    $("#dataDiv").data('arg2') ;

    $('#clickButton').click(function() {
      console.log(fetchData);
    })
});

Démo en direct avec le code ci-dessus: http://codepen.io/anon/pen/KzzNmQ?editors=1011#0

Sur la démo en direct, on peut voir les données des attributs HTML5 data- * à concaténer et à imprimer dans le journal.

Source: https://api.jquery.com/data/

gagallo7
la source
1
J'ai parcouru certaines des autres solutions, mais c'est celle qui a le mieux fonctionné et qui est également assez simple à mettre en œuvre. Merci!
Erik Kalkoken
Cela devrait être la solution acceptée, car elle vous permet de référencer le script par ID et est HTML5 valide.
Tim S
2

Placez les valeurs dont vous avez besoin à un endroit où l'autre script peut les récupérer, comme une entrée masquée, puis extrayez ces valeurs de leur conteneur lorsque vous initialisez votre nouveau script. Vous pouvez même mettre tous vos paramètres sous forme de chaîne JSON dans un champ caché.

bwest
la source
Merci de répondre. Les paramètres sont en fait saisis par les utilisateurs (qui intègrent cette balise de script dans leur code). Et alors?
Tomer Lichtash
La seule chose à laquelle je peux penser si vous n'avez pas le contrôle sur les deux scripts client / serveur est de prendre les entrées des utilisateurs et de les utiliser pour générer un fichier .js spécifique avec leur entrée intégrée, et cela en supposant que vous êtes en contrôle de recueillir et de traiter leurs contributions.
bwest
Ne répond pas à la question d'origine: où placer les arguments quand il n'y a pas de formulaire pour contenir le champ Caché?
David Spector
2

Créez un attribut qui contient une liste des paramètres, comme ceci:

<script src="http://path/to/widget.js" data-params="1, 3"></script>

Ensuite, dans votre JavaScript, récupérez les paramètres sous forme de tableau:

var script = document.currentScript || 
/*Polyfill*/ Array.prototype.slice.call(document.getElementsByTagName('script')).pop();

var params = (script.getAttribute('data-params') || '').split(/, */);

params[0]; // -> 1
params[1]; // -> 3
Mystique
la source
Quels sont les inconvénients de cette approche?
Tronathan le
@Tronathan, il n'y a pas de réels inconvénients à cette approche et un polyfill est inclus pour une meilleure prise en charge du navigateur. Le seul inconvénient que je vois ici est de ne pas pouvoir inclure des virgules dans les paramètres, ce qui n'est généralement pas un problème, et vous pouvez compenser cela en changeant le délimiteur en un caractère que vous n'avez pas l'intention d'utiliser.
mystique
2

Je voulais des solutions avec autant de support que possible des anciens navigateurs. Sinon, je dirais que la méthode currentScript ou la méthode des attributs de données serait la plus élégante.

C'est la seule de ces méthodes qui n'a pas encore été évoquée ici. En particulier, si pour une raison quelconque vous avez de grandes quantités de données, la meilleure option pourrait être:

stockage local

/* On the original page, you add an inline JS Script: */
<script>
   localStorage.setItem('data-1', 'I got a lot of data.');
   localStorage.setItem('data-2', 'More of my data.');
   localStorage.setItem('data-3', 'Even more data.');
</script>

/* External target JS Script, where your data is needed: */
var data1 = localStorage.getItem('data-1');
var data2 = localStorage.getItem('data-2');
var data3 = localStorage.getItem('data-3');

localStorage a une prise en charge complète des navigateurs modernes, et une prise en charge étonnamment bonne des anciens navigateurs aussi, depuis IE 8, Firefox 3,5 et Safari 4 [il y a onze ans] entre autres.

Si vous ne disposez pas de beaucoup de données, mais que vous souhaitez tout de même une prise en charge étendue du navigateur, la meilleure option est peut-être:

Balises Meta [par Robidu]

/* HTML: */
<meta name="yourData" content="Your data is here" />

/* JS: */
var data1 = document.getElementsByName('yourData')[0].content;

Le défaut de ceci, c'est que le bon endroit pour mettre les balises meta [jusqu'à HTML 4] est dans la balise head, et vous pourriez ne pas vouloir ces données là-haut. Pour éviter cela, ou mettre des balises meta dans le corps, vous pouvez utiliser un:

Paragraphe masqué

/* HTML: */
<p hidden id="yourData">Your data is here</p>

/* JS: */
var yourData = document.getElementById('yourData').innerHTML;

Pour encore plus de prise en charge du navigateur, vous pouvez utiliser une classe CSS au lieu de l'attribut masqué:

/* CSS: */
.hidden {
   display: none;
}

/* HTML: */
<p class="hidden" id="yourData">Your data is here</p>
Fom
la source
2

C'est la solution pour jQuery 3.4

<script src="./js/util.js" data-m="myParam"></script>
$(document).ready(function () {
    var m = $('script[data-m][data-m!=null]').attr('data-m');
})
Greil Omatics
la source