จะส่งเหตุการณ์เป็นอาร์กิวเมนต์ไปยังตัวจัดการเหตุการณ์แบบอินไลน์ใน JavaScript ได้อย่างไร


114
// this e works
document.getElementById("p").oncontextmenu = function(e) {
    e = e || window.event;
    var target = e.target || e.srcElement;
    console.log(target);
};

// this e is undefined
function doSomething(e) {
    e = e || window.event;
    var target = e.target || e.srcElement;
    console.log(target);
}
<p id="p" onclick="doSomething(e)">
    <a href="#">foo</a>
    <span>bar</span>
</p>

มีบางคำถามที่คล้ายกันถูกถาม

แต่ในรหัสของฉันฉันพยายามที่จะได้รับองค์ประกอบของเด็กที่ได้รับการคลิกที่เหมือนaspanหรือ

ดังนั้นวิธีที่ถูกต้องในการส่งผ่านeventเป็นอาร์กิวเมนต์ไปยังตัวจัดการเหตุการณ์หรือวิธีรับเหตุการณ์ภายในตัวจัดการโดยไม่ผ่านอาร์กิวเมนต์คืออะไร

แก้ไข

ฉันทราบaddEventListenerและjQueryโปรดให้วิธีแก้ปัญหาสำหรับการส่งต่อเหตุการณ์ไปยังผู้ส่งinlineเหตุการณ์



5
มีเหตุผลที่ดีในการใช้ตัวจัดการเหตุการณ์แบบอินไลน์แทนที่จะเปลี่ยนไปใช้ addEventListener หรือไม่ en.wikipedia.org/wiki/Unobtrusive_JavaScript
Xotic750

2
@ Xotic750 สำหรับฉันใช่ไม่จำเป็นต้องสนใจเกี่ยวกับการผูกใหม่ด้วยตนเองทุกครั้งเมื่อโหลดหรือโหลด html แบบไดนามิกผ่าน ajax
Wadih M.

คำตอบ:


183

เพื่อส่งผ่านeventวัตถุ:

<p id="p" onclick="doSomething(event)">

