Làm cách nào để mô phỏng di chuột với các trình duyệt hỗ trợ cảm ứng?


120

Với một số HTML như thế này:

<p>Some Text</p>

Sau đó, một số CSS như thế này:

p {
  color:black;
}

p:hover {
  color:red;
}

Làm cách nào để cho phép một lần chạm lâu trên thiết bị hỗ trợ cảm ứng để tái tạo di chuột? Tôi có thể thay đổi đánh dấu / sử dụng JS, v.v. nhưng không thể nghĩ ra cách dễ dàng để làm điều này.


Tôi đặc biệt nghĩ đến hệ điều hành iPhone - đó là bản demo của hoạt ảnh CSS mà đối với nhiều người, việc di chuột qua đó dễ sử dụng hơn là nhấp chuột để bắt đầu.
Rich Bradshaw

Câu trả lời:


172

OK, tôi đã tìm ra nó! Nó liên quan đến việc thay đổi CSS một chút và thêm một số JS.

Sử dụng jQuery để làm cho nó dễ dàng:

$(document).ready(function() {
    $('.hover').on('touchstart touchend', function(e) {
        e.preventDefault();
        $(this).toggleClass('hover_effect');
    });
});

Trong tiếng Anh: khi bạn bắt đầu hoặc kết thúc một lần chạm, hãy bật hover_effecthoặc tắt lớp học .

Sau đó, trong HTML của bạn, thêm một lớp di chuột vào bất kỳ thứ gì bạn muốn nó hoạt động. Trong CSS của bạn, thay thế bất kỳ phiên bản nào của:

element:hover {
    rule:properties;
}

với

element:hover, element.hover_effect {
    rule:properties;
}

Và chỉ để tăng thêm tính hữu ích, hãy thêm điều này vào CSS của bạn:

.hover {
-webkit-user-select: none;
-webkit-touch-callout: none;        
}

Để dừng trình duyệt yêu cầu bạn sao chép / lưu / chọn hình ảnh hoặc bất cứ điều gì.

Dễ dàng!


Điều đó thật tuyệt. Tôi chia chức năng domready lên mặc dù vì toggleđiều sẽ mess lên nếu người dùng chạm vào một phần tử và kéo khác (ví dụ như nếu họ chạm vào mục sai và đang cố gắng để hủy bỏ các liên lạc)
Jacksonkr

Tôi đã xóa touchendpreventDefault()trong trang web của mình và nó hoạt động tốt nhưng bây giờ các menu không tự động đóng lại bằng cách chạm ngoài mục tiêu.
Даниил Пронин

Tôi cũng muốn một số lời khuyên về cách đóng menu như vậy khi người dùng chạm vào một nơi khác hoặc bắt đầu cuộn. Tôi đoán có thể có một touchstartngười nghe khác trên cơ thể (hoặc tương tự) nhưng tôi tự hỏi liệu có cách nào tốt hơn không. Cảm ơn!
Darryl Young

2
Có cách nào để bỏ qua một cử chỉ cuộn không? Điều này thực hiện chính xác những gì tôi cần nhưng bây giờ tôi không thể cuộn lên và xuống nội dung có tác dụng này.
alsobubbly

1
Tôi đã gỡ bỏ PreventDefault vì tôi muốn khả dụng cuộn nhưng cảm ơn các mẹo về touchstart và touchhend! Chúa gửi đây là câu trả lời duy nhất hoạt động đáng tin cậy trên tất cả các trình duyệt.
Petraeus

54

Tất cả những gì bạn cần làm là liên kết touchstart trên cha mẹ. Một cái gì đó như thế này sẽ hoạt động:

$('body').on('touchstart', function() {});

Bạn không cần phải làm gì trong hàm, hãy để trống. Điều này sẽ đủ để di chuột khi chạm vào, vì vậy một lần chạm hoạt động giống như: di chuột và ít giống như: hoạt động. Phép thuật iOS.


2
Giải pháp này có cho phép liên kết được thực thi ở lần nhấn thứ hai không?
samuelkobe

