Thêm điểm nhấn vào trang web của bạn

Màn hình cảm ứng ngày càng xuất hiện trên nhiều thiết bị, từ điện thoại cho đến màn hình máy tính. Ứng dụng của bạn phải phản hồi thao tác chạm của họ theo cách trực quan và đẹp mắt.

Màn hình cảm ứng ngày càng xuất hiện trên nhiều thiết bị, từ điện thoại đến màn hình máy tính. Khi người dùng chọn tương tác với giao diện người dùng, ứng dụng của bạn phải phản hồi thao tác chạm của họ theo cách trực quan.

Phản hồi trạng thái phần tử

Bạn đã bao giờ chạm hoặc nhấp vào một phần tử trên trang web và đặt câu hỏi liệu trang web có thực sự phát hiện thấy phần tử đó hay không?

Chỉ cần thay đổi màu của một thành phần khi người dùng chạm hoặc tương tác với các phần trên giao diện người dùng, bạn đã có thể đảm bảo rằng trang web của mình đang hoạt động. Điều này không chỉ giúp giảm bớt sự thất vọng mà còn mang lại cảm giác nhanh chóng và linh hoạt.

Các phần tử DOM có thể kế thừa bất kỳ trạng thái nào sau đây: mặc định, tiêu điểm, di chuột và đang hoạt động. Để thay đổi giao diện người dùng cho từng trạng thái này, chúng ta cần áp dụng kiểu cho các lớp giả sau đây là :hover, :focus:active như minh hoạ bên dưới:

.btn {
  background-color: #4285f4;
}

.btn:hover {
  background-color: #296cdb;
}

.btn:focus {
  background-color: #0f52c1;

  /* The outline parameter suppresses the border
  color / outline when focused */
  outline: 0;
}

.btn:active {
  background-color: #0039a8;
}

Thử nào

Hình ảnh minh hoạ các màu khác nhau cho trạng thái của nút

Trên hầu hết các trình duyệt di động, trạng thái di chuột và/hoặc tập trung sẽ áp dụng cho một phần tử sau khi phần tử đó được nhấn vào.

Hãy cân nhắc kỹ những kiểu bạn đặt và giao diện của các kiểu đó đối với người dùng sau khi họ hoàn tất thao tác chạm.

Chặn các kiểu trình duyệt mặc định

Sau khi thêm các kiểu cho các trạng thái khác nhau, bạn sẽ nhận thấy hầu hết các trình duyệt đều triển khai các kiểu riêng để phản hồi thao tác chạm của người dùng. Điều này phần lớn là do khi thiết bị di động ra mắt lần đầu tiên, một số trang web không định kiểu cho trạng thái :active. Do đó, nhiều trình duyệt đã thêm màu hoặc kiểu làm nổi bật để đưa ra phản hồi cho người dùng.

Hầu hết các trình duyệt đều sử dụng thuộc tính CSS outline để hiển thị một vòng tròn xung quanh một phần tử khi phần tử đó được lấy tiêu điểm. Bạn có thể ngăn chặn lỗi này bằng:

.btn:focus {
    outline: 0;

    /* Add replacement focus styling here (i.e. border) */
}

Safari và Chrome thêm màu nhấn khi nhấn. Bạn có thể ngăn việc này bằng thuộc tính CSS -webkit-tap-highlight-color:

/* Webkit / Chrome Specific CSS to remove tap
highlight color */
.btn {
  -webkit-tap-highlight-color: transparent;
}

Thử nào

Internet Explorer trên Windows Phone cũng có hành vi tương tự, nhưng bị chặn thông qua thẻ meta:

<meta name="msapplication-tap-highlight" content="no">

Firefox có hai tác dụng phụ cần xử lý.

Bạn có thể xoá lớp giả lập -moz-focus-inner (thêm đường viền trên các phần tử có thể chạm) bằng cách đặt border: 0.

Nếu đang sử dụng phần tử <button> trên Firefox, bạn sẽ thấy một hiệu ứng chuyển màu (gradient) được áp dụng. Bạn có thể xoá phần tử này bằng cách đặt background-image: none.

