ปัญหาการวางเมาส์ของ iPad / iPhone ทำให้ผู้ใช้ดับเบิลคลิกที่ลิงก์


125

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

มีวิธีแก้ปัญหาพร้อมแก้ปัญหานี้หรือไม่ บางทีคำสั่ง jquery ที่ฉันใช้ shoudl แทน mouseover / out เป็นต้นขอบคุณ!


1
เหตุการณ์ของคุณผูกพันกับอะไร? เช่นเหตุการณ์ onclick ควรทำงานได้ดี ... onmouseover, onmouseout และ CSS: hover เป็นเหตุการณ์ที่จัดการได้ยากเล็กน้อยเนื่องจากไม่มี "โฮเวอร์" สำหรับหน้าจอสัมผัส คุณมีตัวอย่างโค้ดหรือไม่?
scunliffe

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

ฉันเห็นด้วยกับ "jer" นี่เป็นคำถามแปลก ๆ ฉันไม่คิดว่าวิธีแก้ปัญหานี้เป็น "วิธีแก้ปัญหา" เป็นการส่วนตัว ฉันคิดว่าการแปล "การเลื่อนเมาส์" บนเบราว์เซอร์เดสก์ท็อปเป็น "แตะนิ้ว" บนเบราว์เซอร์หน้าจอสัมผัสนั้นสมเหตุสมผล หากคุณเห็นด้วยกับการแปลนั้น แต่ต้องการแตะหนึ่งครั้งแทนการแตะสองครั้งฉันอาจจะทำการตรวจจับคุณลักษณะสำหรับเหตุการณ์ของ iPad (เช่น "ทัชสตาร์ต") และเปลี่ยนตัวจัดการเหตุการณ์ของคุณ อาจแตกโค้ดของคุณเป็นปลั๊กอิน jquery ประเภท "แตะหรือคลิก" ของฟังก์ชันการทำงานที่เริ่มทำงานแตกต่างกันไปตามคุณสมบัติ แต่ดูเหมือนว่าเฉพาะสำหรับเว็บไซต์ / แอปของคุณสำหรับฉัน
Andy Atkinson

1
ฉันคิดว่าการแปลนี้เป็นคุณลักษณะ หากคุณมีการตั้งค่าเหตุการณ์ที่วางเมาส์ไว้คุณต้องมียูทิลิตี้บางอย่างเพื่อดูเหตุการณ์เหล่านี้ การแตะเพียงครั้งเดียวจะเผยให้เห็นองค์ประกอบที่ลอยอยู่การแตะครั้งที่สองจะตามลิงก์ "ด้านหลัง" ที่วางเมาส์เหนือ
แอรอน

คำตอบ:


205

ยังไม่ได้ทดสอบสิ่งนี้อย่างเต็มที่ แต่เนื่องจาก iOS เริ่มการทำงานของเหตุการณ์การสัมผัสสิ่งนี้จึงสามารถทำงานได้โดยสมมติว่าคุณอยู่ในการตั้งค่า jQuery

$('a').on('click touchend', function(e) {
    var el = $(this);
    var link = el.attr('href');
    window.location = link;
});

แนวคิดคือ Mobile WebKit เริ่มต้นtouchendเหตุการณ์เมื่อสิ้นสุดการแตะดังนั้นเราจึงรับฟังสิ่งนั้นจากนั้นเปลี่ยนเส้นทางเบราว์เซอร์ทันทีที่touchendเหตุการณ์ถูกเริ่มทำงานบนลิงก์


17
ค่าหัวของฉันอยู่ที่ไหน : P
cduruk

2
อดทน Padwan ดังนั้นกล่าวว่าต้องใช้เวลา 24 ชั่วโมงจึงจะมีผล
Andrew Hedges

2
ในฐานะของ jQuery 1.7 เป็นที่ต้องการ.on .liveหลังจากอ่านคำตอบนี้ฉันพบว่าการเปลี่ยนรหัสให้$('a').on('click touchend', function(e) {...})ทำงานได้อย่างยอดเยี่ยม
Blazemonger

23
วิธีนี้ช่วยแก้ปัญหาเริ่มต้นได้ แต่จะสร้างปัญหาใหม่: เมื่อเลื่อนนิ้วไปจะถูกคลิก นี่ไม่ใช่วิธีแก้ปัญหา
luksak

9
สิ่งนี้มีข้อบกพร่องของมัน หากคุณคลิกลิงก์target="_blank"จะเปิดขึ้นในหน้าต่างเดียวกันและในหน้าต่างใหม่
rybo111

37

ยังไม่ชัดเจนว่าคำถามของคุณคืออะไร แต่ถ้าคุณแค่ต้องการกำจัดการดับเบิลคลิกในขณะที่ยังคงเอฟเฟกต์การวางเมาส์ไว้คำแนะนำของฉันคือ:

  • เพิ่มโฉบผลกระทบต่อและtouchstartmouseenter
  • นำผลกระทบเลื่อนบนmouseleave, และtouchmoveclick

พื้นหลัง