1
Không, nó vẫn kích hoạt cú nhấp chuột trong lần chạm đầu tiên. Tôi chỉ thử nghiệm nó.
Jack

Giải pháp tuyệt vời! Nhanh chóng và dễ dàng.
Hunter Turner

41

Thử cái này:

<script>
document.addEventListener("touchstart", function(){}, true);
</script>

Và trong CSS của bạn:

element:hover, element:active {
-webkit-tap-highlight-color: rgba(0,0,0,0);
-webkit-user-select: none;
-webkit-touch-callout: none /*only to disable context menu on long press*/
}

Với mã này, bạn không cần thêm một lớp .hover!


1
điều này hiệu quả với tôi .. một số thứ khác có thể giúp ích nhiều hơn nữa là thay vì thêm javascript, hãy làm như sau: <body ontouchstart = ""> sau đó thêm một bộ đếm thời gian nhỏ trong sự kiện css: active: tr: active {background-color : # 118aab; chuyển tiếp: tất cả .2s tuyến tính; -webkit-tap-highlight-color: rgba (0,0,0,0); -webkit-user-select: none; -webkit-touch-callout: none}
Kozy

Đã làm cho tôi. Cảm ơn ... Điều duy nhất - nó hơi trễ một chút ... Ý tôi là - sau khi bạn nhấn, nó không tải ngay lập tức.
Roman Losev

Sử dụng fastclick.js để loại bỏ độ trễ
Anselm

25

Để trả lời câu hỏi chính của bạn: “Làm cách nào để mô phỏng di chuột bằng thao tác chạm trong các trình duyệt hỗ trợ cảm ứng?”

Chỉ cần cho phép 'nhấp vào' phần tử (bằng cách chạm vào màn hình), sau đó kích hoạt hoversự kiện bằng JavaScript.

var p = document.getElementsByTagName('p')[0];
p.onclick = function() {
 // Trigger the `hover` event on the paragraph
 p.onhover.call(p);
};

Điều này sẽ hoạt động, miễn là có một hoversự kiện trên thiết bị của bạn (mặc dù nó thường không được sử dụng).

Cập nhật: Tôi vừa thử nghiệm kỹ thuật này trên iPhone của mình và nó có vẻ hoạt động tốt. Hãy dùng thử tại đây: http://jsfiddle.net/mathias/YS7ft/show/light/

Nếu bạn muốn sử dụng 'chạm lâu' để kích hoạt di chuột thay thế, bạn có thể sử dụng đoạn mã trên làm điểm bắt đầu và vui chơi với bộ tính giờ và nội dung;)


Tôi không biết về bit onhover.call (p) đó, điều đó khá tuyệt. Không có di chuột mặc dù ...
Rich Bradshaw

Bạn đã thử nghiệm điều này với nhiều yếu tố và cảm ứng lâu chưa? Có nghĩa là người dùng di chuyển ngón tay của mình xung quanh màn hình và hiển thị kiểu di chuột cho từng phần tử?
Marcus

Có vẻ như nếu bạn đang sử dụng jQuery, bạn có thể chỉ gọi sự kiện hover bằng chính jQuery, ví dụ: jQuery.hover (); Tuy nhiên, không chắc api hỗ trợ điều đó.
Kzqai

Rất tiếc, đó là một nhận xét áp dụng hơn cho bài đăng ở trên. Nó thực sự sử dụng jQuery, xin lỗi.
Kzqai

Bạn có cần phải có bất kỳ tập lệnh đặc biệt nào hoặc gọi hàm không? Nó hoạt động với tôi nhưng chỉ trên một trang và tôi không biết sự khác biệt là gì.
Richard Young

13

Giải pháp cải tiến hơn nữa

Đầu tiên, tôi theo cách tiếp cận của Rich Bradshaw , nhưng sau đó các vấn đề bắt đầu xuất hiện. Bằng cách thực hiện e.preventDefault () trên sự kiện 'touchstart' , trang không còn cuộn nữa và việc nhấn và giữ cũng không thể kích hoạt menu tùy chọn cũng như thu phóng nhấp đúp là có thể hoàn tất quá trình thực thi.

