ปัญหาการสั่งซื้อ onclick () และ onblur ()


107

ฉันมีช่องป้อนข้อมูลที่แสดงเมนูแบบเลื่อนลงที่กำหนดเอง ฉันต้องการฟังก์ชันต่อไปนี้:

  • เมื่อผู้ใช้คลิกที่ใดก็ได้นอกช่องป้อนข้อมูลเมนูควรถูกลบออก
  • หากโดยเฉพาะอย่างยิ่งผู้ใช้คลิกที่ div ภายในเมนูเมนูควรถูกลบออกและการประมวลผลพิเศษควรเกิดขึ้นตามการคลิก div

นี่คือการใช้งานของฉัน:

ช่องป้อนข้อมูลมีonblur()เหตุการณ์ที่ลบเมนู (โดยการตั้งค่าระดับบนสุดinnerHTMLเป็นสตริงว่าง) เมื่อใดก็ตามที่ผู้ใช้คลิกนอกช่องป้อนข้อมูล div ภายในเมนูยังมีonclick()เหตุการณ์ที่เรียกใช้การประมวลผลพิเศษ

ปัญหาคือonclick()เหตุการณ์จะไม่เริ่มทำงานเมื่อคลิกเมนูเนื่องจากช่องป้อนข้อมูลonblur()เริ่มทำงานก่อนและลบเมนูรวมถึงonclick()s!

ฉันจะแก้ไขปัญหาโดยการแยก divs เมนูonclick()เข้าonmousedown()และonmouseup()เหตุการณ์ที่เกิดขึ้นและการตั้งธงทั่วโลกในการลงเมาส์ซึ่งจะถูกล้างบนเมาส์ขึ้นคล้ายกับสิ่งที่ได้รับการแนะนำในคำตอบนี้ เนื่องจากonmousedown()เริ่มทำงานก่อนonblur()การตั้งค่าสถานะจะถูกตั้งค่าonblur()หากมีการคลิก div เมนูใดเมนูหนึ่ง แต่จะไม่เกิดขึ้นหากอยู่ที่อื่นบนหน้าจอ หากเมนูถูกคลิกฉันจะกลับทันทีonblur()โดยไม่ต้องลบเมนูจากนั้นรอonclick()ให้ไฟเริ่มทำงานเมื่อถึงจุดนั้นฉันสามารถลบเมนูได้อย่างปลอดภัย

มีวิธีแก้ปัญหาที่หรูหรากว่านี้หรือไม่?

รหัสมีลักษณะดังนี้:

<div class="menu" onmousedown="setFlag()" onmouseup="doProcessing()">...</div>
<input id="input" onblur="removeMenu()" ... />

var mouseflag;

function setFlag() {
    mouseflag = true;
}

function removeMenu() {
    if (!mouseflag) {
        document.getElementById('menu').innerHTML = '';
    }
}

function doProcessing(id, name) {
    mouseflag = false;
    ...
}

คำตอบ:


177

ฉันประสบปัญหาเดียวกันกับคุณ UI ของฉันได้รับการออกแบบตามที่คุณอธิบาย ฉันแก้ไขปัญหาโดยเพียงแค่แทนที่onClickรายการเมนูด้วยonMouseDownไฟล์. ฉันไม่ได้ทำอะไรเลย ไม่onMouseUpไม่มีธง วิธีนี้แก้ไขปัญหาโดยให้เบราว์เซอร์จัดลำดับใหม่โดยอัตโนมัติตามลำดับความสำคัญของตัวจัดการเหตุการณ์เหล่านี้โดยไม่ต้องดำเนินการเพิ่มเติมใด ๆ จากฉัน

มีเหตุผลใดบ้างที่สิ่งนี้จะไม่ได้ผลสำหรับคุณ?


3
นี้ใช้งานได้จริง ฉันได้ทดสอบใน FF แล้วและมันใช้งานได้เหมือนมีเสน่ห์
Supreme Dolphin

3
มันได้ผล. ดูเหมือนว่าonmousedownจะดำเนินการก่อนonblurทดสอบใน Firefox, Chrome และ Internet Explorer
Tonatio

12
ที่น่าสังเกตว่าสิ่งนี้จะเปลี่ยนพฤติกรรมเล็กน้อยตามธรรมชาติ - จากนั้นการโต้ตอบการคลิกจะถูกจัดการโดยใช้เมาส์ลงแทนที่จะเลื่อนเมาส์ขึ้น สำหรับคนส่วนใหญ่อาจจะสบายดี (รวมอยู่ในกรณีนี้ด้วย) แต่มีข้อบกพร่องเล็กน้อย โดยเฉพาะอย่างยิ่งฉันมักจะคลิกจากนั้นลากปุ่มออกหากฉันคลิกผิดซึ่งจะป้องกันไม่ให้มีการเรียก onclick - หากปุ่มทำหน้าที่ไม่ใช่ Pure (ลบโพสต์ ฯลฯ ) คุณอาจต้องการรักษาสิ่งนี้ไว้และใช้วิธีการตั้งค่าสถานะ
Brizee

