Tắt hiệu ứng di chuột trên trình duyệt di động


113

Tôi đang viết một trang Web dùng cho cả máy tính để bàn và máy tính bảng. Khi nó được truy cập từ máy tính để bàn, tôi muốn các vùng có thể nhấp của màn hình sáng lên với các :hoverhiệu ứng (màu nền khác nhau, v.v.) Với máy tính bảng, không có chuột, vì vậy tôi không muốn bất kỳ hiệu ứng di chuột nào.

Vấn đề là, khi tôi chạm vào một thứ gì đó trên máy tính bảng, trình duyệt rõ ràng có một số loại "con trỏ chuột vô hình" mà nó di chuyển đến vị trí tôi đã nhấn, và sau đó để nó ở đó - vì vậy thứ tôi vừa chạm sáng lên với hiệu ứng di chuột cho đến khi tôi chạm vào thứ khác.

Làm cách nào để có được các hiệu ứng di chuột khi tôi đang sử dụng chuột nhưng lại tắt chúng khi tôi đang sử dụng màn hình cảm ứng?

Trong trường hợp ai đó đang nghĩ đến việc đề xuất nó, tôi không muốn sử dụng tính năng đánh hơi tác nhân người dùng. Cùng một thiết bị có thể có cả màn hình cảm ứng và chuột (có thể không quá phổ biến hiện nay, nhưng nhiều hơn thế nữa trong tương lai). Tôi không quan tâm đến thiết bị, tôi quan tâm đến cách nó hiện đang được sử dụng: chuột hay màn hình cảm ứng.

Tôi đã thử nối các touchstart, touchmovetouchendcác sự kiện và gọi preventDefault()tất cả chúng, điều này đôi khi ngăn chặn "con trỏ chuột vô hình"; nhưng nếu tôi chạm nhanh qua lại giữa hai yếu tố khác nhau, sau một vài lần nhấn, nó sẽ bắt đầu di chuyển "con trỏ chuột" và dù sao cũng làm sáng các hiệu ứng di chuột - điều đó giống như tôi preventDefaultkhông phải lúc nào cũng được. Tôi sẽ không cung cấp cho bạn các chi tiết trừ khi cần thiết - tôi thậm chí không chắc đó là cách tiếp cận phù hợp để thực hiện; nếu ai có cách sửa chữa đơn giản hơn, tôi tất cả các tai.


Chỉnh sửa: Điều này có thể được sao chép bằng CSS chuẩn không có thật :hover, nhưng đây là bản diễn lại nhanh để tham khảo.

<style>
  .box { border: 1px solid black; width: 150px; height: 150px; }
  .box:hover { background: blue; }
</style>
<div class="box"></div>
<div class="box"></div>

Nếu bạn di chuột qua một trong hai hộp, nó sẽ nhận được nền màu xanh, tôi muốn. Nhưng nếu bạn chạm vào một trong hai hộp, nó cũng sẽ nhận được nền màu xanh lam, đó là điều tôi đang cố gắng ngăn chặn.

Tôi cũng đã đăng một mẫu ở đây thực hiện điều trên và cũng kết nối các sự kiện chuột của jQuery. Bạn có thể sử dụng nó để thấy rằng sự kiện tap cũng sẽ cháy mouseenter, mousemovemouseleave.


7
@Blender, bạn đã đọc câu hỏi chưa? Tôi đã giải thích lý do tại sao đánh hơi tác nhân người dùng là một lựa chọn tồi.
Joe White

Này Joe, bạn đã tìm thấy giải pháp nào cho việc này chưa?
Ismatjon

Tôi đã tìm kiếm loại câu hỏi này, rất vui vì tôi đã tìm thấy nó!
agpt

Xem thêm câu hỏi này, giải quyết vấn đề vô hiệu hóa di chuột trên bất kỳ thiết bị hỗ trợ cảm ứng nào, không chỉ thiết bị di động: stackoverflow.com/questions/23885255/…
blade

Câu trả lời:


83

Tôi hiểu từ câu hỏi của bạn rằng hiệu ứng di chuột của bạn thay đổi nội dung trang của bạn. Trong trường hợp đó, lời khuyên của tôi là:

  • Thêm hiệu ứng di chuột trên touchstartmouseenter.
  • Di di chuột hiệu ứng trên mouseleave, touchmoveclick.

Ngoài ra, bạn có thể chỉnh sửa trang của mình mà không có thay đổi nội dung.

Lý lịch