ในการจำลองเมาส์เบราว์เซอร์เช่น Webkit mobile จะยิงเหตุการณ์ต่อไปนี้หากผู้ใช้แตะและปล่อยนิ้วบนหน้าจอสัมผัส (เช่น iPad) (ที่มา: Touch And Mouseบน html5rocks.com):

  1. touchstart
  2. touchmove
  3. touchend
  4. ความล่าช้า 300 มิลลิวินาทีโดยที่เบราว์เซอร์ตรวจสอบให้แน่ใจว่าเป็นการแตะเพียงครั้งเดียวไม่ใช่การแตะสองครั้ง
  5. mouseover
  6. mouseenter
    • หมายเหตุ : ถ้าmouseover, mouseenterหรือmousemoveเหตุการณ์การเปลี่ยนแปลงเนื้อหาของหน้าเหตุการณ์ต่อไปนี้จะไม่ยิง
  7. mousemove
  8. mousedown
  9. mouseup
  10. click

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

ที่แย่ไปกว่านั้นคือหากเหตุการณ์วางเมาส์เปลี่ยนเนื้อหาของหน้าเหตุการณ์การคลิกจะไม่เริ่มทำงานตามที่อธิบายไว้ในคู่มือเนื้อหาเว็บ Safari - การจัดการเหตุการณ์โดยเฉพาะรูปที่ 6.4 ในเหตุการณ์ด้วยนิ้วเดียว "การเปลี่ยนแปลงเนื้อหา" คืออะไรจะขึ้นอยู่กับเบราว์เซอร์และเวอร์ชัน ฉันพบว่าสำหรับ iOS 7.0 การเปลี่ยนสีพื้นหลังไม่ใช่การเปลี่ยนแปลงเนื้อหา (หรือไม่มีอีกต่อไป)

อธิบายวิธีแก้ปัญหา

สรุป:

  • เพิ่มโฉบผลกระทบต่อและtouchstartmouseenter
  • นำผลกระทบเลื่อนบนmouseleave, และtouchmoveclick

โปรดทราบว่าไม่มีการดำเนินการใดtouchendๆ !

สิ่งนี้ใช้ได้กับเหตุการณ์ของเมาส์อย่างชัดเจน: mouseenterและmouseleave(เวอร์ชันปรับปรุงเล็กน้อยmouseoverและmouseout) จะเริ่มทำงานและเพิ่มและลบโฮเวอร์

หากผู้ใช้เป็นclickลิงก์จริงผลการวางเมาส์จะถูกลบออกไปด้วย เพื่อให้แน่ใจว่าจะถูกลบออกหากผู้ใช้กดปุ่มย้อนกลับในเว็บเบราว์เซอร์

นอกจากนี้ยังใช้ได้กับเหตุการณ์การสัมผัส: บนเอtouchstartฟเฟกต์โฮเวอร์จะถูกเพิ่ม มันเป็น '' 'ไม่ได้' '' touchendลบออก มันถูกเพิ่มอีกครั้งmouseenterและเนื่องจากสิ่งนี้ทำให้ไม่มีการเปลี่ยนแปลงเนื้อหา (ได้ถูกเพิ่มไปแล้ว) clickเหตุการณ์จึงเริ่มทำงานและลิงก์จะตามมาโดยไม่จำเป็นให้ผู้ใช้คลิกอีกครั้ง!

ความล่าช้า 300 มิลลิวินาทีที่เบราว์เซอร์มีระหว่างtouchstartเหตุการณ์และclickถูกนำไปใช้งานจริงเนื่องจากเอฟเฟกต์โฮเวอร์จะแสดงในช่วงเวลาสั้น ๆ นี้

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

แค่นั้นแหละ!

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

โซลูชั่นทางเลือก

ฉันพบปัญหาต่อไปนี้กับทางเลือกต่อไปนี้:

  • การตรวจจับเบราว์เซอร์:มีแนวโน้มที่จะเกิดข้อผิดพลาดอย่างมาก สมมติว่าอุปกรณ์มีเมาส์หรือระบบสัมผัสในขณะที่การใช้ทั้งสองอย่างร่วมกันจะกลายเป็นเรื่องปกติมากขึ้นเรื่อย ๆ เมื่อการแสดงผลแบบสัมผัสมีสัญญาณรบกวน
  • การตรวจจับสื่อ CSS:โซลูชัน CSS เท่านั้นที่ฉันรู้จัก ยังคงมีแนวโน้มที่จะเกิดข้อผิดพลาดและยังคงถือว่าอุปกรณ์มีเมาส์หรือสัมผัสในขณะที่ทั้งสองอย่างเป็นไปได้
  • จำลองเหตุการณ์การคลิกในtouchend:สิ่งนี้จะไปตามลิงก์อย่างไม่ถูกต้องแม้ว่าผู้ใช้จะต้องการเลื่อนหรือซูมเท่านั้นโดยไม่ได้ตั้งใจที่จะคลิกลิงก์จริงๆ
  • ใช้ตัวแปรเพื่อระงับเหตุการณ์ของเมาส์:ตั้งค่าตัวแปรtouchendที่ใช้เป็น if-condition ในเหตุการณ์ต่อมาของเมาส์เพื่อป้องกันการเปลี่ยนแปลงสถานะ ณ เวลานั้น ตัวแปรจะถูกรีเซ็ตในเหตุการณ์คลิก นี่เป็นทางออกที่ดีหากคุณไม่ต้องการให้มีการวางเมาส์บนอินเทอร์เฟซแบบสัมผัส น่าเสียดายที่วิธีนี้ใช้ไม่ได้หาก a touchendถูกยิงด้วยเหตุผลอื่นและไม่มีเหตุการณ์การคลิกเริ่มทำงาน (เช่นผู้ใช้เลื่อนหรือซูม) และต่อมาพยายามติดตามลิงก์ด้วยเมาส์ (เช่นบนอุปกรณ์ที่มีทั้งเมาส์และอินเทอร์เฟซแบบสัมผัส )