Một giải pháp có thể là tìm ra sự kiện nào đang được gọi và chỉ cần e.preventDefault () trong phần sau, 'touchhend' . Vì 'touchmove' của scroll xuất hiện trước 'touchhend', nó sẽ được giữ nguyên theo mặc định và 'click' cũng bị ngăn vì nó có từ sau trong chuỗi sự kiện áp dụng cho thiết bị di động, như vậy:

// Binding to the '.static_parent' ensuring dynamic ajaxified content
$('.static_parent').on('touchstart touchend', '.link', function (e) {

    // If event is 'touchend' then...
    if (e.type == 'touchend') {
        // Ensuring we event prevent default in all major browsers
        e.preventDefault ? e.preventDefault() : e.returnValue = false;
    }

    // Add class responsible for :hover effect
    $(this).toggleClass('hover_effect');
});

Nhưng sau đó, khi menu tùy chọn xuất hiện, nó không còn kích hoạt 'touchhend' chịu trách nhiệm chuyển đổi lớp học và lần sau, hành vi di chuột sẽ ngược lại, hoàn toàn bị trộn lẫn.

Một giải pháp sau đó sẽ là, một lần nữa, có điều kiện tìm ra sự kiện nào chúng ta đang tham gia hoặc chỉ thực hiện các sự kiện riêng biệt và sử dụng addClass ()removeClass () tương ứng trên 'touchstart''touchhend' , đảm bảo sự kiện luôn bắt đầu và kết thúc bằng tương ứng thêm và bớt thay vì quyết định có điều kiện. Để kết thúc, chúng tôi cũng sẽ ràng buộc lệnh gọi lại xóa với loại sự kiện 'tiêu điểm' , chịu trách nhiệm xóa bất kỳ lớp di chuột nào của liên kết có thể ở lại và không bao giờ được truy cập lại, như vậy:

$('.static_parent').on('touchstart', '.link', function (e) {
    $(this).addClass('hover_effect');
});

$('.static_parent').on('touchend focusout', '.link', function (e) {
    // Think double click zoom still fails here
    e.preventDefault ? e.preventDefault() : e.returnValue = false;
    $(this).removeClass('hover_effect');
});

Lưu ý: Một số lỗi vẫn xảy ra trong hai giải pháp trước và, cũng có thể nghĩ rằng (không được thử nghiệm), thu phóng nhấp đúp cũng không thành công.

Gọn gàng và Hy vọng không có lỗi (không phải :)) Giải pháp Javascript

Bây giờ , đối với phương pháp thứ hai, gọn gàng hơn, gọn gàng hơn và đáp ứng, chỉ sử dụng javascript (không có sự kết hợp giữa lớp .hover và pseudo: hover) và từ đó bạn có thể gọi trực tiếp hành vi ajax của mình trên sự kiện 'nhấp chuột' phổ biến (di động và máy tính để bàn) , Tôi đã tìm thấy một câu hỏi được trả lời khá tốt mà từ đó cuối cùng tôi đã hiểu cách tôi có thể kết hợp các sự kiện chạm và chuột với nhau mà không có một số lệnh gọi lại sự kiện chắc chắn sẽ thay đổi các sự kiện lẫn nhau trong chuỗi sự kiện. Đây là cách thực hiện:

$('.static_parent').on('touchstart mouseenter', '.link', function (e) {
    $(this).addClass('hover_effect');
});

$('.static_parent').on('mouseleave touchmove click', '.link', function (e) {
    $(this).removeClass('hover_effect');

    // As it's the chain's last event we only prevent it from making HTTP request
    if (e.type == 'click') {
        e.preventDefault ? e.preventDefault() : e.returnValue = false;

        // Ajax behavior here!
    }
});

3