Để mô phỏng chuột, các trình duyệt như Webkit di động kích hoạt các sự kiện sau nếu người dùng chạm và thả ngón tay trên màn hình cảm ứng (như iPad) (nguồn: Touch And Mouse trên html5rocks.com):

  1. touchstart
  2. touchmove
  3. touchend
  4. Độ trễ 300ms, trong đó trình duyệt đảm bảo đây là một lần nhấn, không phải nhấn đúp
  5. mouseover
  6. mouseenter
    • Lưu ý : Nếu một mouseover, mouseenterhoặc mousemovesự kiện làm thay đổi nội dung trang, sự kiện sau đây không bao giờ bị sa thải.
  7. mousemove
  8. mousedown
  9. mouseup
  10. click

Có vẻ như không thể chỉ đơn giản là yêu cầu trình duyệt web bỏ qua các sự kiện chuột.

Điều tồi tệ hơn, nếu sự kiện di chuột qua thay đổi nội dung trang, sự kiện nhấp chuột sẽ không bao giờ được kích hoạt, như được giải thích trên Hướng dẫn nội dung web Safari - Sự kiện xử lý , cụ thể là hình 6.4 trong Sự kiện một ngón tay . "Thay đổi nội dung" chính xác là gì, sẽ phụ thuộc vào trình duyệt và phiên bản. Tôi nhận thấy rằng đối với iOS 7.0, thay đổi màu nền không phải (hoặc không còn?) Là thay đổi nội dung.

Giải pháp được giải thích

Tóm lại:

  • Thêm hiệu ứng di chuột trên touchstartmouseenter.
  • Di di chuột hiệu ứng trên mouseleave, touchmoveclick.

Lưu ý rằng không có hành động nào trên touchend !

Điều này rõ ràng hoạt động đối với các sự kiện chuột: mouseentermouseleave(các phiên bản cải tiến một chút của mouseovermouseout) được kích hoạt, đồng thời thêm và xóa di chuột.

Nếu người dùng thực sự có clickliên kết, hiệu ứng di chuột cũng bị loại bỏ. Điều này đảm bảo rằng nó sẽ bị xóa nếu người dùng nhấn nút quay lại trong trình duyệt web.

Điều này cũng hoạt động cho các sự kiện chạm: khi bắt đầu chạm, hiệu ứng di chuột được thêm vào. Nó '' 'không phải' '' bị xóa khi chạm vào. Nó được thêm lần nữa vào mouseentervà vì điều này không gây ra thay đổi nội dung (nó đã được thêm vào), clicksự kiện cũng được kích hoạt và liên kết được theo sau mà không cần người dùng nhấp lại!

Độ trễ 300ms mà trình duyệt có giữa touchstartsự kiện vàclick thực sự được sử dụng tốt vì hiệu ứng di chuột sẽ được hiển thị trong thời gian ngắn này.

Nếu người dùng quyết định hủy nhấp chuột, một cử động của ngón tay sẽ thực hiện như bình thường. Thông thường, đây là một vấn đề vì không có mouseleavesự kiện nào được kích hoạt và hiệu ứng di chuột vẫn còn nguyên. Rất may, điều này có thể dễ dàng được khắc phục bằng cách loại bỏ hiệu ứng di chuột trên touchmove.

Đó là nó!

Lưu ý rằng có thể loại bỏ độ trễ 300ms, ví dụ như sử dụng thư viện FastClick , nhưng điều này nằm ngoài phạm vi cho câu hỏi này.

Các giải pháp thay thế

Tôi đã tìm thấy các vấn đề sau với các lựa chọn thay thế sau:

  • phát hiện trình duyệt: Rất dễ xảy ra lỗi. Giả sử rằng một thiết bị có chuột hoặc cảm ứng, trong khi sự kết hợp của cả hai sẽ ngày càng trở nên phổ biến hơn khi màn hình cảm ứng phát triển tốt hơn.
  • Phát hiện phương tiện CSS: Giải pháp chỉ CSS duy nhất mà tôi biết. Vẫn dễ xảy ra lỗi và vẫn giả định rằng thiết bị có chuột hoặc cảm ứng, trong khi cả hai đều có thể xảy ra.
  • Mô phỏng sự kiện nhấp vào touchend: Điều này sẽ theo liên kết không chính xác, ngay cả khi người dùng chỉ muốn cuộn hoặc thu phóng mà không có ý định thực sự nhấp vào liên kết.
  • Sử dụng một biến để ngăn chặn các sự kiện chuột: Điều này đặt một biến trong touchendđó được sử dụng làm điều kiện if trong các sự kiện chuột tiếp theo để ngăn chặn các thay đổi trạng thái tại thời điểm đó. Biến được đặt lại trong sự kiện nhấp chuột. Xem câu trả lời của Walter Roman trên trang này. Đây là một giải pháp tốt nếu bạn thực sự không muốn có hiệu ứng di chuột trên giao diện cảm ứng. Thật không may, điều này không hoạt động nếu một touchendđược kích hoạt vì một lý do khác và không có sự kiện nhấp chuột nào được kích hoạt (ví dụ: người dùng đã cuộn hoặc thu phóng) và sau đó đang cố gắng theo dõi liên kết bằng chuột (tức là trên thiết bị có cả chuột và giao diện cảm ứng ).