/* Firefox Specific CSS to remove button
differences and focus ring */
.btn {
  background-image: none;
}

.btn::-moz-focus-inner {
  border: 0;
}

Thử nào

Tắt tính năng chọn của người dùng

Khi tạo giao diện người dùng, có thể có những trường hợp bạn muốn người dùng tương tác với các phần tử của bạn nhưng bạn muốn ngăn hành vi mặc định là chọn văn bản khi nhấn và giữ hoặc kéo chuột qua giao diện người dùng.

Bạn có thể thực hiện việc này bằng thuộc tính CSS user-select, nhưng hãy lưu ý rằng việc làm này trên nội dung có thể khiến người dùng vô cùng tức giận nếu họ muốn chọn văn bản trong phần tử. Vì vậy, hãy nhớ sử dụng tính năng này một cách thận trọng và tiết kiệm.

/* Example: Disable selecting text on a paragraph element: */
p.disable-text-selection {
  user-select: none;
}

Triển khai cử chỉ tuỳ chỉnh

Nếu bạn có ý tưởng về các cử chỉ và lượt tương tác tuỳ chỉnh cho trang web của mình, hãy lưu ý hai chủ đề sau:

  1. Cách hỗ trợ tất cả trình duyệt.
  2. Cách duy trì tốc độ khung hình cao.

Trong bài viết này, chúng ta sẽ xem xét chính xác các chủ đề này, bao gồm cả API mà chúng ta cần hỗ trợ để tiếp cận tất cả trình duyệt, sau đó sẽ đề cập đến cách sử dụng các sự kiện này một cách hiệu quả.

Tuỳ thuộc vào việc bạn muốn cử chỉ làm gì, có thể bạn muốn người dùng tương tác với một phần tử tại một thời điểm hoặc bạn muốn họ có thể tương tác với nhiều phần tử cùng một lúc.

Chúng ta sẽ xem xét hai ví dụ trong bài viết này, cả hai đều minh hoạ việc hỗ trợ tất cả trình duyệt và cách duy trì tốc độ khung hình cao.

Ảnh GIF mẫu về thao tác chạm vào tài liệu

Ví dụ đầu tiên sẽ cho phép người dùng tương tác với một phần tử. Trong trường hợp này, bạn có thể muốn tất cả sự kiện chạm được cung cấp cho một phần tử đó, miễn là cử chỉ ban đầu bắt đầu trên chính phần tử đó. Ví dụ: việc di chuyển ngón tay ra khỏi phần tử có thể vuốt vẫn có thể điều khiển phần tử đó.

Điều này rất hữu ích vì mang lại sự linh hoạt cho người dùng, nhưng đồng thời cũng áp dụng một hạn chế về cách người dùng có thể tương tác với giao diện người dùng của bạn.

Ảnh GIF mẫu về thao tác chạm vào phần tử

Tuy nhiên, nếu bạn muốn người dùng tương tác với nhiều phần tử cùng một lúc (sử dụng tính năng cảm ứng đa điểm), bạn nên hạn chế thao tác chạm vào một phần tử cụ thể.

Cách này linh hoạt hơn cho người dùng, nhưng làm phức tạp logic thao tác với giao diện người dùng và ít linh hoạt hơn trước lỗi của người dùng.

Thêm trình nghe sự kiện

Trong Chrome (phiên bản 55 trở lên), Internet Explorer và Edge, bạn nên sử dụng PointerEvents để triển khai các cử chỉ tuỳ chỉnh.

Trong các trình duyệt khác, TouchEventsMouseEvents là phương pháp chính xác.

Tính năng tuyệt vời của PointerEvents là hợp nhất nhiều kiểu phương thức nhập, bao gồm cả sự kiện bằng chuột, chạm và bút, thành một tập hợp lệnh gọi lại. Các sự kiện cần theo dõi là pointerdown, pointermove, pointeruppointercancel.