อ่านเพิ่มเติม

  • http://jsfiddle.net/macfreek/24Z5M/ ทดสอบวิธีแก้ปัญหาข้างต้นด้วยตัวคุณเองในแซนด์บ็อกซ์นี้
  • http://www.macfreek.nl/memory/Touch_and_mouse_with_hover_effects_in_a_web_browser คำตอบเดียวกันนี้พร้อมพื้นหลังอีกเล็กน้อย
  • http://www.html5rocks.com/en/mobile/touchandmouse/ บทความพื้นหลังที่ดีใน html5rocks.com เกี่ยวกับการสัมผัสและเมาส์โดยทั่วไป
  • https://developer.apple.com/library/ios/DOCUMENTATION/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html คู่มือเนื้อหาเว็บ Safari - การจัดการเหตุการณ์ ดูในรูปที่ 6.4 โดยเฉพาะซึ่งอธิบายว่าจะไม่มีการเริ่มเหตุการณ์ใด ๆ อีกหลังจากการเปลี่ยนแปลงเนื้อหาระหว่างเหตุการณ์mouseoverหรือmousemoveเหตุการณ์

ดูเพิ่มเติมคู่ปัญหาคลิก iPad / iPhoneและปิดการใช้งานโฉบผลกระทบต่อเบราว์เซอร์มือถือ


2
ดูเหมือนจะเป็นคำอธิบายที่ดีที่สุดสำหรับผู้ที่ต้องการวิธีแก้ปัญหาที่ตรงประเด็นมากกว่า Thanx
antiplayer

ขอขอบคุณเป็นพิเศษสำหรับข้อมูลเกี่ยวกับสีพื้นหลังสำหรับ> iOS7 ฉันใช้เวลาพยายามคิดว่าเมื่อไหร่จะได้ผล
staffang

20

ดูเหมือนว่าจะมีโซลูชัน CSS อยู่ เหตุผลที่ Safari รอการสัมผัสครั้งที่สองเป็นเพราะภาพพื้นหลัง (หรือองค์ประกอบ) ที่คุณมักกำหนดให้ในเหตุการณ์: hover หากไม่มีการแสดงคุณจะไม่มีปัญหาใด ๆ วิธีแก้ปัญหาคือกำหนดเป้าหมายแพลตฟอร์ม iOS ด้วยไฟล์ CSS รอง (หรือสไตล์ในกรณีของวิธี JS) ซึ่งจะลบล้าง: พื้นหลังวางเมาส์เพื่อสืบทอดเช่นและซ่อนองค์ประกอบที่คุณจะแสดงบนเมาส์ไว้เหนือ:

นี่คือตัวอย่าง CSS และ HTML - บล็อกผลิตภัณฑ์ที่มีป้ายกำกับติดดาววางเมาส์เหนือ:

HTML:

<a href="#" class="s"><span class="s-star"></span>Some text here</a>

CSS:

.s {
   background: url(some-image.png) no-repeat 0 0;

}
.s:hover {
   background: url(some-image-r.png) no-repeat 0 0;
}

.s-star {
   background: url(star.png) no-repeat 0 0;
   height: 56px;
   position: absolute;
   width: 72px;
   display:none;
}

.s:hover .s-star {
   display:block;
}

โซลูชัน (CSS รอง):

/* CSS */
/* Keep hovers the same or hidden */
.s:hover {
   background:inherit;
}
.s:hover .s-star {
   display:none;
}


คำตอบนี้มุ่งเน้นไปที่ภาพพื้นหลัง แต่คุณมีวิธีแก้ไขสำหรับการเปลี่ยนแปลงความทึบอย่างง่ายหรือไม่? โซลูชันนี้ใช้ไม่ได้กับสิ่งนี้
Ian S

5

ไม่จำเป็นต้องทำให้ซับซ้อนมากเกินไป

$('a').on('touchend', function() {
    $(this).click();
});

5

สิ่งที่ได้ผลสำหรับฉันคือสิ่งที่คนอื่น ๆ ได้กล่าวไว้แล้ว:

อย่าแสดง / ซ่อนองค์ประกอบบนโฮเวอร์หรือมูสมูฟ (ซึ่งเป็นเหตุการณ์ในกรณีของฉัน)