hoverKhông thể thực hiện hiệu ứng chuột trên thiết bị cảm ứng. Khi tôi xuất hiện với tình huống tương tự, safari iostôi đã sử dụng:active css để tạo hiệu ứng.

I E.

p:active {
  color:red;
}

Trong trường hợp của tôi, nó hoạt động. Có thể đây cũng là trường hợp có thể được sử dụng mà không sử dụng javascript. Chỉ cần thử.


2

Thêm mã này và sau đó đặt lớp "tapHover" thành các phần tử mà bạn muốn làm việc theo cách này. Lần đầu tiên bạn chạm vào một phần tử, nó sẽ có được giả cổ ": hover" và lớp "tapped". Sự kiện nhấp chuột sẽ bị ngăn chặn. Lần thứ hai bạn nhấn vào cùng một phần tử - sự kiện nhấp chuột sẽ được kích hoạt.

// Activate only in devices with touch screen
if('ontouchstart' in window)
{
    // this will make touch event add hover pseudoclass
    document.addEventListener('touchstart', function(e) {}, true);

    // modify click event
    document.addEventListener('click', function(e) {
        // get .tapHover element under cursor
        var el = jQuery(e.target).hasClass('tapHover')
            ? jQuery(e.target)
            : jQuery(e.target).closest('.tapHover');

        if(!el.length)
            return;

        // remove tapped class from old ones
        jQuery('.tapHover.tapped').each(function() {
            if(this != el.get(0))
                jQuery(this).removeClass('tapped');
        });

        if(!el.hasClass('tapped'))
        {
            // this is the first tap
            el.addClass('tapped');
            e.preventDefault();
            return false;
        }
        else
        {
            // second tap
            return true;
        }
    }, true);
}
.box {
	float:		left;
	
	display:	inline-block;
	margin:		50px 0 0 50px;
	width:		100px;
	height:		100px;
	overflow:	hidden;
	
	font-size:	20px;
	
	border:		solid 1px black;
}
.box.tapHover {
	background:	yellow;
}
.box.tapped {
	border:		solid 3px red;
}
.box:hover {
	background:	red;
}
<div class="box" onclick="this.innerHTML = Math.random().toFixed(5)"></div>
<div class="box tapHover" onclick="this.innerHTML = Math.random().toFixed(5)"></div>
<div class="box tapHover" onclick="this.innerHTML = Math.random().toFixed(5)"></div>


1

Nếu không có thiết bị (hoặc đúng hơn là trình duyệt) JS cụ thể, tôi khá chắc rằng bạn đã gặp may.

Chỉnh sửa: nghĩ rằng bạn muốn tránh điều đó cho đến khi tôi đọc lại câu hỏi của bạn. Trong trường hợp Mobile Safari, bạn có thể đăng ký để nhận tất cả các sự kiện cảm ứng tương tự như những gì bạn có thể làm với UIView-s gốc. Không thể tìm thấy tài liệu ngay bây giờ, tôi sẽ cố gắng.


1

Một cách để thực hiện là thực hiện hiệu ứng di chuột khi chạm bắt đầu, sau đó loại bỏ hiệu ứng di chuột khi chạm di chuyển hoặc kết thúc.

Đây là những gì Apple phải nói về xử lý cảm ứng nói chung, kể từ khi bạn đề cập đến iPhone.


Nội dung liên kết có còn phù hợp bây giờ không?
Flavien Volken

1

Sở thích cá nhân của tôi là cũng quy các :hoverkiểu cho :focustrạng thái, như:

p {
    color: red;
}

p:hover, p:focus {
    color: blue;
}

Sau đó với HTML sau:

<p id="some-p-tag" tabindex="-1">WOOOO</p>

Và JavaScript sau:

$("#some-p-tag").on("touchstart", function(e){
    e.preventDefault();
    var $elem = $(this);

    if($elem.is(":focus")) {
        //this can be registered as a "click" on a mobile device, as it's a double tap
        $elem.blur()
    }
    else {
        $elem.focus();
    }
});

1

