จะส่งพารามิเตอร์ไปยังแท็กสคริปต์ได้อย่างไร?


96

ฉันอ่านวิดเจ็ต DIY แบบสอน- วิธีการฝังไซต์ของคุณบนไซต์อื่นสำหรับ XSS Widgets โดย Dr.Nic

ฉันกำลังมองหาวิธีส่งผ่านพารามิเตอร์ไปยังแท็กสคริปต์ ตัวอย่างเช่นในการทำงานต่อไปนี้:

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

มีวิธีทำไหม?


ลิงค์ที่น่าสนใจสองลิงค์:


ดูสิ่งนี้ด้วย: stackoverflow.com/q/1017424/247696
Flimm

คำตอบ:


124

ฉันขอโทษที่ตอบคำถามเก่า ๆ แต่หลังจากใช้เวลาหนึ่งชั่วโมงในการต่อสู้กับวิธีแก้ปัญหาข้างต้นฉันเลือกใช้สิ่งที่ง่ายกว่า

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

ภายในสคริปต์ด้านบน:

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

ง่ายกว่าการแยกวิเคราะห์ jquery หรือ url มาก

คุณอาจต้องใช้ polyfil สำหรับ doucment.currentScript จากคำตอบของ @Yared Rodriguez สำหรับ IE:

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

6
โปรดทราบว่า currentScript ไม่ทำงานใน IE รายละเอียด
Dehli

ฉันเพิ่ม polyfill สำหรับ IE ในคำตอบ โพลีฟิลล์ไม่ทำงานหรือไม่?
Richard Fox

2
polyfill ไม่ทำงานอีกต่อไป document.currentScript เป็นแบบอ่านอย่างเดียวและไม่สามารถกำหนดได้หากมีอยู่แล้ว อาจเป็นการตรวจสอบอื่นเช่น if (! document.currentScript) {*** ฟังก์ชัน polyfill ***} จะทำงานได้ดีขึ้น
fadomire

3
ฉันขอโทษเดวิดฉันมักจะให้คำตอบของฉันเป็นแบบทั่วไปเพื่อให้คนอื่นสามารถใช้วิธีแก้ปัญหาได้โดยไม่ต้องเพิ่มรายละเอียดการใช้งานเบื้องต้นในปัญหา ในตัวอย่างของฉันด้านบนคุณจะเห็นsrc="..."สิ่งนี้มีขึ้นเพื่อแสดงว่าอะไรก็ได้ไม่สำคัญ :)
Richard Fox

1
@RichardFox ขอบคุณสำหรับคำตอบ แต่ต้องแสดงความคิดเห็นว่า "ไม่ตอบคำถามเดิม: ไม่ใช้ path / to / widget.js" น่าจะเป็นสิ่งที่สนุกที่สุดที่ฉันอ่านมาตลอดสัปดาห์! ไม่อยากจะเชื่อเลยว่าคุณตอบกลับมาอย่างดีเยี่ยม
Skintest

65

จะดีกว่าที่จะใช้คุณสมบัติในแอตทริบิวต์ข้อมูล html5 5

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

ภายในไฟล์สคริปต์http://path.to/widget.jsคุณจะได้รับ paremeters ด้วยวิธีนี้:

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

จะเกิดอะไรขึ้นถ้า id = "myAwesomeWigretNo1" ไม่ใช่แบบนั้น แต่myAwesomeWigretNo2หรือmyAwesomeWigretNo681??? ฉันจะแก้ไขสิ่งนี้เพื่อยอมรับตัวแปรจริงได้อย่างไร
Pathros

9
สำหรับสิ่งที่คุ้มค่ามีวิธีการอื่น ๆ เพื่ออ้างอิงสคริปต์แทนเช่นdocument.currentScript(ทำงานเฉพาะสำหรับสคริปต์ไม่ได้อยู่ในไฟล์ของตัวเอง) และวางidบน<script>แท็กแล้วหาได้โดยที่
Thunderforge

และจะเกิดอะไรขึ้นถ้า ID ถูกเปลี่ยนโดยโปรแกรมเมอร์คนอื่นในทีมของคุณที่ไม่มีเงื่อนงำว่าคุณใช้รหัสนี้?
OBender