Đọc thêm


1
Câu trả lời rất hay. Tôi đã sử dụng tài năng của bạn để bắt đầu tạo ra giải pháp của riêng mình. Tuy nhiên, đôi khi cần có cảm ứng. (khi một touchmove không chạy - tức là khi người dùng di chuyển ra khỏi tài liệu bản thân ...)
Agamemnus

Great câu trả lời nhưng trong nhiều trường hợp tôi muốn đề nghị sử dụng touchend thay vì của touchstarttrong nhiều trường hợp để tránh những hành động kích hoạt ngay lập tức khi người dùng đang cố gắng để swipe-cuộn lên hoặc xuống một trang. Sẽ vẫn xảy ra nhưng ít có khả năng làm mất tập trung hoặc nhầm lẫn (giả sử đó là thứ vô hại như hiển thị nhãn, không phải thứ mà người dùng cần biết đã xảy ra)
user56reinstatemonica8

19

Làm cách nào để có được các hiệu ứng di chuột khi tôi đang sử dụng chuột nhưng lại tắt chúng khi tôi đang sử dụng màn hình cảm ứng?

Có thể không nghĩ về nó quá nhiều như việc loại bỏ các hiệu ứng di chuột cho màn hình cảm ứng, mà là thêm các hiệu ứng di chuột cho các sự kiện chuột?

Nếu bạn muốn giữ các :hoverhiệu ứng trong CSS của mình, bạn có thể chỉ định các kiểu khác nhau cho các phương tiện khác nhau:

@media screen { /* hover styles here */ } 

@media handheld { /* non-hover styles here */ }

Ngoại trừ điều không may là có rất nhiều thiết bị di động bỏ qua điều này và chỉ sử dụng các quy tắc màn hình. May mắn thay, rất nhiều trình duyệt dành cho thiết bị di động / máy tính bảng mới hơn hỗ trợ một số truy vấn phương tiện lạ hơn:

@media screen and (max-width:800px) { /* non-hover styles here */ }

Vì vậy, ngay cả khi phần "màn hình" hoặc "thiết bị cầm tay" bị bỏ qua thì "chiều rộng tối đa" sẽ giúp bạn. Bạn chỉ có thể cho rằng bất kỳ thứ gì có màn hình nhỏ hơn 800 pixel phải là máy tính bảng hoặc điện thoại và không sử dụng hiệu ứng di chuột. Đối với những người dùng hiếm hoi đang sử dụng chuột trên thiết bị có độ phân giải thấp, họ sẽ không thấy hiệu ứng khi di chuột nhưng nếu không thì trang web của bạn sẽ ổn.

Đọc thêm về truy vấn phương tiện truyền thông? Có rất nhiều bài viết về điều này trực tuyến - đây là một bài: http://www.alistapart.com/articles/return-of-the-mobile-stylesheet

Nếu bạn chuyển các hiệu ứng di chuột ra khỏi CSS của mình và áp dụng chúng với JavaScript thì bạn có thể liên kết cụ thể với các sự kiện chuột và / hoặc một lần nữa, bạn có thể chỉ cần đưa ra một số giả định chỉ dựa trên kích thước màn hình với "sự cố" trong trường hợp xấu nhất là một số người dùng đang sử dụng chuột bỏ lỡ các hiệu ứng khi di chuột.


Tôi muốn thêm hiệu ứng di chuột chỉ cho các sự kiện chuột. Nhưng các sự kiện chạm mô phỏng các sự kiện chuột. Nếu tôi kết nối các sự kiện cảm ứng và gọi preventDefault(), điều đó đôi khi ngăn chặn các sự kiện chuột, nhưng như tôi đã nói trong câu hỏi của mình, nó không đáng tin cậy.
Joe White