Đã giải quyết 2019 - Di chuột khi chạm

Bây giờ có vẻ như tốt nhất là tránh sử dụng di chuột hoàn toàn với ios hoặc cảm ứng nói chung. Mã dưới đây áp dụng css của bạn miễn là duy trì cảm ứng và không có các tờ rơi ios khác. Làm cái này;

  1. Truy vấn thêm: $ ("p"). On ("touchstart", function (e) {$ (this) .focus (); e.preventDefault ();});

  2. CSS: thay p: hover bằng p: focus và thêm p: active

Các tùy chọn;

  • thay thế bộ chọn jquery p bằng bất kỳ lớp nào, v.v.

  • để giữ nguyên hiệu ứng, hãy giữ p: hover và thêm nội dung {con trỏ: ponter;} để một lần nhấn ở bất kỳ đâu sẽ kết thúc

  • thử các sự kiện nhấp và di chuột qua cũng như khởi động lại bằng cùng một mã (nhưng không được thử nghiệm)

  • loại bỏ e.preventDefault (); để cho phép người dùng sử dụng các flyout của ios, ví dụ: copy

Ghi chú

  • chỉ được kiểm tra cho các phần tử văn bản, ios có thể xử lý đầu vào, v.v. khác nhau

  • chỉ được thử nghiệm trên iphone XR ios 12.1.12 và ipad 3 ios 9.3.5, sử dụng Safari hoặc Chrome.


0

Sự kết hợp giữa Javascript và jQuery gốc:

var gFireEvent = function (oElem,sEvent) 
{
 try {
 if( typeof sEvent == 'string' && o.isDOM( oElem ))
 {
  var b = !!(document.createEvent),
     evt = b?document.createEvent("HTMLEvents"):document.createEventObject();
  if( b )    
  {  evt.initEvent(sEvent, true, true ); 
    return !oElem.dispatchEvent(evt);
  }
  return oElem.fireEvent('on'+sEvent,evt);
 }
 } catch(e) {}
 return false;
};


// Next you can do is (bIsMob etc you have to determine yourself):

   if( <<< bIsMob || bIsTab || bisTouch >>> )
   {
     $(document).on('mousedown', function(e)
     {
       gFireEvent(e.target,'mouseover' );
     }).on('mouseup', function(e)
     {
       gFireEvent(e.target,'mouseout' );
     });
   }

1
xin lỗi để được pedantic nhưng jquery là javacript
matpol

2
@matpol: jQuery là javascript nhưng javascript không phải jQuery. Đặc biệt cho bạn, tôi thêm từ 'pure', javascript thuần túy. Có hài lòng không thưa ông?
Codebeat

bạn không thể sử dụng jquery nếu không sử dụng javascript 'thuần túy'. Tôi chỉ đưa ra quan điểm vì một số người thường xuyên SO dường như không biết điều này.
matpol

5
Sự kết hợp giữa Javascript và jQuery gốc, Bạn có hài lòng không?
Codebeat

0

Giải pháp dễ dàng nhất mà tôi tìm thấy: Tôi có một số thẻ <span> với quy tắc: hover css trong đó. Tôi đã chuyển cho <a href = "javascript: void (0)"> và voilà. Các kiểu di chuột trong iOS bắt đầu hoạt động.


0

Sử dụng cũng có thể sử dụng CSS, thêm tiêu điểm và hoạt động (cho IE7 trở xuống) vào liên kết ẩn. Ví dụ về menu ul bên trong div với menu lớp:

.menu ul ul {display:none; position:absolute; left:100%; top:0; padding:0;}
.menu ul ul ul {display:none; position:absolute; top:0; left:100%;}
.menu ul ul a, .menu ul ul a:focus, .menu ul ul a:active { width:170px; padding:4px 4%; background:#e77776; color:#fff; margin-left:-15px; }
.menu ul li:hover > ul { display:block; }
.menu ul li ul li {margin:0;}

Đã muộn và chưa được kiểm tra, nên hoạt động ;-)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.