เพื่อรับลูกที่คลิกelement(ควรใช้กับeventพารามิเตอร์:

function doSomething(e) {
    e = e || window.event;
    var target = e.target || e.srcElement;
    console.log(target);
}

เพื่อส่งผ่านelementตัวเอง (DOMElement):

<p id="p" onclick="doThing(this)">

ดูตัวอย่างสดบนjsFiddle

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


11
(และสำหรับใครก็ตามที่สงสัยว่า: ใช่สิ่งนี้ใช้ได้กับ Chrome, Firefox และอื่น ๆ แม้ว่า [Firefox เป็นต้น] บางตัวจะไม่มี global eventobject เนื่องจากบริบทที่เรียกตัวจัดการ DOM0 นั้นมีeventอ็อบเจกต์ แม้ว่า [ในบางเบราว์เซอร์] จะไม่ใช่ทั่วโลกก็ตาม)
TJ Crowder

3
การผ่าน´event´ เป็นวิธีเดียวที่ฉันรู้หากได้รับการสนับสนุน การแยกวิเคราะห์´this´ ไม่มีประโยชน์ในสถานการณ์นี้
Xotic750

5
@ user1643156 นั่นสำคัญมาก ต้องตั้งชื่อพารามิเตอร์เป็น "เหตุการณ์"
The-null-Pointer-

1
คำตอบของ Wadih M. ดีกว่านี้ สิ่งนี้ทำให้เข้าใจผิด (เช่นเดียวกับคนอื่น ๆ ที่คล้ายกัน) ทำให้ผู้คนเชื่อว่าควรใส่พารามิเตอร์ "(event)" ลงในการเรียกฟังก์ชันเมื่อ JavaScript มีพารามิเตอร์ "เหตุการณ์" อยู่แล้วและพร้อมใช้งานภายในฟังก์ชันที่เรียกว่า ดังนั้นจึงไม่จำเป็นต้องประกาศ (ฉันใช้เวลาหลายวันกว่าจะรู้ว่าการเปลี่ยนชื่อตัวแปรไม่แตกต่างกันเพราะมันไม่ได้ถูกส่งผ่านจริงๆ) นอกจากนี้คำอธิบายที่ให้ไว้ยังทำให้ข้อสงสัยเกี่ยวกับสาเหตุที่ JS ทำงานเช่นนั้น (อาจจะไม่ควร แต่นั่นไม่ใช่เรื่องที่ฉันจะตัดสิน ... )
Cyberknight

1
เหตุผล 'เหตุการณ์' วัตถุที่สามารถใช้เป็นอาร์กิวเมนต์ใน HTML แบบอินไลน์จัดการเหตุการณ์ถูกอธิบายในdeveloper.mozilla.org/en-US/docs/Web/Guide/Events/...
Panu Logic

18

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

<p id="p" onclick="doSomething.apply(this, arguments)">

และ

function doSomething(e) {
  if (!e) e = window.event;
  // 'e' is the event.
  // 'this' is the P element
}

'เหตุการณ์' ที่กล่าวถึงในคำตอบที่ยอมรับนั้นเป็นชื่อของอาร์กิวเมนต์ที่ส่งไปยังฟังก์ชัน ไม่มีอะไรเกี่ยวข้องกับเหตุการณ์ระดับโลก


เคล็ดลับที่ดี เมื่อผู้คนเริ่มใช้ส่วนประกอบของเว็บcall()และapply()จะพิสูจน์ได้ว่าจำเป็นในการจำลองความสามารถในการผูกข้อมูลที่มีอยู่ในเฟรมเวิร์ก js หลัก เคล็ดลับพิเศษอย่างหนึ่งคือการทำสิ่งที่คล้ายกับObject.assign(this.querySelector('my-btn'), this)ภายในส่วนประกอบของเว็บและ voila การผูกข้อมูล คุณสามารถเข้าถึงวิธีการปกครองระดับองค์ประกอบเว็บใด ๆ onclick="toggleBtnActive.call(this, true)"จากเหตุการณ์ที่เกิดขึ้นแบบอินไลน์
Adrian Moisa

12

คุณไม่จำเป็นต้องผ่านthisเนื่องจากมีการeventส่งผ่านวัตถุโดยค่าเริ่มต้นโดยอัตโนมัติอยู่แล้วซึ่งมีevent.targetวัตถุที่มาจาก คุณสามารถแบ่งเบาไวยากรณ์ของคุณ:

นี้:

<p onclick="doSomething()">

จะทำงานกับสิ่งนี้:

function doSomething(){
  console.log(event);
  console.log(event.target);
}

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

ตอนนี้ถ้าคุณทริกเกอร์ doSomething () แบบไดนามิกจากที่ใดที่หนึ่งในโค้ดของคุณคุณจะสังเกตเห็นว่าไม่ได้eventกำหนดไว้ เนื่องจากไม่ได้ถูกกระตุ้นจากเหตุการณ์การคลิก ดังนั้นหากคุณยังคงต้องการทริกเกอร์เหตุการณ์แบบเทียมให้ใช้dispatchEvent:

document.getElementById('element').dispatchEvent(new CustomEvent("click", {'bubbles': true}));

แล้วdoSomething()จะเห็นeventและevent.targetตามปกติ!

ไม่จำเป็นต้องผ่านไปthisทุกที่และคุณสามารถรักษาลายเซ็นฟังก์ชันของคุณให้ปราศจากข้อมูลการเดินสายและทำให้สิ่งต่างๆง่ายขึ้น


อย่างน้อยใน IE11 นี่ไม่เป็นความจริงไม่มีอาร์กิวเมนต์เริ่มต้น
cskwg

1
@cskwg มันใช้งานได้กับ IE11 เช่นกัน ใช้งานได้กับเบราว์เซอร์หลักทั้งหมดเนื่องจากจำเป็นสำหรับความเข้ากันได้แบบย้อนกลับ ดังที่ฉันได้กล่าวไว้ในคำตอบเฉพาะในกรณีที่ฟังก์ชันจาวาสคริปต์ถูกเริ่มทำงานจากเหตุการณ์ซึ่งเป็นสถานการณ์เดียวที่มีเหตุการณ์อยู่จะมีวัตถุที่เรียกว่า "เหตุการณ์" อยู่แล้วซึ่งคุณสามารถเข้าถึงภายในฟังก์ชันของคุณได้โดยไม่ต้อง ส่งต่อสายไฟเพิ่มเติมไปยังต้นแบบฟังก์ชันของคุณ ฉันเพิ่งทำการทดสอบบนเครื่องของฉันด้วย IE11 สำหรับเหตุการณ์ onclick และและตัวแปร "event" มี "วัตถุ PointerEvent"
Wadih M.
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.