2
สิ่งที่เกี่ยวกับการช่วยสำหรับการเข้าถึงในขณะที่คุณตั้ง mouseDown แทนที่จะเป็น onClick คุณจะฆ่าการเข้าถึงสำหรับองค์ประกอบ <button> ทั้งหมด: /
ncubica

2
คำตอบที่ระบุไว้ด้านล่างโดย @ ian-macfarlane เป็นวิธีที่ถูกต้องในการจัดการกับปัญหานี้ สรุป ... onMouseDownกับevent.preventDefault() และonClickด้วยการกระทำที่คุณต้องการ
Conal Trinitrotoluene Da Costa

56

onClickonMouseDownไม่ควรถูกแทนที่ด้วย

แม้ว่าแนวทางนี้จะได้ผลแต่ทั้งสองเหตุการณ์ต่างกันโดยพื้นฐานที่มีความคาดหวังที่แตกต่างกันในสายตาของผู้ใช้ การใช้onMouseDownแทนonClickจะทำลายความสามารถในการคาดเดาของซอฟต์แวร์ของคุณในกรณีนี้ ดังนั้นทั้งสองเหตุการณ์จึงไม่สามารถเปลี่ยนแปลงได้

เพื่อเป็นตัวอย่าง: เมื่อคลิกปุ่มโดยไม่ได้ตั้งใจผู้ใช้คาดว่าจะสามารถคลิกเมาส์ค้างไว้ลากเคอร์เซอร์ออกนอกองค์ประกอบแล้วปล่อยปุ่มเมาส์ในที่สุดจะไม่มีการดำเนินการใด ๆ onClickทำสิ่งนี้. onMouseDownไม่อนุญาตให้ผู้ใช้กดเมาส์ค้างไว้และจะทริกเกอร์การดำเนินการทันทีโดยไม่ต้องขอความช่วยเหลือจากผู้ใช้ onClickเป็นมาตรฐานที่เราคาดว่าจะทริกเกอร์การดำเนินการบนคอมพิวเตอร์

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

ท้ายที่สุดแล้วonClickเหตุการณ์คือการรวมกันของonMouseDownและonMouseUpในกรณีที่ทั้งคู่เกิดขึ้นภายในองค์ประกอบเดียวกันเท่านั้น


7
นี่เป็นทางออกที่สมบูรณ์แบบสำหรับฉันและความคิดเห็นนั้นถูกต้องโดยสิ้นเชิง - การแทนที่ onMouseDown ทำให้เกิดความสับสนในประสบการณ์ของผู้ใช้ มีขึ้นโหวต
Paul Bartlett

5
นี่ควรเป็นคำตอบที่ถูกต้อง ขอบคุณสำหรับการโพสต์สิ่งนี้
user1189352

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

2
ถ้าฉันใช้event.preventDefault()ในonMouseDownงานกิจกรรมของฉันonFocusจะไม่ถูกเรียก
Batman

3

แทนที่onmousedownด้วยonfocus. ดังนั้นเหตุการณ์นี้จะถูกทริกเกอร์เมื่อโฟกัสอยู่ภายในกล่องข้อความ

แทนที่onmouseupด้วยonblur. ทันทีที่คุณนำโฟกัสออกจากกล่องข้อความ onblur จะทำงาน

ฉันเดาว่านี่คือสิ่งที่คุณอาจต้องการ

อัพเดท :

เมื่อคุณเรียกใช้ฟังก์ชันออนโฟกัส -> ลบคลาสที่คุณจะใช้ในออนเบลอและเพิ่มคลาสที่คุณต้องการดำเนินการออนโฟกัส

และ

เมื่อคุณเรียกใช้ฟังก์ชัน onblur -> ลบคลาสที่คุณจะนำไปใช้ในออนโฟกัสและเพิ่มคลาสที่คุณต้องการดำเนินการ onblur

ฉันไม่เห็นความจำเป็นของตัวแปรแฟล็ก

อัปเดต 2:

คุณสามารถใช้เหตุการณ์ onmouseout และ onmouseover

onmouseover -ตรวจจับเมื่อเคอร์เซอร์อยู่เหนือมัน

onmouseout -ตรวจจับเมื่อเคอร์เซอร์ออก


ฉันได้แก้ไขคำถามของฉันเพื่อความชัดเจน วิธีนี้หลีกเลี่ยงความจำเป็นในการตั้งค่าสถานะอย่างไร นอกจากนี้ฉันใช้onmousedown()และonmouseup()บนเมนูไม่ใช่ช่องข้อความ / ช่องป้อนข้อมูล
1 ''