6
Đối với truy vấn phương tiện, điều gì sẽ xảy ra khi Windows 8 ra mắt và PC có cả màn hình cảm ứng chuột? Nếu người dùng di chuột bằng chuột, họ sẽ thấy con trỏ chuột và tôi muốn các hiệu ứng di chuột; nếu họ chạm bằng màn hình cảm ứng, tôi không muốn các hiệu ứng di chuột. Nhưng tôi chưa tìm ra cách đáng tin cậy để phát hiện sự khác biệt giữa cảm ứng và chuột.
Joe White

Có lẽ các nhà phát triển trình duyệt sẽ có động lực hơn để làm cho việc phát hiện nhất quán hơn khi họ có số lượng người dùng lớn hơn trên các thiết bị có cảm ứng và chuột. Nhưng bây giờ? Tôi sẽ phỏng đoán dựa trên kích thước màn hình, nhưng có lời khuyên khác trong các câu trả lời khác. Xin lỗi, tôi không thể giúp gì thêm.
nnnnnn

9

Tôi đã viết JS sau cho một dự án gần đây, đó là một trang web dành cho máy tính để bàn / thiết bị di động / máy tính bảng có các hiệu ứng di chuột không xuất hiện khi chạm.

Các mobileNoHoverStatemô-đun bên dưới có một biến preventMouseover(ban đầu khai báo là false), được thiết lập để truekhi người dùng bắn các touchstartsự kiện trên một phần tử, $target.

preventMouseoversau đó được đặt trở lại falsebất cứ khi nàomouseover sự kiện được kích hoạt, điều này cho phép trang web hoạt động như dự kiến ​​nếu người dùng đang sử dụng cả màn hình cảm ứng và chuột của họ.

Chúng tôi biết rằng điều đó mouseoverđang được kích hoạt sau khi touchstartchúng được khai báo theo thứ tự init.

var mobileNoHoverState = function() {

    var hoverClass = 'hover',
        $target = $(".foo"), 
        preventMouseover = false;

    function forTouchstart() {
        preventMouseover = true;
    }

    function forMouseover() {
        if (preventMouseover === false) {
            $(this).addClass(hoverClass);
        } else {
            preventMouseover = false;
        }
    }

    function forMouseout() {
        $(this).removeClass(hoverClass);
    }

    function init() {
        $target.on({
            touchstart  : forTouchstart,
            mouseover   : forMouseover,
            mouseout    : forMouseout
        });                
    }

    return {
        init: init
    };
}();

Mô-đun sau đó được khởi tạo thêm ở dòng:

mobileNoHoverState.init();

"PreventMouseover sau đó được đặt lại thành true bất cứ khi nào kích hoạt sự kiện di chuột qua, cho phép trang web hoạt động như dự định nếu người dùng đang sử dụng cả màn hình cảm ứng và chuột của họ." - Mã của bạn không làm điều đó. Tui bỏ lỡ điều gì vậy?
Redtopia

@Redtopia Cảm ơn bạn đã quan tâm! Tôi đã cập nhật câu trả lời với đoạn mã bị bỏ sót.
Walter Roman

Bạn không cần dấu chấm phẩy sau khi khai báo hàm
nacholibre

@nacholibre sử dụng dấu chấm phẩy đúng đã được đưa ra
Walter La Mã

6

Bản thân tôi thực sự muốn có một cssgiải pháp thuần túy cho vấn đề này, vì việc rắc một giải pháp javascript nặng nề xung quanh tất cả các chế độ xem của tôi dường như là một lựa chọn khó chịu. Cuối cùng đã tìm thấy truy vấn @ media.hover , có thể phát hiện "liệu cơ chế nhập chính có cho phép người dùng di chuột qua các phần tử hay không." Điều này tránh các thiết bị cảm ứng nơi "di chuột" chỉ là một hành động giả lập hơn là khả năng trực tiếp của thiết bị đầu vào.

Ví dụ: nếu tôi có một liên kết:

<a href="/" class="link">Home</a>

Sau đó, tôi có thể tạo kiểu cho nó một cách an toàn chỉ :hoverkhi thiết bị dễ dàng hỗ trợ nó css:

@media (hover: hover) {
  .link:hover { /* hover styles */ }
}

Trong khi hầu hết các trình duyệt hiện đại đều hỗ trợ các truy vấn tính năng tương tác của phương tiện, một số trình duyệt phổ biến như IE và Firefox thì không. Trong trường hợp của tôi, điều này hoạt động tốt, vì tôi chỉ định hỗ trợ Chrome trên máy tính để bàn và Chrome và Safari trên thiết bị di động.


