--- title: 多点触控交互 slug: Web/API/Touch_events/Multi-touch_interaction translation_of: Web/API/Touch_events/Multi-touch_interaction ---
{{DefaultAPISidebar("Touch Events")}}
The touch event interfaces support application-specific single and multi-touch interactions. However, the interfaces can be a bit tricky for programmers to use because touch events are very different from other DOM input events, such as {{domxref("MouseEvent","mouse events")}}. The application described in this guide shows how to use touch events for simple single and multi-touch interactions, the basics needed to build application-specific gestures.
A live version of this application is available on Github. The source code is available on Github and pull requests and bug reports are welcome.
This example demonstrates using the {{event("touchstart")}}, {{event("touchmove")}}, {{event("touchcancel")}}, and {{event("touchend")}}) touch events for the following gestures: single touch, two (simultaneous) touches, more than two simultaneous touches, 1-finger swipe, and 2-finger move/pinch/swipe.
The application uses {{HTMLElement("div")}} elements to represent four touch areas.
<style>
div {
margin: 0em;
padding: 2em;
}
#target1 {
background: white;
border: 1px solid black;
}
#target2 {
background: white;
border: 1px solid black;
}
#target3 {
background: white;
border: 1px solid black;
}
#target4 {
background: white;
border: 1px solid black;
}
</style>
tpCache is used to cache touch points for processing outside of the event where they were fired.
// Log events flag var logEvents = false; // Touch Point cache var tpCache = new Array();
Event handlers are registered for all four touch event types. The {{event("touchend")}} and {{event("touchcancel")}} event types use the same handler.
function set_handlers(name) {
// Install event handlers for the given element
var el=document.getElementById(name);
el.ontouchstart = start_handler;
el.ontouchmove = move_handler;
// Use same handler for touchcancel and touchend
el.ontouchcancel = end_handler;
el.ontouchend = end_handler;
}
function init() {
set_handlers("target1");
set_handlers("target2");
set_handlers("target3");
set_handlers("target4");
}
This function provides very basic support for 2-touch horizontal move/pinch/zoom handling. The code does not include error handling, or vertical moving. Note that the threshold for pinch and zoom movement detection is application specific (and device dependent).
// This is a very basic 2-touch move/pinch/zoom handler that does not include
// error handling, only handles horizontal moves, etc.
function handle_pinch_zoom(ev) {
if (ev.targetTouches.length == 2 && ev.changedTouches.length == 2) {
// Check if the two target touches are the same ones that started
// the 2-touch
var point1=-1, point2=-1;
for (var i=0; i < tpCache.length; i++) {
if (tpCache[i].identifier == ev.targetTouches[0].identifier) point1 = i;
if (tpCache[i].identifier == ev.targetTouches[1].identifier) point2 = i;
}
if (point1 >=0 && point2 >= 0) {
// Calculate the difference between the start and move coordinates
var diff1 = Math.abs(tpCache[point1].clientX - ev.targetTouches[0].clientX);
var diff2 = Math.abs(tpCache[point2].clientX - ev.targetTouches[1].clientX);
// This threshold is device dependent as well as application specific
var PINCH_THRESHHOLD = ev.target.clientWidth / 10;
if (diff1 >= PINCH_THRESHHOLD && diff2 >= PINCH_THRESHHOLD)
ev.target.style.background = "green";
}
else {
// empty tpCache
tpCache = new Array();
}
}
}
The {{event("touchstart")}} event handler caches touch points to support 2-touch gestures. It also calls {{domxref("Event.preventDefault","preventDefault()")}} to keep the browser from applying further event handling (for example, mouse event emulation).
function start_handler(ev) {
// If the user makes simultaneious touches, the browser will fire a
// separate touchstart event for each touch point. Thus if there are
// three simultaneous touches, the first touchstart event will have
// targetTouches length of one, the second event will have a length
// of two, and so on.
ev.preventDefault();
// Cache the touch points for later processing of 2-touch pinch/zoom
if (ev.targetTouches.length == 2) {
for (var i=0; i < ev.targetTouches.length; i++) {
tpCache.push(ev.targetTouches[i]);
}
}
if (logEvents) log("touchStart", ev, true);
update_background(ev);
}
The {{event("touchmove")}} handler calls {{domxref("Event.preventDefault","preventDefault()")}} for the same reason mentioned above, and invokes the pinch/zoom handler.
function move_handler(ev) {
// Note: if the user makes more than one "simultaneous" touches, most browsers
// fire at least one touchmove event and some will fire several touchmoves.
// Consequently, an application might want to "ignore" some touchmoves.
//
// This function sets the target element's border to "dashed" to visually
// indicate the target received a move event.
//
ev.preventDefault();
if (logEvents) log("touchMove", ev, false);
// To avoid too much color flashing many touchmove events are started,
// don't update the background if two touch points are active
if (!(ev.touches.length == 2 && ev.targetTouches.length == 2))
update_background(ev);
// Set the target element's border to dashed to give a clear visual
// indication the element received a move event.
ev.target.style.border = "dashed";
// Check this event for 2-touch Move/Pinch/Zoom gesture
handle_pinch_zoom(ev);
}
The {{event("touchend")}} handler restores the event target's background color back to its original color.
function end_handler(ev) {
ev.preventDefault();
if (logEvents) log(ev.type, ev, false);
if (ev.targetTouches.length == 0) {
// Restore background and border to original values
ev.target.style.background = "white";
ev.target.style.border = "1px solid black";
}
}
The application uses {{HTMLElement("div")}} elements for the touch areas and provides buttons to enable logging and clear the log.
<div id="target1"> Tap, Hold or Swipe me 1</div> <div id="target2"> Tap, Hold or Swipe me 2</div> <div id="target3"> Tap, Hold or Swipe me 3</div> <div id="target4"> Tap, Hold or Swipe me 4</div> <!-- UI for logging/bebugging --> <button id="log" onclick="enableLog(event);">Start/Stop event logging</button> <button id="clearlog" onclick="clearLog(event);">Clear the log</button> <p></p> <output></output>
These functions support the application but aren't directly involved with the event flow.
The background color of the touch areas will change as follows: no touch is white; one touch is yellow; two simultaneous touches is pink, and three or more simultaneous touches is lightblue. See touch move for information about the background color changing when a 2-finger move/pinch/zoom is detected.
function update_background(ev) {
// Change background color based on the number simultaneous touches
// in the event's targetTouches list:
// yellow - one tap (or hold)
// pink - two taps
// lightblue - more than two taps
switch (ev.targetTouches.length) {
case 1:
// Single tap`
ev.target.style.background = "yellow";
break;
case 2:
// Two simultaneous touches
ev.target.style.background = "pink";
break;
default:
// More than two simultaneous touches
ev.target.style.background = "lightblue";
}
}
The functions are used to log event activity to the application window, to support debugging and learning about the event flow.
function enableLog(ev) {
logEvents = logEvents ? false : true;
}
function log(name, ev, printTargetIds) {
var o = document.getElementsByTagName('output')[0];
var s = name + ": touches = " + ev.touches.length +
" ; targetTouches = " + ev.targetTouches.length +
" ; changedTouches = " + ev.changedTouches.length;
o.innerHTML += s + "
";
if (printTargetIds) {
s = "";
for (var i=0; i < ev.targetTouches.length; i++) {
s += "... id = " + ev.targetTouches[i].identifier + "
";
}
o.innerHTML += s;
}
}
function clearLog(event) {
var o = document.getElementsByTagName('output')[0];
o.innerHTML = "";
}