Các đối tượng tương đương trong các trình duyệt khác là touchstart, touchmove, touchendtouchcancel cho các sự kiện chạm và nếu bạn muốn triển khai cùng một cử chỉ cho hoạt động nhập bằng chuột, bạn cần triển khai mousedown, mousemovemouseup.

Nếu bạn có thắc mắc về những sự kiện cần sử dụng, hãy xem bảng Sự kiện chạm, chuột và con trỏ.

Để sử dụng các sự kiện này, bạn cần gọi phương thức addEventListener() trên một phần tử DOM, cùng với tên của một sự kiện, một hàm gọi lại và một boolean. Giá trị boolean xác định xem bạn nên phát hiện sự kiện trước hay sau khi các phần tử khác có cơ hội phát hiện và diễn giải sự kiện. (true có nghĩa là bạn muốn sự kiện diễn ra trước các phần tử khác.)

Dưới đây là ví dụ về cách lắng nghe để bắt đầu một tương tác.

// Check if pointer events are supported.
if (window.PointerEvent) {
  // Add Pointer Event Listener
  swipeFrontElement.addEventListener('pointerdown', this.handleGestureStart, true);
  swipeFrontElement.addEventListener('pointermove', this.handleGestureMove, true);
  swipeFrontElement.addEventListener('pointerup', this.handleGestureEnd, true);
  swipeFrontElement.addEventListener('pointercancel', this.handleGestureEnd, true);
} else {
  // Add Touch Listener
  swipeFrontElement.addEventListener('touchstart', this.handleGestureStart, true);
  swipeFrontElement.addEventListener('touchmove', this.handleGestureMove, true);
  swipeFrontElement.addEventListener('touchend', this.handleGestureEnd, true);
  swipeFrontElement.addEventListener('touchcancel', this.handleGestureEnd, true);

  // Add Mouse Listener
  swipeFrontElement.addEventListener('mousedown', this.handleGestureStart, true);
}

Thử nào

Xử lý lượt tương tác với một phần tử

Trong đoạn mã ngắn ở trên, chúng ta chỉ thêm trình nghe sự kiện bắt đầu cho các sự kiện chuột. Lý do là các sự kiện chuột sẽ chỉ kích hoạt khi con trỏ di chuột qua phần tử mà trình nghe sự kiện được thêm vào.

TouchEvents sẽ theo dõi một cử chỉ sau khi thao tác đó bắt đầu, bất kể vị trí chạm xảy ra và PointerEvents sẽ theo dõi các sự kiện bất kể vị trí chạm xảy ra sau khi chúng ta gọi setPointerCapture trên phần tử DOM.

Đối với các sự kiện di chuyển và kết thúc chuột, chúng ta thêm trình nghe sự kiện trong phương thức bắt đầu cử chỉ và thêm trình nghe vào tài liệu, nghĩa là trình nghe có thể theo dõi con trỏ cho đến khi cử chỉ hoàn tất.

Các bước triển khai như sau:

  1. Thêm tất cả trình nghe TouchEvent và PointerEvent. Đối với MouseEvents, hãy thêm chỉ sự kiện bắt đầu.
  2. Bên trong lệnh gọi lại bắt đầu cử chỉ, hãy liên kết các sự kiện di chuyển chuột và kết thúc với tài liệu. Bằng cách này, tất cả sự kiện chuột đều được nhận, bất kể sự kiện có xảy ra trên phần tử ban đầu hay không. Đối với PointerEvents, chúng tôi cần gọi setPointerCapture() trên phần tử ban đầu để nhận tất cả các sự kiện tiếp theo. Sau đó, hãy xử lý phần bắt đầu của cử chỉ.
  3. Xử lý các sự kiện di chuyển.
  4. Trên sự kiện kết thúc, hãy xoá trình nghe di chuyển chuột và kết thúc khỏi tài liệu rồi kết thúc cử chỉ.

Dưới đây là đoạn mã của phương thức handleGestureStart(). Phương thức này sẽ thêm các sự kiện di chuyển và kết thúc vào tài liệu:

// Handle the start of gestures
this.handleGestureStart = function(evt) {
  evt.preventDefault();

  if(evt.touches && evt.touches.length > 1) {
    return;
  }

  // Add the move and end listeners
  if (window.PointerEvent) {
    evt.target.setPointerCapture(evt.pointerId);
  } else {
    // Add Mouse Listeners
    document.addEventListener('mousemove', this.handleGestureMove, true);
    document.addEventListener('mouseup', this.handleGestureEnd, true);
  }

  initialTouchPos = getGesturePointFromEvent(evt);

  swipeFrontElement.style.transition = 'initial';
}.bind(this);

Thử nào

Lệnh gọi lại kết thúc mà chúng ta thêm là handleGestureEnd(). Lệnh này sẽ xoá trình nghe sự kiện di chuyển và kết thúc khỏi tài liệu, đồng thời phát hành tính năng chụp con trỏ khi cử chỉ kết thúc như sau:

// Handle end gestures
this.handleGestureEnd = function(evt) {
  evt.preventDefault();

  if (evt.touches && evt.touches.length > 0) {
    return;
  }

  rafPending = false;

  // Remove Event Listeners
  if (window.PointerEvent) {
    evt.target.releasePointerCapture(evt.pointerId);
  } else {
    // Remove Mouse Listeners
    document.removeEventListener('mousemove', this.handleGestureMove, true);
    document.removeEventListener('mouseup', this.handleGestureEnd, true);
  }

  updateSwipeRestPosition();

  initialTouchPos = null;
}.bind(this);

Thử nào

Bằng cách làm theo mẫu này để thêm sự kiện di chuyển vào tài liệu, nếu người dùng bắt đầu tương tác với một phần tử và di chuyển cử chỉ của họ ra khỏi phần tử đó, chúng ta sẽ tiếp tục nhận được các chuyển động của chuột bất kể vị trí của chúng trên trang, vì các sự kiện đang được nhận từ tài liệu.

Sơ đồ này cho thấy những gì các sự kiện chạm đang thực hiện khi chúng ta thêm sự kiện di chuyển và kết thúc vào tài liệu sau khi một cử chỉ bắt đầu.

Minh hoạ các sự kiện chạm liên kết với tài liệu trong
&quot;Touchstart&quot;

Phản hồi thao tác chạm một cách hiệu quả

Giờ đây, khi đã xử lý xong sự kiện bắt đầu và kết thúc, chúng ta có thể thực sự phản hồi các sự kiện chạm.

Đối với bất kỳ sự kiện bắt đầu và di chuyển nào, bạn có thể dễ dàng trích xuất xy từ một sự kiện.

Ví dụ sau đây sẽ kiểm tra xem sự kiện này có đến từ TouchEvent hay không bằng cách kiểm tra xem targetTouches có tồn tại hay không. Nếu có, thì lớp này sẽ trích xuất clientXclientY từ lần chạm đầu tiên. Nếu sự kiện là PointerEvent hoặc MouseEvent, thì sự kiện đó sẽ trích xuất clientXclientY trực tiếp từ chính sự kiện đó.

function getGesturePointFromEvent(evt) {
    var point = {};

    if (evt.targetTouches) {
      // Prefer Touch Events
      point.x = evt.targetTouches[0].clientX;
      point.y = evt.targetTouches[0].clientY;
    } else {
      // Either Mouse event or Pointer Event
      point.x = evt.clientX;
      point.y = evt.clientY;
    }

    return point;
  }

Thử nào

TouchEvent có 3 danh sách chứa dữ liệu chạm:

  • touches: danh sách tất cả các thao tác chạm hiện tại trên màn hình, bất kể các thao tác đó đang ở phần tử DOM nào.
  • targetTouches: danh sách các lượt chạm hiện đang nằm trên phần tử DOM mà sự kiện được liên kết.
  • changedTouches: danh sách các lần chạm đã thay đổi dẫn đến sự kiện được kích hoạt.