Giải pháp tốt có vẻ hoạt động khi bạn mô phỏng thiết bị trong Chrome devtools. Nhưng nó vẫn không hoạt động cho Chrome Android :-(
Sjeiti

Tôi nghĩ đây là giải pháp thuận tiện và đúng đắn nhất. Hy vọng nó sẽ sớm được thêm vào tiêu chuẩn W3C.
GProst

5

Giải pháp của tôi là thêm lớp css hoạt động khi di chuột vào thẻ HTML và sử dụng nó trên đầu của tất cả các bộ chọn CSS với: di chuột và xóa lớp đó trong sự kiện touchstart đầu tiên.

http://codepen.io/Bnaya/pen/EoJlb

JS:

(function () {
    'use strict';

    if (!('addEventListener' in window)) {
        return;
    }

    var htmlElement = document.querySelector('html');

    function touchStart () {
        document.querySelector('html').classList.remove('hover-active');

        htmlElement.removeEventListener('touchstart', touchStart);
    }

    htmlElement.addEventListener('touchstart', touchStart);
}());

HTML:

<html class="hover-active">

CSS:

.hover-active .mybutton:hover {
    box-shadow: 1px 1px 1px #000;
}

Thay vì nghe một sự kiện chạm, bạn có thể kiểm tra 'ontouchstart' in window. ví dụif ('ontouchstart' in window) document.querySelector('html').classList.remove('hover-active');
Yuval A.

@YuvalA. Lý do tôi chờ đợi sự kiện cảm ứng vì có các thiết bị hỗ trợ con trỏ và cảm ứng, và người dùng đang sử dụng con trỏ, tôi không muốn loại bỏ di chuột. Nó có thể người dùng sẽ sử dụng cảm ứng và sau đó con trỏ nhưng tôi không có nhiều việc phải làm về điều đó
Bnaya

2

Những gì tôi đã làm để giải quyết vấn đề tương tự là phát hiện tính năng (tôi sử dụng một cái gì đó như mã này ), xem liệu onTouchMove có được xác định hay không và nếu có thì tôi thêm lớp css "touchMode" vào nội dung, nếu không thì tôi thêm " desktopMode ”.

Sau đó, mỗi khi một số hiệu ứng kiểu chỉ áp dụng cho thiết bị cảm ứng hoặc chỉ cho máy tính để bàn, quy tắc css được thêm vào trước với lớp thích hợp:

.desktopMode .someClass:hover{ color: red }
.touchMode .mainDiv { width: 100%; margin: 0; /*etc.*/ }

Chỉnh sửa : Tất nhiên, chiến lược này sẽ thêm một vài ký tự bổ sung vào css của bạn, vì vậy, nếu bạn lo lắng về kích thước css, bạn có thể tìm kiếm mã xác định touchMode và desktopMode và đưa chúng vào các tệp khác nhau, vì vậy bạn có thể phân phát css được tối ưu hóa cho từng thiết bị kiểu; hoặc bạn có thể thay đổi tên lớp thành tên ngắn hơn nhiều trước khi chuyển sang sản phẩm.


2

Đúng vậy, tôi đã gặp sự cố tương tự nhưng đã tìm cách khắc phục nó bằng các truy vấn phương tiện và CSS đơn giản. Tôi chắc chắn rằng tôi đang vi phạm một số quy tắc ở đây, nhưng nó có hiệu quả với tôi.

Về cơ bản, tôi phải sử dụng một ứng dụng lớn do ai đó tạo ra và làm cho nó đáp ứng. Họ đã sử dụng jQueryUI và yêu cầu tôi không can thiệp vào bất kỳ jQuery nào của họ, vì vậy tôi bị hạn chế sử dụng CSS một mình.

Khi tôi nhấn một trong các nút của chúng ở chế độ màn hình cảm ứng, hiệu ứng di chuột sẽ phát ra trong một giây trước khi hành động của nút có hiệu lực. Đây là cách tôi đã sửa nó.

@media only screen and (max-width:1024px) {

       #buttonOne{
            height: 44px;
        }


        #buttonOne:hover{
            display:none;
        }
}   

2

Trong dự án của tôi, chúng tôi đã giải quyết vấn đề này bằng cách sử dụng https://www.npmjs.com/package/postcss-hover-prefixhttps://modernizr.com/ Đầu tiên, chúng tôi xử lý các tệp css đầu ra với postcss-hover-prefix. Nó bổ sung .no-touchcho tất cả các hoverquy tắc css .

