Como passar parâmetros para uma tag Script?

88

Eu li o tutorial DIY widgets - Como incorporar seu site em outro site para XSS Widgets do Dr. Nic.

Estou procurando uma maneira de passar parâmetros para a tag de script. Por exemplo, para fazer o seguinte funcionar:

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

Existe uma maneira de fazer isso?


Dois links interessantes:

Tomer Lichtash
fonte

Respostas:

118

Peço desculpas por responder a uma pergunta super antiga, mas depois de passar uma hora lutando com as soluções acima, optei por coisas mais simples.

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

No script acima:

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

Muito mais fácil do que jquery OU análise de url.

Você pode precisar do polyfil para doucment.currentScript da resposta de @Yared Rodriguez para o IE:

document.currentScript = document.currentScript || (function() {
  var scripts = document.getElementsByTagName('script');
  return scripts[scripts.length - 1];
})();
Richard Fox
fonte
5
Observe que currentScript não funciona no IE. Detalhes
Dehli
Eu adicionei um polyfill para o IE na resposta. O polyfill não funciona?
Richard Fox
2
o polyfill não funciona mais, document.currentScript é somente leitura e não pode ser atribuído se já existir. talvez uma verificação diferente, como se (! document.currentScript) {*** a função polyfill ***} funcionasse melhor
fadomire
2
Minhas desculpas David, sempre torno minhas respostas genéricas para que outras pessoas possam usar a solução sem que os detalhes de implementação inicial aumentem os problemas. No meu exemplo acima, você pode ver que src="..."isto significa, QUALQUER src, não importa :)
Richard Fox
1
@RichardFox obrigado pela resposta, mas só queria comentar que "Não responde à pergunta original: não usa path / to / widget.js" é provavelmente a coisa mais engraçada que li durante toda a semana! Não posso acreditar que você respondeu tão bem quanto fez.
Skintest de
63

É melhor usar o recurso em html5 5 atributos de dados

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

Dentro do arquivo de script http://path.to/widget.js você pode obter os parâmetros desta forma:

<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
fonte
E se id = "myAwesomeWigretNo1" não for sempre assim myAwesomeWigretNo2, mas ou myAwesomeWigretNo681??? Como posso corrigir isso para aceitar uma variável real?
Pathros
9
Pelo que vale a pena, existem outras maneiras de referenciar o script, como document.currentScript(funciona apenas para scripts que não estão em seu próprio arquivo) e colocar um idna <script>tag e localizá-lo por meio disso.
Thunderforge
E se o ID foi alterado por algum outro programador em sua equipe que não tinha ideia de que você usa esse id?
OBender
1
Se você carregar scripts de forma assíncrona, usar um ID é a única opção confiável que eu recomendaria. Obrigado @Thunderforge ... Além disso, qualquer programador deve abster-se de refatorar um código sem um plano de sprint adequado, visto por alguém que tenha uma ideia do que está acontecendo;)
Luca Borrione
Claro que você pode exigir uma ética forte dos desenvolvedores, mas não funcionará no longo prazo ... As pessoas esquecem coisas .... Em um bom design de software, cada bloco calçado deve ser isolado, awesome-pixels.tumblr.com/post/101930002170 /… En.wikipedia.org/wiki/SOLID_(object-oriented_design) Então, eu não discuto que é uma solução boa vs má, apenas mais complexo manter IDs vs não manter :-) Você não planeja carregar o script Async Não vejo razão para carregar usando ID
OBender
17

Entendi. Tipo de hack, mas funciona muito bem:

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];

Eu passo os parâmetros na tag de script como classes:

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

Este artigo ajudou muito.

Tomer Lichtash
fonte
1
O artigo é incrível!
Bartek Skwira
14
As classes devem ser usadas para definir o estilo do elemento, não para passar parâmetros.
kspacja
5
@kspacja Sim e HTML deve conter conteúdo apenas sem estilo, exceto que temos que ordenar precisamente nossas tags DIV para layouts de float e coluna porque CSS não pode realmente fazer o trabalho, e de alguma forma estamos bem com isso. Corte, eu digo. Mas você pode usar os atributos "dados-" se quiser evitar conflito ou se você for do tipo que perde o sono por causa disso.
Jason C
13

Outra maneira é usar metatags. Quaisquer dados que devem ser passados ​​para o seu JavaScript podem ser atribuídos desta forma:

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

Os dados podem ser extraídos das metatags como este (melhor feito em um manipulador de eventos DOMContentLoaded):

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

Absolutamente sem complicações com jQuery ou similares, sem hacks e soluções alternativas necessárias e funciona com qualquer versão HTML que suporte metatags ...

Robidu
fonte
Achei que esse método era de longe o método mais fácil de todos. Funciona como um encanto e me dá exatamente o que preciso. Ótima pergunta e solução fantástica!
arios
10

JQuery tem uma maneira de passar parâmetros de HTML para javascript:

Coloque isso no myhtml.htmlarquivo:

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

No mesmo diretório faça um subscript.jsarquivo e coloque-o lá:

//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);

Resultado da análise:

Ao carregar a página myhtml.html, 'foobar.mp4' será impresso na tela. A variável chamada video_filename foi passada de html para javascript. Javascript o imprimiu na tela e apareceu como embutido no html no pai.

Prova de que o acima funciona:

http://jsfiddle.net/xqr77dLt/

Eric Leschinski
fonte
7

Se você estiver usando jquery, você pode querer considerar seu método de dados.

Usei algo semelhante ao que você está tentando em sua resposta, mas assim:

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

Você também pode criar uma função que permite pegar os parâmetros GET diretamente (isso é o que eu uso com frequência):

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
fonte
4

é um tópico muito antigo, eu sei, mas isso também pode ajudar se alguém chegar aqui depois de procurar uma solução.

Basicamente, usei o document.currentScript para obter o elemento de onde meu código está sendo executado e filtro usando o nome da variável que estou procurando. Fiz isso estendendo currentScript com um método chamado "get", para que possamos buscar o valor dentro desse script usando:

document.currentScript.get('get_variable_name');

Desta forma, podemos usar o URI padrão para recuperar as variáveis ​​sem adicionar atributos especiais.

Este é o código final

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

Eu estava esquecendo do IE :) Não poderia ser mais fácil ... Bem, eu não mencionei que document.currentScript é uma propriedade HTML5. Ele não foi incluído em diferentes versões do IE (testei até o IE11 e ainda não estava lá). Para compatibilidade com o IE, adicionei esta parte ao código:

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

O que estamos fazendo aqui é definir algum código alternativo para o IE, que retorna o objeto de script atual, que é necessário na solução para extrair parâmetros da propriedade src. Esta não é a solução perfeita para o IE, pois existem algumas limitações; Se o script for carregado de forma assíncrona. Os navegadores mais recentes devem incluir a propriedade ".currentScript".

Espero que ajude.

Yared Rodriguez
fonte
3

Graças ao jQuery, uma solução simples compatível com HTML5 é criar uma tag HTML extra, como div, para armazenar os dados.

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);
    })
});

Demonstração ao vivo com o código acima: http://codepen.io/anon/pen/KzzNmQ?editors=1011#0

Na demonstração ao vivo, é possível ver os dados dos atributos data- * do HTML5 a serem concatenados e impressos no log.

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

gagallo7
fonte
1
Passei por algumas das outras soluções, mas esta foi a que funcionou melhor e também é bastante simples de implementar. obrigado!
Erik Kalkoken
Essa deve ser a solução aceita, pois permite que você faça referência ao script por ID e é HTML5 válido.
Tim S,
2

Coloque os valores necessários em algum lugar onde o outro script possa recuperá-los, como uma entrada oculta, e extraia esses valores de seu contêiner ao inicializar o novo script. Você pode até colocar todos os seus parâmetros como uma string JSON em um campo oculto.

bwest
fonte
Obrigado por responder. Os parâmetros são, na verdade, inseridos pelos usuários (que incorpora essa tag de script em seu código). O que então?
Tomer Lichtash
A única coisa em que posso pensar se você não tem controle sobre os scripts de cliente / servidor é pegar a entrada do usuário e usá-la para gerar um arquivo .js específico com a entrada incorporada nele, e isso assumindo que você está no controle de coleta e processamento de suas entradas.
bwest
Não responde à pergunta original: onde colocar os argumentos quando não há forma de manter o campo Oculto?
David Spector,
2

Crie um atributo que contenha uma lista dos parâmetros, assim:

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

Em seguida, em seu JavaScript, obtenha os parâmetros como uma matriz:

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
Místico
fonte
Quais são as desvantagens dessa abordagem?
Tronathan
@Tronathan não há desvantagens reais para esta abordagem e há um polyfill incluído para melhor suporte do navegador. A única desvantagem que vejo aqui é não poder incluir vírgulas nos parâmetros, o que geralmente não é um problema, e você pode compensar isso alterando o delimitador para um caractere que você não está planejando usar.
Místico
2

Eu queria soluções com o máximo possível de suporte para navegadores antigos. Caso contrário, eu diria que tanto o currentScript quanto o método de atributos de dados seriam mais elegantes.

Este é o único desses métodos que ainda não foi mencionado aqui. Particularmente, se por algum motivo você tiver grandes quantidades de dados, a melhor opção pode ser:

localStorage

/* 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');

O localStorage tem suporte completo a navegadores modernos e também um suporte surpreendentemente bom para navegadores mais antigos, desde o IE 8, Firefox 3,5 e Safari 4 [onze anos atrás], entre outros.

Se você não tem muitos dados, mas ainda deseja amplo suporte ao navegador, talvez a melhor opção seja:

Meta tags [por Robidu]

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

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

A falha disso é que o lugar correto para colocar metatags [até HTML 4] é na tag head, e você pode não querer esses dados lá. Para evitar isso, ou colocar metatags no corpo, você pode usar:

Parágrafo oculto

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

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

Para obter ainda mais suporte ao navegador, você pode usar uma classe CSS em vez do atributo oculto:

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

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

Esta é a solução para 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
fonte