1
หากคุณโหลดสคริปต์แบบอะซิงโครนัสการใช้ ID เป็นตัวเลือกเดียวที่เชื่อถือได้ฉันขอแนะนำ ขอบคุณ @Thunderforge ... นอกจากนี้โปรแกรมเมอร์ทุกคนควรละเว้นจากการปรับรหัสใหม่โดยไม่มีแผนการวิ่งที่เหมาะสมโดยภาพรวมของคนที่มีเงื่อนงำว่าเกิดอะไรขึ้น;)
Luca Borrione

แน่นอนว่าคุณสามารถเรียกร้องจริยธรรมที่แข็งแกร่งจากนักพัฒนาได้ แต่มันจะไม่ได้ผลในระยะยาว ... ผู้คนลืมสิ่งต่างๆ .... ในการออกแบบซอฟต์แวร์ที่ดีแต่ละบล็อก Shod จะถูกแยกออกน่า กลัว -pixels.tumblr.com/post/101930002170 / … en.wikipedia.org/wiki/SOLID_(object-oriented_design) ดังนั้นฉันไม่เถียงว่ามันเป็นทางออกที่ดีและไม่ดีมันซับซ้อนกว่าในการรักษา ID เทียบกับไม่รักษา :-) หรือเปล่าคุณไม่ได้วางแผนที่จะ โหลดสคริปต์ Async ฉันไม่เห็นเหตุผลที่จะโหลดโดยใช้ ID
OBender

17

เข้าใจแล้ว เป็นแฮ็ก แต่ใช้งานได้ดี:

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

ฉันส่งพารามิเตอร์ในแท็กสคริปต์เป็นคลาส:

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

บทความนี้ช่วยได้มาก


1
บทความนี้ยอดเยี่ยมมาก!
Bartek Skwira

14
ควรใช้คลาสเพื่อจัดรูปแบบองค์ประกอบไม่ให้ส่งผ่านพารามิเตอร์
kspacja

5
@kspacja ใช่และ HTML ควรมีเนื้อหาโดยไม่ต้องจัดรูปแบบเท่านั้นยกเว้นเราต้องสั่งแท็ก DIV ของเราอย่างแม่นยำสำหรับการจัดวางแบบลอยและคอลัมน์เนื่องจาก CSS ไม่สามารถทำงานได้จริงและเราก็โอเคกับสิ่งนั้น แฮ็คไปฉันพูด แต่คุณสามารถใช้แอตทริบิวต์ "data-" ได้หากคุณต้องการหลีกเลี่ยงความขัดแย้งหรือคุณเป็นคนประเภทที่ต้องนอนไม่หลับ
Jason C

14

อีกวิธีหนึ่งคือการใช้เมตาแท็ก ไม่ว่าข้อมูลใดที่ควรจะส่งไปยัง JavaScript ของคุณสามารถกำหนดได้ดังนี้:

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

จากนั้นสามารถดึงข้อมูลจากเมตาแท็กเช่นนี้ได้ (ทำได้ดีที่สุดในตัวจัดการเหตุการณ์ DOMContentLoaded):

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

ไม่ต้องยุ่งยากกับ jQuery หรือสิ่งที่ชอบไม่ต้องแฮ็กและวิธีแก้ปัญหาที่จำเป็นและทำงานร่วมกับเวอร์ชัน HTML ใด ๆ ที่รองรับเมตาแท็ก ...


ฉันคิดว่าวิธีนี้เป็นวิธีที่ง่ายที่สุดสำหรับพวกเขาทั้งหมด มันใช้งานได้เหมือนมีเสน่ห์และให้สิ่งที่ฉันต้องการ คำถามที่ดีและทางออกที่ยอดเยี่ยม!
arios

10

JQuery มีวิธีส่งผ่านพารามิเตอร์จาก HTML ไปยัง javascript:

ใส่สิ่งนี้ในmyhtml.htmlไฟล์:

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

ในไดเร็กทอรีเดียวกันให้สร้างsubscript.jsไฟล์และใส่สิ่งนี้ไว้ที่นั่น:

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

วิเคราะห์ผลลัพธ์:

การโหลดหน้า myhtml.html มีการพิมพ์ "foobar.mp4" ไปที่หน้าจอ ตัวแปรที่เรียกว่า video_filename ถูกส่งต่อจาก html เป็น javascript Javascript พิมพ์ไปยังหน้าจอและปรากฏว่าฝังอยู่ใน html ในพาเรนต์