const fs = require("fs");
const postcss = require("postcss");
const hoverPrfx = require("postcss-hover-prefix");

var css = fs.readFileSync(cssFileName, "utf8").toString();
postcss()
   .use(hoverPrfx("no-touch"))
   .process(css)
   .then((result) => {
      fs.writeFileSync(cssFileName, result);
   });

css

a.text-primary:hover {
  color: #62686d;
}

trở thành

.no-touch a.text-primary:hover {
  color: #62686d;
}

Khi chạy Modernizrtự động thêm các lớp css để htmlgắn thẻ như thế này

<html class="wpfe-full-height js flexbox flexboxlegacy canvas canvastext webgl 
  no-touch 
  geolocation postmessage websqldatabase indexeddb hashchange
  history draganddrop websockets rgba hsla multiplebgs backgroundsize borderimage
  borderradius boxshadow textshadow opacity cssanimations csscolumns cssgradients
  cssreflections csstransforms csstransforms3d csstransitions fontface
  generatedcontent video audio localstorage sessionstorage webworkers
  applicationcache svg inlinesvg smil svgclippaths websocketsbinary">

Quá trình xử lý sau css plus Modernizr như vậy sẽ tắt di chuột cho các thiết bị cảm ứng và bật cho những thiết bị khác. Trên thực tế, cách tiếp cận này được lấy cảm hứng từ Bootstrap 4, cách họ giải quyết vấn đề tương tự: https://v4-alpha.getbootstrap.com/getting-started/b browser-devices/#sticky-hoverfocus-on-mobile


1

Bạn có thể kích hoạt mouseLeavesự kiện bất cứ khi nào bạn chạm vào một phần tử trên màn hình cảm ứng. Đây là một giải pháp cho tất cả <a>các thẻ:

function removeHover() {
    var anchors = document.getElementsByTagName('a');
    for(i=0; i<anchors.length; i++) {
        anchors[i].addEventListener('touchstart', function(e){
            $('a').mouseleave();
        }, false);
    }
}

JSHint nói "không tạo các hàm trong vòng lặp".
NetOperator Wibby 17/02/16

Đó là một vụ hack. Nó KHÔNG phải là một mã có thể tái sử dụng mà có thể được coi là một phương pháp hay. @NetOperatorWibby
biết

Chà, nó không thực sự hữu ích khi đăng mã không thể được coi là phương pháp hay. Điều đó giống như đặt Band-Aid vào vết thương do dao đâm.
NetOperator Wibby 20/02/16

1

Iv'd đã tìm thấy 2 giải pháp cho vấn đề, điều này ngụ ý rằng bạn phát hiện cảm ứng bằng modernizr hoặc thứ gì đó khác và đặt lớp cảm ứng trên phần tử html.

Điều này là tốt nhưng không được hỗ trợ rất tốt:

html.touch *:hover {
    all:unset!important;
}

Nhưng điều này có một hỗ trợ rất tốt :

html.touch *:hover {
    pointer-events: none !important;
}

Đối với tôi, nó hoạt động hoàn hảo, nó làm cho tất cả các hiệu ứng di chuột giống như khi bạn chạm vào một nút, nó sẽ sáng lên nhưng không gặp lỗi như hiệu ứng di chuột ban đầu cho các sự kiện chuột.

Phát hiện cảm ứng từ các thiết bị không cảm ứng, tôi nghĩ modernizr đã thực hiện công việc tốt nhất:

https://github.com/Modernizr/Modernizr/blob/master/feature-detects/touchevents.js

BIÊN TẬP

Tôi đã tìm thấy một giải pháp tốt hơn và đơn giản hơn cho vấn đề này

Cách xác định xem máy khách có phải là thiết bị cảm ứng hay không


0

Có thể hữu ích khi xem CSS của bạn, vì nó có vẻ là một vấn đề khá kỳ lạ. Nhưng dù sao đi nữa, nếu nó đang xảy ra và mọi thứ khác đều tốt, bạn có thể thử chuyển hiệu ứng di chuột sang javascript (bạn cũng có thể sử dụng jquery). Đơn giản, liên kết với sự kiện di chuột qua hoặc tốt hơn là vẫn di chuột và chiếu sáng phần tử của bạn khi sự kiện kích hoạt.

Hãy xem ví dụ cuối cùng tại đây: http://api.jquery.com/mouseover/ , bạn có thể sử dụng thứ gì đó tương tự để ghi nhật ký khi sự kiện xảy ra và lấy nó từ đó!