Trong hầu hết các trường hợp, targetTouches cung cấp cho bạn mọi thứ bạn cần và muốn. (Để biết thêm thông tin về các danh sách này, hãy xem Danh sách cảm ứng).

Sử dụng requestAnimationFrame

Vì các lệnh gọi lại sự kiện được kích hoạt trên luồng chính, nên chúng ta muốn chạy càng ít mã càng tốt trong lệnh gọi lại cho sự kiện, duy trì tốc độ khung hình cao và ngăn hiện tượng giật.

Khi sử dụng requestAnimationFrame(), chúng ta có cơ hội cập nhật giao diện người dùng ngay trước khi trình duyệt dự định vẽ một khung và sẽ giúp chúng ta di chuyển một số công việc ra khỏi lệnh gọi lại sự kiện.

Nếu chưa quen với requestAnimationFrame(), bạn có thể tìm hiểu thêm tại đây.

Cách triển khai thông thường là lưu toạ độ xy từ sự kiện bắt đầu và di chuyển, đồng thời yêu cầu một khung ảnh động bên trong lệnh gọi lại sự kiện di chuyển.

Trong bản minh hoạ, chúng ta lưu trữ vị trí chạm ban đầu trong handleGestureStart() (tìm initialTouchPos):

// Handle the start of gestures
this.handleGestureStart = function(evt) {
  evt.preventDefault();

  if (evt.touches && evt.touches.length > 1) {
    return;
  }

  // Add the move and end listeners
  if (window.PointerEvent) {
    evt.target.setPointerCapture(evt.pointerId);
  } else {
    // Add Mouse Listeners
    document.addEventListener('mousemove', this.handleGestureMove, true);
    document.addEventListener('mouseup', this.handleGestureEnd, true);
  }

  initialTouchPos = getGesturePointFromEvent(evt);

  swipeFrontElement.style.transition = 'initial';
}.bind(this);

Phương thức handleGestureMove() lưu trữ vị trí của sự kiện trước khi yêu cầu một khung ảnh động nếu cần, truyền hàm onAnimFrame() làm lệnh gọi lại:

this.handleGestureMove = function (evt) {
  evt.preventDefault();

  if (!initialTouchPos) {
    return;
  }

  lastTouchPos = getGesturePointFromEvent(evt);

  if (rafPending) {
    return;
  }

  rafPending = true;

  window.requestAnimFrame(onAnimFrame);
}.bind(this);

Giá trị onAnimFrame là một hàm mà khi được gọi, sẽ thay đổi giao diện người dùng để di chuyển hàm đó. Bằng cách truyền hàm này vào requestAnimationFrame(), chúng ta sẽ yêu cầu trình duyệt gọi hàm này ngay trước khi cập nhật trang (tức là vẽ mọi thay đổi đối với trang).

Trong lệnh gọi lại handleGestureMove(), ban đầu chúng ta kiểm tra xem rafPending có phải là sai hay không, cho biết liệu requestAnimationFrame() có gọi onAnimFrame() kể từ sự kiện di chuyển gần đây nhất hay không. Điều này có nghĩa là chúng ta chỉ có một requestAnimationFrame() đang chờ chạy tại một thời điểm bất kỳ.

Khi lệnh gọi lại onAnimFrame() được thực thi, chúng ta đặt phép biến đổi trên mọi phần tử mà chúng ta muốn di chuyển trước khi cập nhật rafPending thành false, cho phép sự kiện chạm tiếp theo yêu cầu một khung ảnh động mới.

function onAnimFrame() {
  if (!rafPending) {
    return;
  }

  var differenceInX = initialTouchPos.x - lastTouchPos.x;
  var newXTransform = (currentXPosition - differenceInX)+'px';
  var transformStyle = 'translateX('+newXTransform+')';

  swipeFrontElement.style.webkitTransform = transformStyle;
  swipeFrontElement.style.MozTransform = transformStyle;
  swipeFrontElement.style.msTransform = transformStyle;
  swipeFrontElement.style.transform = transformStyle;

  rafPending = false;
}

