将参数传递给 JavaScript 文件
Posted
技术标签:
【中文标题】将参数传递给 JavaScript 文件【英文标题】:Passing parameters to JavaScript files 【发布时间】:2011-01-12 13:04:53 【问题描述】:我通常会有一个我想要使用的 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();
然后搜索我的价值观。
我想知道是否有另一种方法可以在不构建函数来解析我的字符串的情况下做到这一点。
你们都知道其他方法吗?
【问题讨论】:
这是一个重复的问题 (***.com/questions/1017424/…),在我看来这是一个被误导的设计。要么使用你的第一个变量解决方案(好的),要么让脚本定义一个函数,然后用变量调用它(更好)。 我正在寻找一个更新的解决方案,利用新的 ECMAScript 6 功能......如果有的话 如果站点是 HTTPS 并且完全启用了 CSP,则使用任何内部脚本都会触发 CSP 报告。 CSP 文档中给出的原因是允许内部元素可以使注入更容易。 我在我的 html 中使用 Script 标签来包含一个 JavaScript 文件,并在 src 属性中指定参数。但在 JavaScript 方面,window.location 不包含参数。如何找回它们? 【参考方案1】:如果可能,我建议不要使用全局变量。使用命名空间和 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>
【讨论】:
@Naeem - 当 MYLIBRARY.init(["somevalue", 1, "controlId"]);被执行?也许我们需要准备好把它放在文件上? 1) 如果 MYLIBRARY 存在,则使用它或定义一个新对象。目的是创建一个全局命名空间,通常我会使用子命名空间,所以这一行有助于避免重新定义***命名空间。 2) 是的,它创建了一个单例。 这个想法我做了一个例子:http://plnkr.co/edit/iE0Vr7sszfqrrDIsR8Wi?p=preview 这个表达是什么意思?var MYLIBRARY = MYLIBRARY || (function()());
?为什么要将MYLIBRARY
设置为布尔值?
@Alexander,看我上面的评论***.com/questions/2190801/…【参考方案2】:
您可以传递具有任意属性的参数。这适用于所有最新的浏览器。
<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
...等等...
【讨论】:
非常好的解决方案,这甚至适用于 async 属性。 旧但对于那些谷歌搜索:如果您需要解决 CSP(内容安全策略),这非常好。我们使用了很多脚本,其中我们将由语言资源和 API 密钥等确定的字符串传递到 JS 文件中。 请注意,您也可以使用document.currentScript
,请参阅caniuse.com/#feat=document-currentscript 以了解兼容性(或使用polyfill)
$(..)
语法是 jquery,不要忘记包含它。【参考方案3】:
我遇到的另一个想法是将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
【讨论】:
如果你不想依赖id属性,你也可以让你的helper.js
脚本循环遍历页面上所有script
标签,寻找带有scr="helper.js"
的标签,然后提取data-name
。
@jvannistelrooy 我没有尝试过,但我相信应该能够通过 jquery 和一个聪明的选择器访问脚本:var this_js_script = $('script[src*=somefile]');
(复制自 above)【参考方案4】:
查看此网址。它完全符合要求。
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;
【讨论】:
我喜欢这个解决方案,但稍作修改,使用片段标识符,这样它就不会破坏缓存: var frag = myScript.src.replace(/^[^\#]+ \#?/,''); 哦,我发现将 JSON 放入其中是可行的,只要您对其进行 urlencode 即可。 @user378221 - 你确定这总能得到正确的文件吗?我的意思是假设这个文件是最后一个。如果在执行之前加载了更多脚本标签怎么办?我不知道这是否可能,但我假设文档不会等待代码执行完成来加载其他标签? 最好使用 decodeURI() 或 decodeURIComponent() 而不是 unescape,因为该函数已被弃用。 @Darius.V 这适用于非异步脚本。我更喜欢使用option 1 with option 5 as a fallback。【参考方案5】:你使用全局变量:-D。
像这样:
<script type="text/javascript">
var obj1 = "somevalue";
var obj2 = "someothervalue";
</script>
<script type="text/javascript" src="file.js"></script">
'file.js' 中的 JavaScript 代码可以毫无问题地访问obj1
和obj2
。
编辑只是想补充一点,如果'file.js'想要检查obj1
和obj2
是否已经被声明,你可以使用以下函数。
function IsDefined($Name)
return (window[$Name] != undefined);
希望这会有所帮助。
【讨论】:
这将在 IE 中引发未引用的错误。该函数的首选主体是return typeof window[$Name] !== 'undefined';
。请注意,您将向该函数传递一个包含变量名称的字符串。通过if (typeof var !== 'undefined')
简单地检查调用代码中是否存在变量(这不能作为函数实现)可能更容易。
是的,但根据我对 JavaScript 的经验,我只会将全局变量用于模块命名空间,并尽可能多地公开所需的变量(如初始化代码、一些属性),如图所示 here .在复杂的项目中很容易出现命名冲突......花费数小时然后发现您已经在项目的其他地方使用了该变量。
你可以省略var
。【参考方案6】:
这是一个非常仓促的概念证明。
我确信至少有 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 实际上会将值设置为全局变量...非常酷。 eval 是邪恶的逃跑 @barrychapman - 哦,伙计,2010 年。我很惊讶那里没有 10 个其他危险信号。【参考方案7】:可能很简单
例如
<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, '":"')
+ '"');
然后可以用like
console.log(json.id);
【讨论】:
【参考方案8】:如果您使用 jQuery 等 Javascript 框架,这可以轻松完成。 像这样,
var x = $('script:first').attr('src'); //Fetch the source in the first script tag
var params = x.split('?')[1]; //Get the params
现在您可以通过拆分来使用这些参数作为可变参数。
同样的过程可以在没有任何框架的情况下完成,但需要更多的代码行。
【讨论】:
还有一个名为 parseQuery 的 jQuery 插件可以让这一切变得更简单:plugins.jquery.com/project/parseQuery @JimmyCuadra - 不幸的是,您提供的链接已损坏。但我在 jQuery 本身中发现了类似的方法:jQuery.param()【参考方案9】:好吧,您可以使用任何脚本语言构建 javascript 文件,并在每次请求时将变量注入文件中。您必须告诉您的网络服务器不要静态输出 js 文件(使用 mod_rewrite 就足够了)。
请注意,由于这些 js 文件不断更改,您会丢失任何缓存。
再见。
【讨论】:
不明白为什么这被否决了。这是诉诸服务器端逻辑的完全有效的解决方案。据我所知,OP 并不要求它是一个完全 JavaScript 的解决方案。 @aefxx - 你是对的。在<script>
块内,您可以使用类似MyModule.Initialize( '<%: Model.SomeProperty%>', '<%: Model.SomeOtherProperty%>', ...);
的东西,它在服务器上呈现。注意:<%:
转义值,而<%=
发送未转义的值。 MyModule
将是一个命名空间(即 .js 文件中的一个变量,它是自调用的,它公开了函数 Initialize
)。我赞成你的回答,因为这是一个有用的贡献。
注意:关于如何创建包含公开属性的模块的概念在此页面上here 进行了更详细的描述。【参考方案10】:
不错的问题和有创意的答案,但我的建议是让您的方法参数化,这样可以解决您的所有问题而无需任何技巧。
如果你有功能:
function A()
var val = external_value_from_query_string_or_global_param;
您可以将其更改为:
function B(function_param)
var val = function_param;
我认为这是最自然的方法,您不需要创建有关“文件参数”的额外文档,并且您会收到相同的信息。如果您允许其他开发人员使用您的 js 文件,这将特别有用。
【讨论】:
【参考方案11】:在这里,我找到了另一种做同样事情的方法。在需要的 js 文件 [cttricks.js 因为我用它来测试,你可以有你的任何 .js 文件],我们将简单地列出所有脚本元素并获取所需的一个总是会在最后一个索引。然后从中获取“.attributes.src.value”。
现在,在任何脚本调用的情况下,它都是
<script src="./cttricks.js?data1=Hello&data2=World"></script>
在 cttricks.js 脚本文件中,
var scripts = document.getElementsByTagName('script');
var jsFile = new URL("http://" + scripts[scripts.length-1].attributes.src.value);
/*get value from query parameters*/
console.log(jsFile.searchParams.get("data1"));
console.log(jsFile.searchParams.get("data2"));
享受!!
【讨论】:
【参考方案12】:不,您不能通过将变量添加到 JS 文件 URL 的查询字符串部分来真正做到这一点。如果它编写代码部分来解析困扰你的字符串,也许另一种方法是对你的变量进行 json 编码并将它们放在标签的 rel 属性中?我不知道这在 HTML 验证方面有多有效,如果那是您非常担心的事情。然后你只需要找到脚本的 rel 属性,然后 json_decode 。
例如
<script type='text/javascript' src='file.js' rel='"myvar":"somevalue","anothervar":"anothervalue"'></script>
【讨论】:
你可以用假的查询字符串来做到这一点。这不是一个好主意。但这也不是。 rel 属性旨在指定一种链接关系类型,而不是将随机数据塞进脚本标签中。 ^^ 同意。我看不出有任何问题,只是保持原样,使用 方法,这是最好的方法,我相信 - 正确的方法。【参考方案13】:它不是有效的 html(我不认为),但它似乎 如果您为网页中的脚本标签创建自定义属性:
<script id="myScript" myCustomAttribute="some value" ....>
然后在javascript中访问自定义属性:
var myVar = document.getElementById( "myScript" ).getAttribute( "myCustomAttribute" );
不确定这是否比解析脚本源字符串更好或更差。
【讨论】:
【参考方案14】:如果您需要一种通过 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');
【讨论】:
【参考方案15】:虽然这个问题已经被问到了一段时间,但到今天它仍然是相关的。这不是使用脚本文件参数的简单方法,但我已经有一些极端用例最适合这种方法。
我看到这篇文章是为了找到一个比我前一段时间写的更好的解决方案,希望能找到一个原生功能或类似的东西。 我将分享我的解决方案,直到实施更好的解决方案。这适用于大多数现代浏览器,甚至可能适用于较旧的浏览器,但没有尝试过。
上述所有解决方案都是基于这样一个事实,即它必须注入预定义且标记良好的 SCRIPT 标签,并且完全依赖于 HTML 实现。但是,如果脚本是动态注入的,或者更糟糕的是,如果你正在编写一个库,它将被用于各种网站怎么办? 在这些和其他一些情况下,上述所有答案都不够充分,甚至变得过于复杂。
首先,让我们尝试了解我们需要在这里实现什么。我们需要做的就是获取脚本本身的 URL,从那里它是小菜一碟。
实际上有一个很好的技巧可以从脚本本身获取脚本 URL。本机Error
类的功能之一是能够提供“有问题的位置”的堆栈跟踪,包括到最后一次调用的确切文件跟踪。为了实现这一点,我将使用 Error 实例的 stack 属性,该属性一旦创建,就会提供完整的堆栈跟踪。
以下是魔法的工作原理:
// The pattern to split each row in the stack trace string
const STACK_TRACE_SPLIT_PATTERN = /(?:Error)?\n(?:\s*at\s+)?/;
// For browsers, like Chrome, IE, Edge and more.
const STACK_TRACE_ROW_PATTERN1 = /^.+?\s\((.+?):\d+:\d+\)$/;
// For browsers, like Firefox, Safari, some variants of Chrome and maybe other browsers.
const STACK_TRACE_ROW_PATTERN2 = /^(?:.*?@)?(.*?):\d+(?::\d+)?$/;
const getFileParams = () =>
const stack = new Error().stack;
const row = stack.split(STACK_TRACE_SPLIT_PATTERN, 2)[1];
const [, url] = row.match(STACK_TRACE_ROW_PATTERN1) || row.match(STACK_TRACE_ROW_PATTERN2) || [];
if (!url)
console.warn("Something went wrong. You should debug it and find out why.");
return;
try
const urlObj = new URL(url);
return urlObj.searchParams; // This feature doesn't exists in IE, in this case you should use urlObj.search and handle the query parsing by yourself.
catch (e)
console.warn(`The URL '$url' is not valid.`);
现在,在任何脚本调用的情况下,例如在 OP 情况下:
<script type="text/javascript" src="file.js?obj1=somevalue&obj2=someothervalue"></script>
在file.js
脚本中,您现在可以执行以下操作:
const params = getFileParams();
console.log(params.get('obj2'));
// Prints: someothervalue
这也适用于RequireJS 和其他动态注入的文件脚本。
【讨论】:
【参考方案16】:我认为在包含 javascript 的页面上使用 localStorage 然后在 javascript 本身内重新使用它是更好和更现代的解决方案。将其设置在 localStorage 中:
localStorage.setItem("nameOfVariable", "some text value");
并在 javascript 文件中引用它,例如:
localStorage.getItem("nameOfVariable");
【讨论】:
【参考方案17】:可以通过import.meta.url
向js模块传递参数并读取。
例如,使用以下 HTML
<script type="module">
import './index.mjs?someURLInfo=5';
</script>
以下 JavaScript 文件将记录 someURLInfo 参数:
// index.mjs
new URL(import.meta.url).searchParams.get('someURLInfo'); // 5
当一个文件导入另一个文件时也是如此:
// index.mjs
import './index2.mjs?someURLInfo=5';
// index2.mjs
new URL(import.meta.url).searchParams.get('someURLInfo'); // 5
【讨论】:
以上是关于将参数传递给 JavaScript 文件的主要内容,如果未能解决你的问题,请参考以下文章
从 JavaScript 将参数传递给 p:remoteCommand
通过 javascript 将复杂参数传递给 Web API 服务
JavaScript/jQuery:将多个参数传递给 API 中的 POST 请求