Không có gì đặc biệt về CSS; xem bản chỉnh sửa của tôi. Và tôi đã thử mouseenter; không có con xúc xắc. Nhấn sẽ di chuyển "con trỏ chuột vô hình", do đó, nó sẽ kích hoạt mouseentermousemove(và mouseleavekhi bạn nhấn vào một nơi khác).
Joe White

0

Nếu bạn hài lòng khi sử dụng JavaScript thì bạn có thể sử dụng Modernizr trong trang của mình. Khi trang tải, trình duyệt màn hình không cảm ứng sẽ có lớp '.no-touch' được thêm vào thẻ html, nhưng đối với trình duyệt màn hình cảm ứng, thẻ html sẽ có thêm lớp '.touch' vào thẻ html .

Sau đó, nó chỉ đơn giản là một trường hợp kiểm tra xem liệu thẻ html có lớp không liên lạc hay không trước khi quyết định thêm trình nghe trung tâm và mouseleave của bạn.

if($('html').hasClass('no-touch')){
    $('.box').on("mouseenter", function(event){
            $(this).css('background-color','#0000ff')
    });
    $('.box').on("mouseleave", function(event){
            $(this).css('background-color','')
    });
}

Đối với thiết bị màn hình cảm ứng, các sự kiện sẽ không có người nghe nên bạn sẽ không nhận được hiệu ứng di chuột khi chạm vào.


Khi nó có thể được thực hiện với việc sử dụng css dont javascript (jquery) một sự lãng phí của sức mạnh máy tính
Simon Dragsbæk

1
Đơn giản hơn, trong CSS của bạn, bạn có thể xác định các quy tắc riêng biệt cho .touch.no-touch. Để viết lại câu trả lời của bạn trong CSS cùng với Modernizer html.no-touch .box:hover {background-color: "#0000ff"}và không xác định bất cứ điều gì cho html.touch .box:hovernên thực hiện một mẹo nhỏ, vì OP chỉ cố gắng tránh di động :hover.
Walter Roman

0

Trong một dự án mà tôi đã thực hiện gần đây, tôi đã giải quyết vấn đề này bằng tính năng sự kiện được ủy quyền của jQuery. Nó tìm kiếm các phần tử nhất định bằng cách sử dụng công cụ chọn jQuery và thêm / xóa một lớp CSS vào các phần tử đó khi chuột qua phần tử đó. Nó có vẻ hoạt động tốt theo những gì tôi đã có thể kiểm tra, bao gồm IE10 trên một máy tính xách tay có khả năng cảm ứng chạy Windows 8.

$(document).ready(
    function()
    {
        // insert your own selector here: maybe '.hoverable'?
        var selector = 'button, .hotspot';

        $('body')
            .on('mouseover', selector, function(){ $(this).addClass('mouseover');    })
            .on('mouseout',  selector, function(){ $(this).removeClass('mouseover'); })
            .on('click',     selector, function(){ $(this).removeClass('mouseover'); });
    }
);

chỉnh sửa: tất nhiên, giải pháp này yêu cầu bạn thay đổi CSS của mình để loại bỏ các bộ chọn ": hover" và xem xét trước phần tử nào bạn muốn "có thể di chuyển".

Tuy nhiên, nếu bạn có rất nhiều phần tử trên trang của mình (chẳng hạn như vài nghìn phần tử), nó có thể hơi chậm vì giải pháp này bắt các sự kiện có ba loại trên tất cả các phần tử trong trang và sau đó sẽ hoạt động nếu bộ chọn khớp. Tôi đặt tên lớp CSS là "mouseover" thay vì "hover", vì tôi không muốn bất kỳ trình đọc CSS nào đọc ": hover" nơi tôi đã viết ".hover".


0

Đây là giải pháp của tôi: http://jsfiddle.net/agamemnus/g56aw709/-- mã bên dưới.