ฉันยังยอมรับคำตอบนี้ไม่ได้เพราะฉันไม่รู้ว่าถูกต้อง คุณช่วยตอบข้อกังวลที่ฉันแจ้งในความคิดเห็นด้านบนได้ไหม
1 ''

แน่นอนฉันสามารถดูว่าคุณสามารถใช้ onmouseover และ onmouseout คล้ายกับที่ฉันกำลังทำอยู่ได้อย่างไรเพื่อตั้งค่าสถานะเมื่อเมาส์อยู่เหนือเมนู อย่างไรก็ตามฉันยังคิดว่าคุณจะต้องตั้งค่าสถานะใน onmouseover ซึ่งจะถูกล้างใน onmouseout เพื่อที่คุณจะได้รู้ว่าคุณอยู่เหนือเมนูหรือไม่เมื่อคุณคลิก คุณคิดวิธีที่ไม่ต้องตั้งค่าสถานะได้ไหม?
1 ''

ฉันเห็นรหัสของคุณได้ไหม ... ใส่ไว้ในซอ ... เพียงแค่ใส่ส่วนที่เกี่ยวข้องและมันก็โอเคถ้าฉันไม่เห็นผลลัพธ์.. เพียงแค่รหัส ..
HIRA THAKUR


2

โซลูชันที่หรูหรากว่า (แต่มีประสิทธิภาพน้อยกว่า):

แทนที่จะใช้ onblur ของอินพุตเพื่อลบเมนูให้ใช้document.onclickซึ่งจะเริ่มทำงานหลังจากonblurนั้น

อย่างไรก็ตามนี่ยังหมายความว่าเมนูจะถูกลบออกเมื่อมีการคลิกอินพุตซึ่งเป็นพฤติกรรมที่ไม่ต้องการ ตั้งค่าinput.onclickด้วยevent.stopPropagation()เพื่อหลีกเลี่ยงการเผยแพร่การคลิกไปยังเหตุการณ์การคลิกเอกสาร


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

0

เปลี่ยน onclick โดย onfocus

แม้ว่าออนเบลอและออนคลิกจะไม่เข้ากันได้ดีนัก แต่ก็เห็นได้ชัดว่าออนโฟกัสและใช่ออนเบลอ เนื่องจากแม้หลังจากปิดเมนูแล้วออนโฟกัสก็ยังใช้ได้กับองค์ประกอบที่คลิกภายใน

ฉันทำและมันได้ผล


-7

คุณสามารถใช้setIntervalฟังก์ชันภายในonBlurตัวจัดการของคุณดังนี้:

<input id="input" onblur="removeMenu()" ... />

function removeMenu() {
    setInterval(function(){
        if (!mouseflag) {
            document.getElementById('menu').innerHTML = '';
        }
    }, 0);
}

setIntervalฟังก์ชั่นจะลบของคุณonBlur ฟังก์ชั่นออกจากสาย stack เพิ่มเพราะคุณเวลาที่กำหนดเป็น 0, ฟังก์ชั่นนี้จะถูกเรียกว่าทันทีหลังจากจัดการเหตุการณ์อื่น ๆ ที่ดำเนินการเสร็จสิ้น


5
setIntervalเป็นความคิดที่ไม่ดีคุณจะไม่ยกเลิกมันดังนั้นมันจะเรียกใช้ฟังก์ชันของคุณอย่างต่อเนื่องและมักจะทำให้ไซต์ของคุณใช้ซีพียูสูงสุด ใช้setTimeoutแทนหากคุณจะใช้เทคนิคนี้ (ซึ่งฉันไม่แนะนำ) การสร้างแอปของคุณขึ้นอยู่กับช่วงเวลาของเหตุการณ์บางอย่างถือเป็นธุรกิจที่มีความเสี่ยง
casey

6
โรบินสันจะเป็นอันตราย! อันตราย! สภาพการแข่งขันข้างหน้า!
GoreDefex

เดิมทีฉันคิดวิธีแก้ปัญหานี้ ( setTimeoutไม่ดีsetInterval) แต่ฉันต้องชนมันถึง250ms ก่อนที่เวลาจะเกิดขึ้นตามลำดับที่ถูกต้อง ข้อบกพร่องนี้อาจยังคงมีอยู่ในอุปกรณ์ที่ทำงานช้าลงและยังทำให้เห็นความล่าช้าได้อีกด้วย ฉันลองonMouseDownแล้วและใช้งานได้ดี ฉันสงสัยว่ามันต้องการเหตุการณ์สัมผัสเช่นกัน
Brennan Cheung

บางอย่างเช่นช่วงเวลาก็ไม่เลวหากคุณต้องการใช้ onClick จริงๆ แต่คุณต้องการการหมดเวลาแบบวนซ้ำโดยมีเงื่อนไขมากกว่าช่วงเวลาเพื่อไม่ให้ทำงานตลอดไป นี่เป็นรูปแบบเดียวกับที่ใช้ Selenium conditional waits
Will Cain
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.