jsfiddle พิสูจน์ว่าข้างต้นใช้งานได้:

http://jsfiddle.net/xqr77dLt/


7

หากคุณใช้ jquery คุณอาจต้องการพิจารณาวิธีการข้อมูลของพวกเขา

ฉันได้ใช้สิ่งที่คล้ายกับสิ่งที่คุณพยายามตอบสนอง แต่เป็นแบบนี้:

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

คุณยังสามารถสร้างฟังก์ชั่นที่ช่วยให้คุณจับ GET params ได้โดยตรง (นี่คือสิ่งที่ฉันใช้บ่อย):

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

4

ต้องขอบคุณ jQuery โซลูชันที่เข้ากันได้กับ HTML5 แบบง่ายๆคือการสร้างแท็ก HTML เพิ่มเติมเช่น div เพื่อจัดเก็บข้อมูล

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

การสาธิตสดด้วยรหัสด้านบน: http://codepen.io/anon/pen/KzzNmQ?editors=1011#0

ในการสาธิตสดเราสามารถดูข้อมูลจากแอตทริบิวต์ข้อมูล HTML5 - * ที่จะเชื่อมต่อกันและพิมพ์ลงในบันทึก

ที่มา: https://api.jquery.com/data/


1
ผ่านวิธีแก้ปัญหาอื่น ๆ แต่นี่เป็นวิธีที่ได้ผลดีที่สุดและยังใช้งานได้ง่ายอีกด้วย ขอบคุณ!
Erik Kalkoken

นี่ควรเป็นโซลูชันที่ได้รับการยอมรับเนื่องจากอนุญาตให้คุณอ้างอิงสคริปต์ด้วย ID และเป็น HTML5 ที่ถูกต้อง
Tim S

4

มันเป็นกระทู้เก่ามากฉันรู้ แต่สิ่งนี้อาจช่วยได้เช่นกันหากมีใครมาที่นี่เมื่อพวกเขาค้นหาวิธีแก้ปัญหา

โดยทั่วไปฉันใช้ document.currentScript เพื่อรับองค์ประกอบจากตำแหน่งที่โค้ดของฉันกำลังทำงานและฉันกรองโดยใช้ชื่อของตัวแปรที่ฉันกำลังมองหา ฉันได้ขยาย currentScript ด้วยวิธีการที่เรียกว่า "get" ดังนั้นเราจะสามารถดึงค่าภายในสคริปต์นั้นได้โดยใช้:

document.currentScript.get('get_variable_name');

ด้วยวิธีนี้เราสามารถใช้ URI มาตรฐานเพื่อดึงตัวแปรโดยไม่ต้องเพิ่มแอตทริบิวต์พิเศษ

นี่คือรหัสสุดท้าย

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

ฉันลืมเกี่ยวกับ IE :) มันไม่ง่ายกว่านั้นอีกแล้ว ... ฉันไม่ได้พูดถึง document.currentScript นั้นเป็นคุณสมบัติ HTML5 ยังไม่รวมอยู่ใน IE เวอร์ชันต่างๆ (ฉันทดสอบจนถึง IE11 แต่ก็ยังไม่มี) สำหรับความเข้ากันได้ของ IE ฉันได้เพิ่มส่วนนี้ลงในโค้ด:

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

สิ่งที่เรากำลังทำอยู่ที่นี่คือการกำหนดโค้ดทางเลือกสำหรับ IE ซึ่งส่งคืนอ็อบเจ็กต์สคริปต์ปัจจุบันซึ่งจำเป็นในโซลูชันเพื่อแยกพารามิเตอร์จากคุณสมบัติ src นี่ไม่ใช่โซลูชันที่สมบูรณ์แบบสำหรับ IE เนื่องจากมีข้อ จำกัด บางประการ หากสคริปต์ถูกโหลดแบบอะซิงโครนัส เบราว์เซอร์รุ่นใหม่ควรมีคุณสมบัติ ".currentScript"

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


4

สร้างแอตทริบิวต์ที่มีรายการพารามิเตอร์ดังนี้:

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

จากนั้นใน JavaScript ของคุณรับพารามิเตอร์เป็นอาร์เรย์:

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