Điều khiển cử chỉ bằng thao tác chạm

Thuộc tính CSS touch-action cho phép bạn kiểm soát hành vi chạm mặc định của một phần tử. Trong các ví dụ, chúng ta sử dụng touch-action: none để ngăn trình duyệt thực hiện bất kỳ thao tác nào khi người dùng chạm vào, cho phép chúng ta chặn tất cả sự kiện chạm.

/* Pass all touches to javascript: */
button.custom-touch-logic {
  touch-action: none;
}

Việc sử dụng touch-action: none có phần giống như một lựa chọn hạt nhân vì nó ngăn tất cả các hành vi mặc định của trình duyệt. Trong nhiều trường hợp, một trong các tuỳ chọn bên dưới sẽ là giải pháp tốt hơn.

touch-action cho phép bạn tắt các cử chỉ do trình duyệt triển khai. Ví dụ: IE10 trở lên hỗ trợ cử chỉ nhấn đúp để thu phóng. Bằng cách đặt touch-actionmanipulation, bạn sẽ ngăn chặn hành vi nhấn đúp mặc định.

Điều này cho phép bạn tự triển khai cử chỉ nhấn đúp.

Dưới đây là danh sách các giá trị touch-action thường dùng:

Tham số thao tác chạm
touch-action: none Trình duyệt sẽ không xử lý bất kỳ lượt tương tác nào bằng thao tác chạm.
touch-action: pinch-zoom Tắt tất cả các hoạt động tương tác với trình duyệt như "touch-action: none", ngoại trừ "pinch-zoom" (thu phóng bằng cách chụm hai ngón tay) vẫn do trình duyệt xử lý.
touch-action: pan-y pinch-zoom Xử lý thao tác cuộn theo chiều ngang trong JavaScript mà không tắt tính năng cuộn theo chiều dọc hoặc thu phóng bằng cách chụm hai ngón tay (ví dụ: băng chuyền hình ảnh).
touch-action: manipulation Tắt cử chỉ nhấn đúp để tránh mọi độ trễ nhấp của trình duyệt. Chuyển thao tác cuộn và chụm để thu phóng lên trình duyệt.

Hỗ trợ các phiên bản IE cũ

Nếu muốn hỗ trợ IE10, bạn cần xử lý các phiên bản có tiền tố từ nhà cung cấp của PointerEvents.

Để kiểm tra khả năng hỗ trợ PointerEvents, bạn thường tìm window.PointerEvent, nhưng trong IE10, bạn sẽ tìm window.navigator.msPointerEnabled.

Tên sự kiện có tiền tố của nhà cung cấp là: 'MSPointerDown', 'MSPointerUp''MSPointerMove'.

Ví dụ bên dưới cho bạn biết cách kiểm tra tính năng hỗ trợ và chuyển đổi tên sự kiện.

var pointerDownName = 'pointerdown';
var pointerUpName = 'pointerup';
var pointerMoveName = 'pointermove';

if (window.navigator.msPointerEnabled) {
  pointerDownName = 'MSPointerDown';
  pointerUpName = 'MSPointerUp';
  pointerMoveName = 'MSPointerMove';
}

// Simple way to check if some form of pointerevents is enabled or not
window.PointerEventsSupport = false;
if (window.PointerEvent || window.navigator.msPointerEnabled) {
  window.PointerEventsSupport = true;
}

Để biết thêm thông tin, hãy xem bài viết cập nhật này của Microsoft.

Tài liệu tham khảo

Lớp giả lập cho trạng thái chạm

Lớp Ví dụ: Mô tả
:hover
Nút ở trạng thái nhấn
Được nhập khi con trỏ được đặt trên một phần tử. Những thay đổi trong giao diện người dùng khi di chuột sẽ giúp khuyến khích người dùng tương tác với các phần tử.
:focus
Nút có trạng thái lấy nét
Được nhập khi người dùng nhấn phím tab qua các phần tử trên trang. Trạng thái tâm điểm cho phép người dùng biết họ đang tương tác với phần tử nào; cũng cho phép người dùng dễ dàng thao tác trên giao diện người dùng của bạn bằng bàn phím.
:đang hoạt động
Nút ở trạng thái nhấn
Được nhập khi một phần tử đang được chọn, ví dụ: khi người dùng nhấp hoặc chạm vào một phần tử.

