การส่งพารามิเตอร์ไปยังไฟล์ 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

การใช้สคริปต์ภายในจะเรียกรายงาน CSP หากไซต์เป็น HTTPS และหากเปิดใช้งาน CSP อย่างสมบูรณ์ เหตุผลที่กำหนดในเอกสาร CSP คือการอนุญาตให้องค์ประกอบภายในสามารถทำให้การฉีดง่ายขึ้น
David Spector

คำตอบ:


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 - เป็น file.js โหลด 100% ของเวลาที่ MYLIBRARY.init (["somevalue", 1, "controlId"]); ถูกประหารชีวิตไหม? บางทีเราต้องการเอกสารที่พร้อมจะใส่?
Darius.V

2
1) ถ้ามี MYLIBRARY ให้ใช้หรือกำหนดวัตถุใหม่ จุดประสงค์คือการสร้างเนมสเปซส่วนกลางโดยปกติแล้วฉันจะใช้เนมสเปซย่อยเพื่อให้บรรทัดนี้ช่วยหลีกเลี่ยงการกำหนดเนมสเปซระดับบนอีกครั้ง 2) ใช่มันสร้างซิงเกิลตัน
Naeem Sarfraz

1
ฉันได้ทำตัวอย่างของความคิดนี้: http://plnkr.co/edit/iE0Vr7sszfqrrDIsR8Wi?p=preview
robe007

1
การแสดงออกนี้หมายความว่าอย่างไร var MYLIBRARY = MYLIBRARY || (function(){}());? เหตุใดจึงควรMYLIBRARYตั้งค่าเป็นบูลีน
อเล็กซ์

1
@Alexander ดูความคิดเห็นของฉันด้านบนstackoverflow.com/questions/2190801/…
Naeem Sarfraz

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
เก่า แต่สำหรับ googling เหล่านี้เป็นสิ่งที่ดีถ้าคุณต้องการแก้ไข CSP (นโยบายความปลอดภัยของเนื้อหา) เราใช้สคริปต์จำนวนมากที่เราส่งผ่านสตริงที่กำหนดจากทรัพยากรภาษาและคีย์ API เป็นต้นไปยังไฟล์ JS
monkeySeeMonkeyDo

2
โปรดทราบว่าคุณยังสามารถใช้งานdocument.currentScriptได้โปรดดูcaniuse.com/#feat=document-currentscriptสำหรับความเข้ากันได้ (หรือใช้ polyfill)
Yves M.

$(..)ไวยากรณ์ jQuery ไม่ลืมที่จะรวมไว้
Timo

48

ความคิดที่ฉันมาข้ามอีกการกำหนดidให้กับ<script>องค์ประกอบและผ่านการขัดแย้งเป็นdata-*คุณลักษณะ ส่งผลให้<script>แท็กจะมีลักษณะบางอย่างเช่นนี้

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

สคริปต์สามารถใช้รหัสเพื่อระบุตำแหน่งตัวเองโดยทางโปรแกรมและวิเคราะห์อาร์กิวเมนต์ ด้วย<script>แท็กก่อนหน้านี้ชื่อสามารถเรียกคืนได้ดังนี้:

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

เราได้รับname=helper


4
หากคุณไม่ต้องการขึ้นอยู่กับแอตทริบิวต์ id คุณสามารถทำให้helper.jsสคริปต์วนซ้ำผ่านscriptแท็กทั้งหมดบนหน้าเว็บค้นหาด้วยscr="helper.js"และแยกdata-nameออก
jvannistelrooy