อะไรคือข้อเสียของแนวทางนี้?
Tronathan

@Tronathan ไม่มีข้อเสียที่แท้จริงสำหรับแนวทางนี้และมี polyfill รวมอยู่ด้วยเพื่อการสนับสนุนเบราว์เซอร์ที่ดีขึ้น ข้อเสียเพียงอย่างเดียวที่ฉันเห็นที่นี่คือไม่สามารถใส่เครื่องหมายจุลภาคในพารามิเตอร์ซึ่งโดยปกติแล้วจะไม่ใช่ปัญหาและคุณสามารถชดเชยได้โดยการเปลี่ยนตัวคั่นเป็นอักขระที่คุณไม่ได้วางแผนจะใช้
อาถรรพ์

2

ใส่ค่าที่คุณต้องการในที่ที่สคริปต์อื่นสามารถดึงค่าได้เช่นอินพุตที่ซ่อนอยู่จากนั้นดึงค่าเหล่านั้นจากคอนเทนเนอร์เมื่อคุณเริ่มต้นสคริปต์ใหม่ คุณสามารถใส่พารามิเตอร์ทั้งหมดของคุณเป็นสตริง JSON ลงในฟิลด์ที่ซ่อนอยู่


ขอบคุณสำหรับคำตอบ. พารามิเตอร์ถูกป้อนโดยผู้ใช้ (ซึ่งฝังแท็กสคริปต์นี้ไว้ในโค้ด) แล้วอะไรล่ะ?
Tomer Lichtash

สิ่งเดียวที่ฉันคิดได้หากคุณไม่สามารถควบคุมสคริปต์ไคลเอนต์ / เซิร์ฟเวอร์ได้คือการป้อนข้อมูลของผู้ใช้และใช้เพื่อสร้างไฟล์. js เฉพาะโดยมีอินพุตฝังอยู่ในนั้นและสมมติว่าคุณเป็นผู้ควบคุม ของการรวบรวมและประมวลผลข้อมูล
bwest

ไม่ตอบคำถามเดิม: จะใส่อาร์กิวเมนต์ไว้ที่ไหนเมื่อไม่มีรูปแบบที่จะเก็บฟิลด์ที่ซ่อนไว้?
David Spector

2

ฉันต้องการโซลูชันที่รองรับเบราว์เซอร์รุ่นเก่าให้ได้มากที่สุด ไม่เช่นนั้นฉันจะบอกว่าวิธีcurrentScriptหรือdata attributesจะมีสไตล์ที่สุด

นี่เป็นวิธีเดียวที่ยังไม่ได้นำเสนอที่นี่ โดยเฉพาะอย่างยิ่งหากคุณมีข้อมูลจำนวนมากด้วยเหตุผลบางประการตัวเลือกที่ดีที่สุดอาจเป็น:

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

localStorage มีการสนับสนุนเบราว์เซอร์ที่ทันสมัยเต็มรูปแบบและการสนับสนุนที่ดีอย่างน่าประหลาดใจสำหรับเบราว์เซอร์รุ่นเก่าเช่นกันย้อนกลับไปที่ IE 8, Firefox 3,5 และ Safari 4 [11 ปีย้อนหลัง]

หากคุณมีข้อมูลไม่มาก แต่ยังต้องการการสนับสนุนเบราว์เซอร์ที่กว้างขวางตัวเลือกที่ดีที่สุดอาจเป็นดังนี้

เมตาแท็ก [โดย Robidu]

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

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

ข้อบกพร่องของสิ่งนี้คือตำแหน่งที่ถูกต้องในการใส่เมตาแท็ก [จนถึง HTML 4] อยู่ในแท็ก head และคุณอาจไม่ต้องการให้ข้อมูลนี้อยู่ที่นั่น เพื่อหลีกเลี่ยงสิ่งนั้นหรือใส่เมตาแท็กในเนื้อหาคุณสามารถใช้ a:

ย่อหน้าที่ซ่อนอยู่

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

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

สำหรับการรองรับเบราว์เซอร์เพิ่มเติมคุณสามารถใช้คลาส CSS แทนแอตทริบิวต์ที่ซ่อนอยู่:

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

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

2

นี่คือโซลูชันสำหรับ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');
})
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.