Tất cả những gì người ta cần làm là chuyển đổi ": hover" thành ".hover" ... thế là xong! Sự khác biệt lớn giữa phần này và phần còn lại là điều này cũng sẽ hoạt động trên các bộ chọn phần tử không phải số ít chẳng hạn như .my_class > *:hover {.

handle_css_hover_effects ()

function handle_css_hover_effects (init) {
 var init = init || {}
 var handle_touch_events = init.handle_touch_events || true
 var handle_mouse_events = init.handle_mouse_events || true
 var hover_class         = init.hover_class         || "hover"
 var delay_preferences   = init.delay_preferences   || {touch: {add: 500, remove: 500}}
 function default_handler (curobj, input_type, op) {
  var hovered_element_selector = "*" + ((op == "add") ? ":" : ("." + hover_class))
  var hovered_elements = Array.prototype.slice.call(document.body.querySelectorAll(hovered_element_selector))
  var modified_list = []
  while (true) {
   if ((curobj == null) || (curobj == document.documentElement)) break
   if (hovered_elements.indexOf(curobj) != -1) modified_list.push (curobj)
   curobj = curobj.parentNode
  }
  function do_hover_change () {modified_list.forEach (function (curobj) {curobj.classList[op](hover_class)})}
  if ((!delay_preferences[input_type]) || (!delay_preferences[input_type][op])) {
   do_hover_change ()
  } else {
   setTimeout (do_hover_change, delay_preferences[input_type][op])
  }
 }

 if (handle_mouse_events) {
  document.body.addEventListener ('mouseover' , function (evt) {var curobj = evt.target; default_handler (curobj, "mouse", "add")})
  document.body.addEventListener ('mouseout'  , function (evt) {var curobj = evt.target; default_handler (curobj, "mouse", "remove")})
  document.body.addEventListener ('click'     , function (evt) {var curobj = evt.target; default_handler (curobj, "mouse", "remove")})
 }

 if (handle_touch_events) {
  document.body.addEventListener ('touchstart', function (evt) {var curobj = evt.target; default_handler (curobj, "touch", "add")})
  document.body.addEventListener ('touchend'  , function (evt) {var curobj = evt.target; default_handler (curobj, "touch", "remove")})
  document.body.addEventListener ('touchmove',  function (evt) {
   var curobj = evt.target
   var hovered_elements = Array.prototype.slice.call(document.body.querySelectorAll("*:hover"))
   var lastobj = null
   evt = evt.changedTouches[0]
   var elements_at_point = get_elements_at_point (evt.pageX, evt.pageY)
   // Get the last element that isn't at the current point but is still hovered over, and remove only its hover attribute.
   while (true) {
    if ((curobj == null) || (curobj == document.documentElement)) break
    if ((hovered_elements.indexOf(curobj) != -1) && (elements_at_point.indexOf(curobj) == -1)) lastobj = curobj
    curobj = curobj.parentNode
   }
   if (lastobj == null) return
   if ((!delay_preferences.touch) || (!delay_preferences.touch.remove)) {
    lastobj.classList.remove(hover_class)
   } else {
    setTimeout (function () {lastobj.classList.remove(hover_class)}, delay_preferences.touch.remove)
   }

   function get_elements_at_point (x, y) {
    var el_list = [], pe_list = []
    while (true) {
     var curobj = document.elementFromPoint(x, y)
     if ((curobj == null) || (curobj == document.documentElement)) break
     el_list.push (curobj); pe_list.push (curobj.style.pointerEvents)
     curobj.style.pointerEvents = "none"
    }
    el_list.forEach (function (current_element, i) {current_element.style.pointerEvents = pe_list[i]})
    return el_list
   }
  })
 }
}

0

Bao gồm Modernizr trên trang của bạn và đặt các trạng thái di chuột của bạn như sau:

html.no-touchevents .box:hover {
    background: blue;
}

0

Xin chào người đến từ tương lai, bạn có thể muốn sử dụng truy vấn pointervà / hoặc hoverphương tiện. Các handheldtruy vấn phương tiện truyền thông đã phản đối.

/* device is using a mouse or similar */
@media (pointer: fine) {
  a:hover {
    background: red;
  }
}

-1

Hãy thử giải pháp jquery 2019 dễ dàng này, mặc dù nó đã được một thời gian;

  1. thêm plugin này vào đầu:

    src="https://code.jquery.com/ui/1.12.0/jquery-ui.min.js"

  2. thêm cái này vào js:

    $("*").on("touchend", function(e) { $(this).focus(); }); //applies to all elements

  3. một số biến thể được đề xuất cho điều này là:

    $(":input, :checkbox,").on("touchend", function(e) {(this).focus);}); //specify elements
    
    $("*").on("click, touchend", function(e) { $(this).focus(); });  //include click event`
    
    css: body { cursor: pointer; } //touch anywhere to end a focus`

Ghi chú

  • đặt plugin trước bootstrap.js, nếu có, để tránh ảnh hưởng đến chú giải công cụ
  • 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.

Người giới thiệu:

https://code.jquery.com/ui/

https://api.jquery.com/category/selectors/jquery-selector-extensions/

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.