นี่คือสิ่งที่ Apple พูด ( https://developer.apple.com/library/content/documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html ):

องค์ประกอบที่คลิกได้คือลิงก์องค์ประกอบรูปแบบพื้นที่แผนที่รูปภาพหรือองค์ประกอบอื่น ๆ ที่มีการเคลื่อนย้ายเมาส์การเลื่อนเมาส์การวางเมาส์หรือตัวจัดการบนคลิก

หากผู้ใช้แตะองค์ประกอบที่คลิกได้เหตุการณ์จะมาตามลำดับต่อไปนี้: วางเมาส์เหนือเมาส์เลื่อนเมาส์ดาวน์เลื่อนเมาส์และคลิก นอกจากนี้หากเนื้อหาของเพจเปลี่ยนไปในเหตุการณ์ mousemove จะไม่มีการส่งเหตุการณ์ที่ตามมาในลำดับ ลักษณะการทำงานนี้ทำให้ผู้ใช้แตะเนื้อหาใหม่ได้

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

แต่ ... ถ้าคุณไม่ต้องการยุ่งกับ userAgents และยังคงซ่อน / แสดงองค์ประกอบบน hover / mousemove ฉันพบว่าคุณสามารถทำได้โดยใช้จาวาสคริปต์ดั้งเดิมเช่นนี้:

$("body").on("mouseover", function() {
       document.getElementsByTagName("my-class")[0].style.display = 'block'; //show element
       document.querySelector(".my-selector div").style.display = 'none'; // hide element
});

สิ่งนี้จะใช้ได้กับเวอร์ชันเดสก์ท็อปและจะไม่ทำอะไรเลยในเวอร์ชันมือถือ

และเพื่อความเข้ากันได้อีกเล็กน้อย ...

$("body").on("mouseover", function() {
   if (document.getElementsByTagName && document.querySelector) { // check compatibility
       document.getElementsByTagName("my-class")[0].style.display = 'block'; //show element
       document.querySelector(".my-selector div").style.display = 'none'; // hide element
    } else {
        $(".my-class").show();
        $(".my-selector div").hide();
    }
});

1
บิตนั้น "หากเนื้อหาของเพจเปลี่ยนไปในเหตุการณ์ mousemove จะไม่มีการส่งเหตุการณ์ตามลำดับ" สำหรับฉันจริงๆ ฉันมีหน้าเว็บที่ลิงก์ส่วนหัวจะต้องมีการแตะสองครั้งซึ่งปุ่มต่างๆในเนื้อหา (พร้อมการเปลี่ยน css3 ที่มีความสุขทั้งหมด) จะต้องใช้การแตะเพียงครั้งเดียว ปรากฏว่าลิงก์ส่วนหัวมีองค์ประกอบหลอกที่เปลี่ยนจาก opacity: 0 เป็น opacity: 1 เมื่อวางเมาส์เหนือ การลบเอฟเฟกต์นั้นช่วยแก้ปัญหาได้ทันทีและฉันพบวิธีแก้ปัญหา CSS เพื่อให้ได้รูปลักษณ์ที่ฉันต้องการ
Fake Haak

3

วิธีแก้ปัญหาของ cduruk ค่อนข้างมีประสิทธิภาพ แต่ทำให้เกิดปัญหาในบางส่วนของไซต์ของฉัน เนื่องจากฉันใช้ jQuery เพื่อเพิ่มคลาสโฮเวอร์ CSS อยู่แล้ววิธีแก้ปัญหาที่ง่ายที่สุดคือไม่เพิ่มคลาสโฮเวอร์ CSS บนอุปกรณ์มือถือ (หรืออย่างแม่นยำยิ่งขึ้นเพื่อเพิ่มเฉพาะเมื่อไม่ได้อยู่บนอุปกรณ์เคลื่อนที่)

นี่คือแนวคิดทั่วไป:

var device = navigator.userAgent.toLowerCase();
var ios = device.match(/(iphone|ipod|ipad)/);

if (!(ios)) {
    $(".portfolio-style").hover(
        function(){
            $(this).stop().animate({opacity: 1}, 100);
            $(this).addClass("portfolio-red-text");
        },
        function(){
            $(this).stop().animate({opacity: 0.85}, 100);
            $(this).removeClass("portfolio-red-text");
        }
    );
}

* รหัสลดลงเพื่อวัตถุประสงค์ในการอธิบาย


1
นี่คือคำตอบที่ชัดเจน "วิธีแก้ปัญหา" อื่น ๆ ไม่สามารถแก้ไขปัญหาได้ iOS Safari มีข้อบกพร่องอย่างชัดเจนเนื่องจากคิดว่าเราต้องการวางเมาส์ไว้ก่อน ระบบปฏิบัติการอื่นมีคุณสมบัติการวางเมาส์เหนือรายการเมื่อคุณวางเมาส์เหนือรายการ
Joshua Pack

นี่เป็นสิ่งเดียวที่ใช้ได้ผลสำหรับฉัน ขอบคุณมาก!
tx291

2

ฉันคิดว่ามันควรจะฉลาดที่จะลองในสถานที่ของmouseenter mouseoverเป็นสิ่งที่ใช้ภายในเมื่อมีผลผูกพัน.hover(fn,fn)และโดยทั่วไปเป็นสิ่งที่คุณต้องการ


1

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

ปัญหานี้แก้ได้

ใช้เพียงtouchstartหรือtouchend:

  • ทำให้เหตุการณ์เริ่มทำงานเมื่อมีคนพยายามเลื่อนผ่านเนื้อหาและเพิ่งจะเอานิ้วไปแตะองค์ประกอบนี้เมื่อเริ่มปัด - ทำให้เกิดการกระทำโดยไม่คาดคิด
  • อาจทำให้เหตุการณ์เริ่มทำงานบน longpressคล้ายกับการคลิกขวาบนเดสก์ท็อป ตัวอย่างเช่นหากเหตุการณ์การคลิกของคุณไปที่ URL X และผู้ใช้กดนานเพื่อเปิด X ในแท็บใหม่ผู้ใช้จะสับสนเมื่อพบ X ที่เปิดอยู่ในทั้งสองแท็บ ในบางเบราว์เซอร์ (เช่น iPhone) อาจทำให้เมนูกดแบบยาวไม่ปรากฏขึ้นด้วยซ้ำ

การทริกเกอร์mouseoverเหตุการณ์ในtouchstartและmouseoutต่อไปtouchmoveมีผลกระทบที่ร้ายแรงน้อยกว่า แต่จะรบกวนพฤติกรรมปกติของเบราว์เซอร์ตัวอย่างเช่น

  • การกดแบบยาวจะทำให้เมาส์โอเวอร์ไม่สิ้นสุด
  • เบราว์เซอร์ Android หลายรักษาสถานที่ตั้งของลายนิ้วมือบนtouchstartเหมือนmouseoverซึ่งเป็นmouseouted touchstartบนต่อไป วิธีหนึ่งในการดูเนื้อหาเมาส์โอเวอร์ใน Android คือการแตะบริเวณที่สนใจแล้วกระดิกนิ้วเลื่อนหน้าเล็กน้อย การรักษาtouchmoveเป็นmouseoutแบ่งนี้

การแก้ไขปัญหา

ตามทฤษฎีแล้วคุณสามารถเพิ่มธงได้touchmoveแต่ iPhone จะเรียกใช้ Touchmove แม้ว่าจะไม่มีการเคลื่อนไหวก็ตาม ในทางทฤษฎีแล้วคุณก็สามารถเปรียบเทียบtouchstartและtouchendเหตุการณ์pageXและpageY แต่บน iPhone ไม่มีtouchend pageXpageYหรือ

ดังนั้นน่าเสียดายที่จะครอบคลุมฐานทั้งหมดมันซับซ้อนกว่าเล็กน้อย

$el.on('touchstart', function(e){
    $el.data('tstartE', e);
    if(event.originalEvent.targetTouches){
        // store values, not reference, since touch obj will change
        var touch = e.originalEvent.targetTouches[0];
        $el.data('tstartT',{ clientX: touch.clientX, clientY: touch.clientY } );
    }
});
$el.on('touchmove', function(e){
    if(event.originalEvent.targetTouches){
        $el.data('tstartM', event.originalEvent.targetTouches[0]);
    }
});

$el.on('click touchend', function(e){
    var oldE = $el.data('tstartE');
    if( oldE && oldE.timeStamp + 1000 < e.timeStamp ) {
        $el.data('tstartE',false);
        return;
    }
    if( $el.data('iosTouchM') && $el.data('tstartT') ){
        var start = $el.data('tstartT'), end = $el.data('tstartM');
        if( start.clientX != end.clientX || start.clientY != end.clientY ){
            $el.data('tstartT', false);
            $el.data('tstartM', false);
            $el.data('tstartE',false);
            return;
        }
    }
    $el.data('tstartE',false);

ในทางทฤษฎีมีวิธีการที่จะได้รับเวลาที่แน่นอนที่ใช้สำหรับ longpress แทนการใช้เพียง 1000 รวมประมาณ แต่ในทางปฏิบัติก็ไม่ได้ว่าง่ายและดีที่สุดที่จะใช้พร็อกซี่ที่เหมาะสม


1

คำตอบของ MacFreak มีประโยชน์มากสำหรับฉัน ต่อไปนี้เป็นโค้ดเชิงปฏิบัติเพื่อช่วยคุณ

ปัญหา - การใช้การสัมผัสหมายความว่าทุกครั้งที่คุณเลื่อนนิ้วไปที่องค์ประกอบนั้นจะตอบสนองราวกับว่าคุณได้กดมันแม้ว่าคุณจะพยายามเลื่อนผ่านก็ตาม

ฉันกำลังสร้างเอฟเฟกต์ด้วย jQuery ซึ่งจะทำให้เส้นจางลงใต้ปุ่มบางปุ่มเพื่อ "ไฮไลต์" ปุ่มที่วางอยู่ ฉันไม่ต้องการให้หมายความว่าคุณต้องกดปุ่มสองครั้งบนอุปกรณ์สัมผัสเพื่อไปที่ลิงค์

นี่คือปุ่ม:

<a class="menu_button" href="#">
    <div class="menu_underline"></div>
</a>

ฉันต้องการให้ div "menu_underline" ปรากฏขึ้นเมื่อวางเมาส์และเลื่อนเมาส์ออก แต่ฉันต้องการให้อุปกรณ์ระบบสัมผัสสามารถไปตามลิงก์ได้ในคลิกเดียวไม่ใช่สองครั้ง

โซลูชัน - นี่คือ jQuery ที่จะทำให้มันใช้งานได้:

//Mouse Enter
$('.menu_button').bind('touchstart mouseenter', function(){
    $(this).find(".menu_underline").fadeIn();
});

//Mouse Out   
$('.menu_button').bind('mouseleave touchmove click', function(){
    $(this).find(".menu_underline").fadeOut();
});

ขอบคุณมากสำหรับความช่วยเหลือของคุณเกี่ยวกับ MacFreak นี้


1

ฉันเพิ่งค้นพบว่ามันใช้งานได้ถ้าคุณเพิ่ม Listener ที่ว่างเปล่าอย่าถามฉันว่าทำไม แต่ฉันทดสอบบน iPhone และ iPad ด้วย iOS 9.3.2 และใช้งานได้ดี

if(/iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream){
    var elements = document.getElementsByTagName('a');
    for(var i = 0; i < elements.length; i++){
        elements[i].addEventListener('touchend',function(){});
    }
}

1

ฉัน "คิดว่า" ลิงก์ของคุณไม่มีเหตุการณ์ onmouseover โดยที่การแตะ 1 ครั้งจะเปิดใช้งานบนเมาส์โอเวอร์และการแตะสองครั้งจะเป็นการเปิดใช้งานลิงก์ แต่ idk. ฉันไม่มีไอแพด ฉันคิดว่าคุณต้องใช้ท่าทางสัมผัส / เหตุการณ์สัมผัส

https://developer.apple.com/documentation/webkitjs


0

ฉันมีปัญหาเดียวกัน แต่ไม่ใช่บนอุปกรณ์สัมผัส เหตุการณ์จะทริกเกอร์ทุกครั้งที่คุณคลิก มีบางอย่างเกี่ยวกับการจัดคิวเหตุการณ์หรือมากกว่านั้น

อย่างไรก็ตามวิธีแก้ปัญหาของฉันเป็นเช่นนี้: เมื่อคลิกเหตุการณ์ (หรือสัมผัส?) คุณตั้งเวลา หากลิงก์ถูกคลิกอีกครั้งภายใน X ms คุณจะส่งคืนเท็จ

$.data()ในการตั้งค่าต่อจับเวลาองค์ประกอบคุณสามารถใช้

นอกจากนี้ยังอาจแก้ไขปัญหา @Ferdy ที่อธิบายไว้ข้างต้น


คุณสามารถโพสต์ลักษณะของรหัสนี้ได้หรือไม่? ฉันมีปัญหาเกี่ยวกับเหตุการณ์การคลิกที่ถูกทริกเกอร์สองครั้ง
แฟนซี

0

หากคุณใช้ Modernizr มันเป็นเรื่องง่ายมากที่จะใช้ Modernizr.touch ดังที่กล่าวไว้ก่อนหน้านี้

อย่างไรก็ตามฉันชอบใช้ Modernizr.touch และการทดสอบตัวแทนผู้ใช้ร่วมกันเพื่อความปลอดภัย

var deviceAgent = navigator.userAgent.toLowerCase();

var isTouchDevice = Modernizr.touch || 
(deviceAgent.match(/(iphone|ipod|ipad)/) ||
deviceAgent.match(/(android)/)  || 
deviceAgent.match(/(iemobile)/) || 
deviceAgent.match(/iphone/i) || 
deviceAgent.match(/ipad/i) || 
deviceAgent.match(/ipod/i) || 
deviceAgent.match(/blackberry/i) || 
deviceAgent.match(/bada/i));

function Tipsy(element, options) {
    this.$element = $(element);
    this.options = options;
    this.enabled = !isTouchDevice;
    this.fixTitle();
};

หากคุณไม่ได้ใช้ Modernizr คุณสามารถแทนที่Modernizr.touchฟังก์ชันด้านบนด้วย('ontouchstart' in document.documentElement)

นอกจากนี้โปรดทราบว่าการทดสอบตัวแทนผู้ใช้ iemobile จะทำให้คุณมีอุปกรณ์เคลื่อนที่ Microsoft ที่ตรวจพบได้กว้างกว่า Windows Phone


0

คุณสามารถใช้click touchend,

ตัวอย่าง:

$('a').on('click touchend', function() {
    var linkToAffect = $(this);
    var linkToAffectHref = linkToAffect.attr('href');
    window.location = linkToAffectHref;
});

ตัวอย่างด้านบนจะส่งผลต่อลิงก์ทั้งหมดบนอุปกรณ์ระบบสัมผัส

หากคุณต้องการกำหนดเป้าหมายเฉพาะลิงก์ที่เฉพาะเจาะจงคุณสามารถทำได้โดยการตั้งค่าชั้นเรียนเช่น:

HTML:

<a href="example.html" class="prevent-extra-click">Prevent extra click on touch device</a>

jquery:

$('a.prevent-extra-click').on('click touchend', function() {
    var linkToAffect = $(this);
    var linkToAffectHref = linkToAffect.attr('href');
    window.location = linkToAffectHref;
});

ไชโย

Jeroen


0

ฉันพบสถานการณ์ที่คล้ายกันซึ่งฉันมีเหตุการณ์ที่เชื่อมโยงกับสถานะ mouseenter / mouseleave / click ขององค์ประกอบ แต่ใน iPhone ผู้ใช้ต้องดับเบิลคลิกที่องค์ประกอบเพื่อทริกเกอร์เหตุการณ์ mouseenter ก่อนจากนั้นอีกครั้งเพื่อเริ่มเหตุการณ์การคลิก .

ฉันแก้ไขสิ่งนี้โดยใช้วิธีการที่คล้ายกันข้างต้น แต่ฉันใช้ปลั๊กอิน jQuery $ .browser (สำหรับ jQuery 1.9>) และเพิ่มเหตุการณ์. ทริกเกอร์ให้กับเหตุการณ์การเชื่อมต่อของ mouseenter ดังนี้:

// mouseenter event
$('.element').on( "mouseenter", function() {
    // insert mouseenter events below

    // double click fix for iOS and mouseenter events
    if ($.browser.iphone || $.browser.ipad) $(this).trigger('click');
});
// mouseleave event
$('.element').on( "mouseleave", function() { 
    // insert mouseout events below
});
// onclick event
$('.element').on( "click", function() {
    // insert click events below
});

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

คุณสามารถรับปลั๊กอิน jQuery $ .browser ได้ที่นี่: https://github.com/gabceb/jquery-browser-plugin


0

เพียงแค่การปรับปรุงเพื่อหลีกเลี่ยงการเปลี่ยนเส้นทางเมื่อคุณเลื่อนนิ้วไปบนลิงก์โดยไม่ได้ตั้งใจ

// tablet "one touch (click)" X "hover" > link redirection
$('a').on('touchmove touchend', function(e) {

    // if touchmove>touchend, set the data() for this element to true. then leave touchmove & let touchend fail(data=true) redirection
    if (e.type == 'touchmove') {
        $.data(this, "touchmove_cancel_redirection", true );
        return;
    }

    // if it's a simple touchend, data() for this element doesn't exist.
    if (e.type == 'touchend' && !$.data(this, "touchmove_cancel_redirection")) {
        var el = $(this);
        var link = el.attr('href');
        window.location = link;
    }

    // if touchmove>touchend, to be redirected on a future simple touchend for this element
    $.data(this, "touchmove_cancel_redirection", false );
});

0

ด้วยแรงบันดาลใจจาก MacFreak ฉันจึงรวบรวมสิ่งที่เหมาะกับตัวเอง

วิธี js นี้จะป้องกันไม่ให้โฮเวอร์ติดบน iPad และป้องกันการคลิกที่ลงทะเบียนเป็นการคลิกสองครั้งในบางกรณี ใน CSS ถ้าคุณมี: hover psudo คลาสใน css ของคุณให้เปลี่ยนเป็น. hover ตัวอย่างเช่น. บางคลาส: โฮเวอร์เป็น. บางคลาส. โฮเวอร์

ทดสอบโค้ดนี้บน iPad เพื่อดูว่าวิธีการโฮเวอร์ css และ js ทำงานแตกต่างกันอย่างไร (ในเอฟเฟกต์โฮเวอร์เท่านั้น) ปุ่ม CSS ไม่มีการแจ้งเตือนการคลิกที่สวยงาม http://jsfiddle.net/bensontrent/ctgr6stm/

function clicker(id, doStuff) {
  id.on('touchstart', function(e) {
    id.addClass('hover');
  }).on('touchmove', function(e) {
    id.removeClass('hover');
  }).mouseenter(function(e) {
    id.addClass('hover');
  }).mouseleave(function(e) {
    id.removeClass('hover');
  }).click(function(e) {
    id.removeClass('hover');
    //It's clicked. Do Something
    doStuff(id);
  });
}

function doStuff(id) {
  //Do Stuff
  $('#clicked-alert').fadeIn(function() {
    $(this).fadeOut();
  });
}
clicker($('#unique-id'), doStuff);
button {
  display: block;
  margin: 20px;
  padding: 10px;
  -webkit-appearance: none;
  touch-action: manipulation;
}
.hover {
  background: yellow;
}
.btn:active {
  background: red;
}
.cssonly:hover {
  background: yellow;
}
.cssonly:active {
  background: red;
}
#clicked-alert {
  display: none;
}
<button id="unique-id" class="btn">JS Hover for Mobile devices<span id="clicked-alert"> Clicked</span>

</button>
<button class="cssonly">CSS Only Button</button>
<br>This js method prevents hover from sticking on an ipad, and prevents the click registering as two clicks. In CSS, if you have any :hover in your css, change them to .hover For example .some-class:hover to .some-class.hover


0

เพื่อให้ลิงก์ทำงานได้โดยไม่ต้องเลื่อนการสัมผัสฉันแก้ไขปัญหานี้ด้วยเหตุการณ์ "แตะ" ของ jQuery Mobile:

    $('a').not('nav.navbar a').on("tap", function () {
        var link = $(this).attr('href');
        if (typeof link !== 'undefined') {
            window.location = link;
        }
    });

0

ฉันสายเกินไปฉันรู้ แต่นี่เป็นหนึ่งในวิธีแก้ปัญหาที่ง่ายที่สุดที่ฉันพบ:

    $('body').on('touchstart','*',function(){   //listen to touch
        var jQueryElement=$(this);  
        var element = jQueryElement.get(0); // find tapped HTML element
        if(!element.click){
            var eventObj = document.createEvent('MouseEvents');
            eventObj.initEvent('click',true,true);
            element.dispatchEvent(eventObj);
        }
    });

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


0

ข้อมูลโค้ดสั้น ๆ นี้น่าจะใช้ได้ ทริกเกอร์เหตุการณ์การคลิกเมื่อแตะลิงก์:

  $('a').on('touchstart', function() {
    $(this).trigger('click');
  });

0

ไม่มีคำตอบอื่นใดที่เหมาะกับฉัน แอปของฉันมีผู้ฟังเหตุการณ์จำนวนมากช่องทำเครื่องหมายและลิงก์ของตัวเองที่มีผู้ฟังและลิงก์ที่ไม่มีผู้ฟัง

ฉันใช้สิ่งนี้:

var selector = "label, a, button";
var timer;
var startX;
var startY;
$(document).on("click", selector, function (e) {
    if ($(this).data("touched") === true) {
        e.stopImmediatePropagation();
        return false;
    }
    return;
}).on("touchend", selector, function (e) {
    if (Math.abs(startX - e.originalEvent.changedTouches[0].screenX) > 10 || Math.abs(startY - e.originalEvent.changedTouches[0].screenY) > 10)
        // user action is not a tap
        return;
    var $this = $(this);
    // Visit: http://stackoverflow.com/questions/1694595/can-i-call-jquery-click-to-follow-an-a-link-if-i-havent-bound-an-event-hand/12801548#12801548
    this.click();
    // prevents double click
    $this.data("touched", true);
    if (timer)
        clearTimeout(timer);
    setTimeout(function () {
        $this.data("touched", false);
    }, 400);
    e.stopImmediatePropagation();
    return false;
}).on("touchstart", function (e) {
    startX = e.originalEvent.changedTouches[0].screenX;
    startY = e.originalEvent.changedTouches[0].screenY;
});

0

สิ่งนี้ใช้ได้กับฉันเมื่อคุณมีเมนูแบบเลื่อนลง jquery ui

if (navigator.userAgent.match(/(iPod|iPhone|iPad)/)) {
      $('.ui-autocomplete').off('menufocus hover mouseover');
}

0

หลีกเลี่ยงการเปลี่ยนรูปแบบ "การแสดงผล" ภายในเหตุการณ์ hover css ฉันมี "display: block" อยู่ในสถานะวางเมาส์เหนือ หลังจากลบ ios ออกไปด้วยการแตะเพียงครั้งเดียว ดูเหมือนว่าการอัปเดต IOS ล่าสุดได้แก้ไข "คุณลักษณะ" นี้แล้ว


0

วิธีที่ง่ายที่สุดในการแก้ปัญหาการดับเบิลคลิกบน IPad คือการตัด css ของคุณเพื่อให้ได้ผลโฮเวอร์ในการสืบค้นสื่อ@media (pointer: fine):

@media (pointer: fine) {
  a span {
    display: none;
  }
  a:hover span {
    display: inline-block;
  }
}

CSS ที่รวมอยู่ในแบบสอบถามสื่อนี้จะใช้กับเดสก์ท็อปเท่านั้น

คำอธิบายของโซลูชันนี้อยู่ที่นี่https://css-tricks.com/annoying-mobile-double-tap-link-issue/


-1

คุณสามารถตรวจสอบได้navigator.userAgentดังนี้:

if(!navigator.userAgent.match(/iPhone/i) || !navigator.userAgent.match(/iPad/i)) {
    //bind your mouseovers...
}

แต่คุณจะต้องตรวจสอบแบล็กเบอร์รี่หุ่นยนต์หน้าจอสัมผัสอื่น ๆ คุณสามารถผูกเมาส์โอเวอร์ได้เฉพาะในกรณีที่ userAgent มี Mozilla, IE, Webkit หรือ Opera แต่คุณยังต้องคัดกรองอุปกรณ์บางอย่างเนื่องจาก Droid รายงานสตริง userAgent เป็น:

Mozilla/5.0 (Linux; U; Android 2.0.1; en-us; Droid Build/ESD56) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17

สายของ iPhone นั้นคล้ายกัน หากคุณเพียงแค่หน้าจอสำหรับ iPhone, iPod, iPad, Android และ Blackberry คุณอาจได้รับอุปกรณ์พกพาส่วนใหญ่ แต่ไม่ใช่ทั้งหมด


ฉันคิดว่าตอนนี้เพื่อไม่ให้คลั่งไคล้สิ่งที่ดีที่สุดที่ควรทำอาจเป็นเพียงสคริปต์ที่ข้ามเหตุการณ์ที่เลื่อนไปมา .. ฉันเดาว่าคำตอบแรกนั้นดี ... และใช่คุณพูดถูก ... ฉันควร คิดถึงอุปกรณ์อื่น ๆ ทั้งหมด ... ฉันหวังว่า Jquery หรือปลั๊กอินบางตัวจะมีคุณสมบัติการแยกประเภทนี้ .. !
Francesco

wurfl.sourceforge.netนี่อาจเป็นคำตอบของคุณ ฐานข้อมูลของอุปกรณ์ไร้สาย จะไม่ตรงไปตรงมาเหมือนปลั๊กอิน jQuery แต่คุณสามารถเขียนได้ตลอดเวลา! นอกจากนี้ยังมีtera-wurfl.comซึ่งใช้ฐานข้อมูลมากกว่าไฟล์ xml ยังไม่ได้ทำการขุดมากนัก แต่อาจมีเวอร์ชันโฮสต์อยู่ดังนั้นคุณไม่ต้องกังวลเกี่ยวกับการอัปเดตไฟล์ wurfl หรือฐานข้อมูล tera-wurfl ให้เป็นปัจจุบัน
jasongetsdown

1
ฉันพลาดอะไรไปหรือไม่ใช่คำถามเกี่ยวกับการตรวจจับ iPads แต่เกี่ยวกับการทำงานกับพฤติกรรมเฉพาะบน iPads
Andrew Hedges

5
UA ดม? ยุค 90: P
Macha

-1

เพียงแค่สร้างข้อความค้นหาสื่อ CSS ซึ่งไม่รวมแท็บเล็ตและอุปกรณ์มือถือและวางเมาส์ไว้ที่นั่น คุณไม่จำเป็นต้องใช้ jQuery หรือ JavaScript สำหรับสิ่งนี้

@media screen and (min-device-width:1024px) {
    your-element:hover {
        /* Do whatever here */
    }
}

และอย่าลืมเพิ่มสิ่งนี้ลงในส่วนหัว html ของคุณเพื่อให้แน่ใจว่าคำนวณด้วยพิกเซลจริงไม่ใช่ความละเอียด

<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.