将参数传递到JavaScript文件


163

通常,我会想要使用一个JavaScript文件,该文件要求在我的网页中定义某些变量。

所以代码是这样的:

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

但是我想做的是:

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

我尝试了不同的方法,最好的方法是解析查询字符串,如下所示:

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

然后搜索我的价值观。

我想知道是否还有另一种方法可以在不构建函数来解析我的字符串的情况下。

你们都知道其他方法吗?


9
这是一个重复的问题(stackoverflow.com/questions/1017424/…),我认为这是一个错误的设计。使用第一个变量解决方案(好的),或者让脚本定义一个函数,然后用变量调用(更好),这要简单得多。
Matthew Flaschen

我正在寻找一种利用新ECMAScript 6功能的更新解决方案...(如果有)
Chef_Code

如果站点是HTTPS并且完全启用了CSP,则使用任何内部脚本都将触发CSP报告。CSP文档中给出的原因是允许内部元素可以使注入更加容易。
David Spector

Answers:


207

如果可能,我建议不要使用全局变量。使用名称空间和OOP将参数传递给对象。

此代码属于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]);
        }
    };
}());

并在您的html文件中:

<script type="text/javascript" src="file.js"></script>
<script type="text/javascript">
   MYLIBRARY.init(["somevalue", 1, "controlId"]);
   MYLIBRARY.helloWorld();
</script>

4
@Naeem-当MYLIBRARY.init([“ somevalue”,1,“ controlId”]);时,file.js的加载时间为100%被执行?也许我们需要准备好要放的文件?
Darius.V 2014年

2
1)如果存在MYLIBRARY,则使用它或定义一个新对象。目的是创建一个全局名称空间,通常我将使用子名称空间,因此此行有助于避免重新定义顶级名称空间。2)是的,它已经创建了一个单例。
Naeem Sarfraz 2015年

1
我已经举例说明了这个想法:http
//plnkr.co/edit/iE0Vr7sszfqrrDIsR8Wi?p=preview

1
这个表达是什么意思?var MYLIBRARY = MYLIBRARY || (function(){}());?为什么应将MYLIBRARY其设置为布尔值?
亚历克斯


79

您可以传递具有任意属性的参数。这在所有最近的浏览器中都有效。

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

在somefile.js中,您可以通过以下方式获取传递的变量值:

........

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

...等等...


1
非常好的解决方案,甚至可以与async属性一起使用。
ViRuSTriNiTy

2
较旧,但对于那些使用Google搜索的用户来说,如果您需要解决CSP(内容安全策略),那就太好了。我们使用许多脚本,其中将根据语言资源和API密钥等确定的字符串传递到JS文件中。
monkeySeeMonkeyDo

2
请注意,您也可以使用document.currentScript,请参见caniuse.com/#feat=document-currentscript以获取兼容性(或使用polyfill
Yves M.

$(..)语法是jQuery的,不要忘了把它列入。
蒂莫

48

我遇到的另一个想法是将an分配id<script>元素并将参数作为data-*属性传递。结果<script>标签看起来像这样:

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

然后,脚本可以使用id以编程方式定位自身并解析参数。给定前面的<script>标签,可以像这样检索名称:

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

我们得到name=helper


4
如果您不想依赖id属性,还可以使helper.js脚本遍历script页面上的所有标记scr="helper.js",并使用来查找一个标记,然后提取data-name
jvannistelrooy 2014年

1
@jvannistelrooy我还没有尝试过,但是我相信人们应该能够通过jquery和一个聪明的选择器来访问脚本,如下所示var this_js_script = $('script[src*=somefile]');:(从上面复制)
LosManos 2014年

19

检出此URL。它完全可以满足要求。

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

非常感谢作者。为了快速参考,我粘贴了以下主要逻辑:

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