Bạn có thể xem tài liệu tham khảo chính thức về các sự kiện chạm tại đây: Sự kiện chạm W3C.

Sự kiện chạm, chuột và con trỏ

Các sự kiện này là những thành phần cơ bản để thêm cử chỉ mới vào ứng dụng:

Sự kiện chạm, chuột, con trỏ
touchstart, mousedown, pointerdown Lệnh này được gọi khi ngón tay chạm vào một phần tử lần đầu tiên hoặc khi người dùng nhấp chuột xuống.
touchmove, mousemove, pointermove Lệnh này được gọi khi người dùng di chuyển ngón tay trên màn hình hoặc kéo bằng chuột.
touchend, mouseup, pointerup Lệnh này được gọi khi người dùng nhấc ngón tay ra khỏi màn hình hoặc nhả chuột.
touchcancel pointercancel Phương thức này được gọi khi trình duyệt huỷ các cử chỉ chạm. Ví dụ: người dùng chạm vào một ứng dụng web rồi thay đổi các thẻ.

Danh sách cảm ứng

Mỗi sự kiện chạm bao gồm 3 thuộc tính danh sách:

Thuộc tính sự kiện chạm
touches Danh sách tất cả các thao tác chạm hiện tại trên màn hình, bất kể các thành phần đang được chạm vào.
targetTouches Danh sách các thao tác chạm bắt đầu trên phần tử là mục tiêu của sự kiện hiện tại. Ví dụ: nếu liên kết với <button>, bạn sẽ chỉ nhận được các thao tác chạm hiện đang có trên nút đó. Nếu liên kết với tài liệu, bạn sẽ nhận được tất cả các thao tác chạm hiện có trên tài liệu.
changedTouches Danh sách các thao tác chạm đã thay đổi dẫn đến việc kích hoạt sự kiện:
  • Đối với sự kiện touchstart – danh sách các điểm tiếp xúc vừa bắt đầu hoạt động cùng với sự kiện hiện tại.
  • Đối với sự kiện touchmove – danh sách các điểm chạm đã di chuyển kể từ sự kiện gần nhất.
  • Đối với các sự kiện touchend touchcancel – danh sách các điểm tiếp xúc vừa bị xoá khỏi nền tảng.

Bật tính năng hỗ trợ trạng thái đang hoạt động trên iOS

Rất tiếc, Safari trên iOS không áp dụng trạng thái đang hoạt động theo mặc định. Để làm cho trạng thái này hoạt động, bạn cần thêm trình nghe sự kiện touchstart vào phần nội dung tài liệu hoặc vào từng phần tử.

Bạn nên thực hiện việc này sau khi kiểm thử tác nhân người dùng để chỉ chạy trên thiết bị iOS.

Việc thêm điểm bắt đầu chạm vào phần thân có ưu điểm là áp dụng cho tất cả các phần tử trong DOM, tuy nhiên, điều này có thể gây ra vấn đề về hiệu suất khi cuộn trang.

window.onload = function() {
  if (/iP(hone|ad)/.test(window.navigator.userAgent)) {
    document.body.addEventListener('touchstart', function() {}, false);
  }
};

Giải pháp thay thế là thêm trình nghe bắt đầu chạm vào tất cả các phần tử có thể tương tác trong trang, giúp giảm bớt một số vấn đề về hiệu suất.

window.onload = function() {
  if (/iP(hone|ad)/.test(window.navigator.userAgent)) {
    var elements = document.querySelectorAll('button');
    var emptyFunction = function() {};

    for (var i = 0; i < elements.length; i++) {
        elements[i].addEventListener('touchstart', emptyFunction, false);
    }
  }
};