1
@jvannistelrooy ฉันไม่ได้ลอง แต่ฉันเชื่อว่าควรจะได้รับสคริปต์ผ่าน jquery และตัวเลือกที่ฉลาดเช่นนั้น: var this_js_script = $('script[src*=somefile]');(คัดลอกมาจากด้านบน )
LosManos

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 (/ ^ [^ \ #] + \ #? /, '') ;
Mark Nottingham

โอ้และฉันพบว่าการวาง JSON ไว้ในนั้นก็ใช้งานได้ตราบใดที่คุณใช้มัน
มาร์คน็อตติงแฮม

@ user378221 - คุณแน่ใจหรือไม่ว่านี่จะได้รับไฟล์ที่ถูกต้องเสมอ ฉันหมายความว่านี่ถือว่าไฟล์นี้เป็นไฟล์สุดท้าย จะเกิดอะไรขึ้นถ้ามีการโหลดแท็กสคริปต์เพิ่มเติมก่อนที่จะดำเนินการนี้ ฉันไม่รู้ว่าเป็นไปได้หรือไม่ แต่ฉันถือว่าเอกสารไม่รอให้การเรียกใช้โค้ดเสร็จสิ้นเพื่อโหลดแท็กอื่น ๆ
Darius.V

ควรใช้ Use decodeURI () หรือ decodeURIComponent () แทน unescape เนื่องจากฟังก์ชั่นดังกล่าวถูกคัดค้าน
Steve Childs

@ Darius.V ใช้งานได้กับสคริปต์ที่ไม่ใช่ async ผมชอบใช้1 ตัวเลือกที่มีตัวเลือก 5 เป็นทางเลือก
ลุค

14

คุณใช้ตัวแปรส่วนกลาง :-D

แบบนี้:

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

รหัส JavaScript ใน 'file.js' สามารถเข้าถึงobj1และobj2ไม่มีปัญหา

แก้ไขเพียงแค่ต้องการเพิ่มว่าหาก 'file.js' ต้องการตรวจสอบobj1และobj2ได้รับการประกาศแม้คุณสามารถใช้ฟังก์ชั่นต่อไปนี้

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

หวังว่านี่จะช่วยได้


นั่นจะทำให้เกิดข้อผิดพลาดที่ไม่ได้รับการยืนยันใน IE return typeof window[$Name] !== 'undefined';ร่างกายที่ต้องการของฟังก์ชั่นที่เป็น โปรดทราบว่าคุณจะผ่านฟังก์ชั่นนั้นเป็นสตริงที่มีชื่อของตัวแปร มันอาจเป็นไปได้ง่ายขึ้นเพียงแค่ตรวจสอบว่าตัวแปรที่มีอยู่ในรหัสโทร (นี้ไม่สามารถนำมาใช้เป็นฟังก์ชั่น) if (typeof var !== 'undefined')ผ่าน
Anthony DiSanti

2
โอ้ไม่เคยใช้ IE ขอโทษ
NawaMan

ใช่ แต่ตามประสบการณ์ของผมกับ JavaScript ผมจะใช้ตัวแปรทั่วโลกเฉพาะสำหรับ namespaces โมดูลและเปิดเผยเพียงเท่าสิ่งที่จำเป็น (เช่นรหัส init คุณสมบัติบางอย่าง) ดังที่แสดงไว้ที่นี่ มันง่ายเกินไปที่จะตั้งชื่อความขัดแย้งในโครงการที่ซับซ้อน ... ใช้เวลาหลายชั่วโมงแล้วหาว่าคุณใช้ตัวแปรไปแล้วที่อื่นในโครงการ
Matt

varคุณสามารถละเว้น
Timo

12

นี่เป็นข้อพิสูจน์แนวคิดที่รวดเร็วมาก

ฉันแน่ใจว่ามีอย่างน้อย 2 แห่งที่สามารถปรับปรุงได้และฉันก็มั่นใจว่าสิ่งนี้จะไม่รอดในป่านาน ข้อเสนอแนะใด ๆ ที่จะทำให้มันเรียบร้อยมากขึ้นหรือใช้งานได้ก็ยินดีต้อนรับ

กุญแจสำคัญคือการตั้งรหัสสำหรับองค์ประกอบสคริปต์ของคุณ สิ่งที่จับได้เพียงอย่างเดียวคือสิ่งนี้หมายความว่าคุณสามารถเรียกสคริปต์ได้เพียงครั้งเดียวเนื่องจากจะมองหา 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

1
eval นั้นหนีไปชั่วร้าย
Barry Chapman

@barrychapman - โอ้มนุษย์ 2010 ฉันแปลกใจที่ไม่มีธงสีแดงอีก 10 ตัวในนั้น
Anthony

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

สิ่งนี้สามารถทำได้อย่างง่ายดายหากคุณใช้เฟรมเวิร์ก Javascript บางอย่างเช่น jQuery เช่นนั้น

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

ตอนนี้คุณสามารถใช้พารามิเตอร์เหล่านี้โดยแยกเป็นพารามิเตอร์ตัวแปรของคุณ

กระบวนการเดียวกันสามารถทำได้โดยไม่ต้องมีกรอบ แต่จะใช้รหัสบรรทัดเพิ่มเติม


2
นอกจากนี้ยังมีปลั๊กอิน jQuery ชื่อ parseQuery ที่ทำให้สิ่งนี้ง่ายยิ่งขึ้น: plugins.jquery.com/project/parseQuery
Jimmy Cuadra

@JimmyCuadra - น่าเสียดายที่ลิงก์ที่คุณระบุเสีย แต่ฉันพบวิธีการที่คล้ายกันใน jQuery เอง: jQuery.param ()
Matt

1

คุณอาจมีไฟล์จาวาสคริปต์ที่ถูกสร้างขึ้นโดยภาษาสคริปต์ใด ๆ โดยฉีดตัวแปรของคุณลงในไฟล์ในทุกคำขอ คุณจะต้องแจ้งให้เว็บเซิร์ฟเวอร์ของคุณทราบว่าจะไม่ลบไฟล์ js-statically (การใช้ mod_rewrite น่าจะเพียงพอแล้ว)

ระวังแม้ว่าคุณจะสูญเสียการแคชไฟล์ js ใด ๆ เหล่านี้เนื่องจากมีการเปลี่ยนแปลงอยู่ตลอดเวลา

บาย.


1
ไม่สามารถเข้าใจว่าทำไมสิ่งนี้จึงถูกลดระดับลง มันเป็นทางออกที่ถูกต้องโดยใช้ตรรกะด้านเซิร์ฟเวอร์ เท่าที่ฉันเห็น OP ไม่ต้องการให้เป็นโซลูชันแบบเต็มจาวาสคริปต์
Anoyz

@aefxx - คุณพูดถูก ภายใน<script>บล็อกคุณสามารถใช้สิ่งที่ต้องการMyModule.Initialize( '<%: Model.SomeProperty%>', '<%: Model.SomeOtherProperty%>', ...);แสดงบนเซิร์ฟเวอร์ ข้อควรระวัง: <%:หนีค่าขณะที่<%=ส่งค่าที่ไม่ใช้ค่า Escape MyModuleจะเป็นเนมสเปซ (เช่นตัวแปรภายในไฟล์. js ซึ่งเรียกตัวเองซึ่งแสดงถึงฟังก์ชันInitialize) ฉันยกระดับคำตอบของคุณเพราะเป็นประโยชน์
Matt

หมายเหตุ:แนวคิดวิธีการสร้างโมดูลซึ่งมีคุณสมบัติที่เปิดเผยได้อธิบายรายละเอียดเพิ่มเติมที่นี่ในหน้านี้
Matt

1

คำถามที่ดีและคำตอบที่สร้างสรรค์ แต่ suggetion ของฉันคือการทำให้วิธีการของคุณถูกทำให้ผิดและที่ควรแก้ปัญหาทั้งหมดของคุณโดยไม่มีเทคนิคใด ๆ

หากคุณมีฟังก์ชั่น:

function A()
{
    var val = external_value_from_query_string_or_global_param;
}

คุณสามารถเปลี่ยนเป็น:

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

ฉันคิดว่านี่เป็นวิธีที่เป็นธรรมชาติที่สุดคุณไม่จำเป็นต้องสร้างเอกสารเพิ่มเติมเกี่ยวกับ 'พารามิเตอร์ไฟล์' และคุณจะได้รับเหมือนกัน สิ่งนี้มีประโยชน์เป็นพิเศษหากคุณอนุญาตให้ผู้พัฒนารายอื่นใช้ไฟล์ js ของคุณ


0

ไม่คุณไม่สามารถทำได้โดยการเพิ่มตัวแปรลงในส่วนการสอบถามของ URL ไฟล์ JS หากการเขียนส่วนของรหัสเพื่อแยกสตริงที่รบกวนคุณอาจเป็นวิธีอื่นที่จะ 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

0

มันไม่ถูกต้อง html (ฉันไม่คิดว่า) แต่ดูเหมือนว่าจะทำงานถ้าคุณสร้างแอตทริบิวต์ที่กำหนดเองสำหรับแท็กสคริปต์ในหน้าเว็บของคุณ :

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

จากนั้นเข้าถึงแอตทริบิวต์ที่กำหนดเองใน javascript:

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

ไม่แน่ใจว่าสิ่งนี้ดีกว่าหรือแย่กว่าการแยกสตริงสคริปต์


0

หากคุณต้องการวิธีที่ผ่านการตรวจสอบ CSP (ซึ่งห้ามการไม่ปลอดภัยแบบอินไลน์) คุณจะต้องใช้วิธีการที่ไม่จำเป็นในการเพิ่มค่าที่ไม่ซ้ำกันให้กับทั้งสคริปต์และคำสั่ง CSP หรือเขียนค่าลงใน html และอ่านอีกครั้ง

วิธี Nonce สำหรับ 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>`)
})

หรือเขียนค่าลงในวิธี html ในกรณีนี้ใช้ Jquery:

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


$(document).ready(() => {
    globalThis.EMAIL = $('#account').data('email');
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.