1
我喜欢此解决方案,但对其进行了少许修改以使用片段标识符,以便它不会破坏缓存:var frag = myScript.src.replace(/ ^ [^ \#] + \#?/,'') ;
马克·诺丁汉

哦,我发现,只要您对它进行urlencode,就可以在其中放入JSON。
马克·诺丁汉

@ user378221-您确定这将始终获得正确的文件吗?我的意思是这假设该文件是最后一个。如果在执行之前加载了更多脚本标签怎么办?我不知道这是否可行,但是我认为文档不等待代码执行完成以加载其他标签吗?
Darius.V 2014年

更好地使用,因为不赞成使用此函数,所以使用unegodURI()或decodeURIComponent()代替unescape。
史蒂夫·柴尔德斯

@ Darius.V这适用于非异步脚本。我更喜欢将选项1和选项5用作后备
路加福音

14

您使用全局变量:-D。

像这样:

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

“ file.js”中的JavaScript代码可以访问obj1obj2没有问题。

编辑只是想补充一点,如果“file.js”想要检查obj1obj2甚至已经宣布你可以用下面的函数。

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

希望这可以帮助。


这将在IE中引发未引用的错误。该函数的首选主体为return typeof window[$Name] !== 'undefined';。请注意,您将向该函数传递包含变量名称的字符串。通过可以简单地检查调用代码中是否存在变量(无法将其实现为函数),这可能会更容易if (typeof var !== 'undefined')
安东尼·迪桑蒂

2
哦,永远不要使用IE。抱歉。
NawaMan

是的,但按我的JavaScript的经验,我会用全局变量只为模块命名空间和暴露程度不亚于需要什么(如初始化代码,一些属性),如图所示这里。在复杂项目中出现命名冲突太容易了……花费数小时的时间,然后发现您已经在项目的其他地方使用了变量。
马特

您可以省略var
蒂莫

12

这是一个非常仓促的概念证明。

我确信至少有2个地方可以改进,而且我也肯定这不会在野外长期存在。欢迎提供任何使它更美观或更有用的反馈。

关键是为脚本元素设置ID。唯一要注意的是,这意味着您只能调用一次脚本,因为它会寻找该ID来提取查询字符串。相反,如果脚本循环遍历所有查询元素以查看它们是否指向该查询元素,并且使用该脚本元素的最后一个实例,则可以修复此问题。无论如何,代码如下:

脚本被调用:

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

通过以下页面调用脚本:

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

<h1 id="docTitle"></h1>
<p id="docText"></p>

所以eval实际上会将值设置为全局变量。
rodmjay 2012年

1
评估是邪恶的逃跑
巴里·查普曼

@barrychapman-天哪,2010年。我很惊讶那里没有10个其他危险信号。
安东尼

9

可能很简单

例如

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

然后可以将查询字符串转换为json,如下所示

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

然后可以使用像

console.log(json.id);

6

如果您使用的是jQuery之类的Javascript框架,则可以轻松完成此操作。像这样

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

现在,您可以通过拆分作为变量参数来使用这些参数。

可以在没有任何框架的情况下完成相同的过程,但是将花费更多的代码行。


2
还有一个名为parseQuery的jQuery插件,它使此操作变得更加容易:plugins.jquery.com/project/parseQuery
Jimmy Cuadra 2010年

@JimmyCuadra-很遗憾,您提供的链接已断开。但是我在jQuery本身中找到了一种类似的方法:jQuery.param()
马特

1

好吧,您可以使用任何脚本语言来构建javascript文件,并在每次请求时将变量注入文件中。您必须告诉您的网络服务器不要静态地分发js文件(使用mod_rewrite就足够了)。

请注意,尽管这些js文件不断更改,但它们会丢失所有缓存。

再见


1
不明白为什么这被否决了。这是依靠服务器端逻辑的完美有效的解决方案。据我所知,OP并不要求它是完全使用JavaScript的解决方案。
Anoyz 2015年

@aefxx-你是对的。在<script>块内部,您可以使用MyModule.Initialize( '<%: Model.SomeProperty%>', '<%: Model.SomeOtherProperty%>', ...);服务器上呈现的内容。注意:<%:<%=发送值时不转义时转义该值。MyModule将是一个命名空间(即.js文件中的一个自调用变量,该变量公开了函数Initialize)。我支持您的回答,因为这是有益的贡献。
马特

注:这个概念,如何创建一个包含更详细描述的暴露性的模块在这里这个页面上。
马特

1

好的问题和有创意的答案,但是我的建议是使您的方法参数化,这应该可以解决所有问题而没有任何技巧。

如果您具有功能:

function A()
{
    var val = external_value_from_query_string_or_global_param;
}

您可以将其更改为:

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

我认为这是最自然的方法,您无需创建有关“文件参数”的额外文档,也可以收到相同的信息。如果您允许其他开发人员使用您的js文件,这将特别有用。


0

不,您无法通过在JS文件URL的querystring部分添加变量来真正做到这一点。如果它编写代码部分来解析困扰您的字符串,也许另一种方法是对变量进行json编码,然后将其放入类似标记的rel属性的位置?我不知道这在HTML验证方面有多有效,如果您对此非常担心的话。然后,您只需要找到脚本的rel属性,然后对其进行json_decode即可。

例如

<script type='text/javascript' src='file.js' rel='{"myvar":"somevalue","anothervar":"anothervalue"}'></script>

2
您可以使用伪造的查询字符串来实现。这不是一个好主意。但这不是。rel属性用于指定链接关系的类型,而不是将随机数据填充到脚本标签中。
Matthew Flaschen

1
^^同意。我只看到它,并使用<script> var obj1 =“ somevalue” </ script>方法,这是最好的方法,我相信-正确的方法,看不到任何问题。
Dal Hundal '02

0

这不是有效的html(我不认为),但是如果您在网页中为script标签创建了自定义属性,则它似乎可以工作

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

然后在javascript中访问自定义属性:

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

不知道这比解析脚本源字符串好还是坏。


0

如果需要通过CSP检查的方式(禁止不安全的内联),则必须使用nonce方法向脚本和CSP指令添加唯一值,或者将值写入html并再次读取它们。

express.js的Nonce方法:

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

或将值写入html方法。在这种情况下,使用Jquery:

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


$(document).ready(() => {
    globalThis.EMAIL = $('#account').data('email');
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.