快速入門:指標 (HTML)

[ 本文的目標對象是撰寫 Windows 執行階段 App 的 Windows 8.x 和 Windows Phone 8.x 開發人員。如果您正在開發適用於 Windows 10 的 App,請參閱 最新文件 ]

觸控、滑鼠及畫筆/手寫筆互動在使用 JavaScript 的應用程式中,會以指標輸入的形式接收、處理及管理。

Windows 8.1 的更新: Windows 8.1 對指標輸入 API 引入了數種更新及改進。如需詳細資訊,請參閱 Windows 8.1 的 API 變更

如果您是使用 JavaScript 開發應用程式的新手: 請仔細閱讀這些主題以熟悉這裡討論的技術。

使用 JavaScript 建立您的第一個 Windows 市集應用程式

使用 JavaScript 建立 Windows 市集應用程式的藍圖

請參閱快速入門:新增 HTML 控制項和處理事件以了解事件

應用程式功能,從開始到完成:

應用程式功能,從開始到完成系列深入探索此功能。

使用者互動,從開始到完成 (HTML)

使用者互動自訂,從開始到完成 (HTML)

使用者經驗指導方針:

平台控制項程式庫 (HTMLXAML) 提供完整的 Windows 使用者互動體驗,包含標準互動、動畫物理效果及視覺化回饋。 如果您不需要自訂的互動支援,請使用這些內建控制項。

如果平台控制項不足,下列使用者互動指導方針能讓您在各種輸入模式下提供令人讚賞的沈浸式互動體驗。這些指導方針主要著重在觸控輸入,不過與觸控板、滑鼠、鍵盤和手寫筆輸入仍有相關。

範例:應用程式範例中,查看此功能的執行方式。

使用者互動自訂,從開始到完成範例

HTML 捲動、移動瀏覽和縮放範例

輸入:DOM 指標事件處理範例

輸入:可具現化手勢範例

輸入:筆跡範例

輸入:操作和手勢 (JavaScript) 範例

輸入:簡化的筆跡範例

目標: 了解如何接聽和處理指標輸入。

先決條件

我們假設您可以利用 JavaScript,以適用於 JavaScript 的 Windows Library 範本建立基本的應用程式。

若要完成這個教學課程,您需要:

完成所需的時間: 30 分鐘.

指示

什麼是指標輸入?

透過將滑鼠、畫筆/手寫筆及觸控輸入統一成抽象的指標輸入,無論使用何種輸入裝置類型,您都可以使用您的應用程式來處理使用者互動。

指標物件代表一個來自輸入裝置 (例如滑鼠、畫筆/手寫筆、單指或多指) 的單一、獨特的輸入「接觸點」(一個 PointerPoint)。當第一次偵測到接觸點時,系統會建立一個指標,然後當指標離開 (移出) 偵測範圍或取消時,就會將它銷毀。如果有多個裝置或為多點觸控輸入,就會將每個接觸點視為不同的單一指標。

有一組廣泛的指標式輸入 API,可以直接攔截來自各種裝置的輸入資料。您可以處理指標事件以取得一般資訊 (如位置與裝置類型) 和延伸資訊 (如壓力和接觸點幾何)。由於在許多情況下,應用程式必須以不同方式回應不同的輸入模式,因此也有特定的裝置屬性 (例如使用者按下哪個滑鼠按鈕,或使用者是否正使用手寫筆橡皮擦觸控端)。例如,可以篩選觸控以支援移動瀏覽和捲動之類的互動,而滑鼠和畫筆/手寫筆則通常較適合精準的工作 (例如筆跡和繪圖)。如果您的應用程式必須區別輸入裝置和它們的功能,請參閱快速入門:識別輸入裝置

如果您實作自己的互動支援,請牢記使用者所期待的是與應用程式 UI 元素直接互動的直覺式體驗。 建議您以架構控制項來模型化您的自訂互動,以保持一致和可探索的 UI 體驗。只有在需求明確且定義清楚,而且沒有基本的互動可以支援您的情況時,才建立自訂互動。

建立 UI

針對這個範例,我們使用矩形 (target) 做為指標輸入的目標物件。當指標狀態變更時,目標的色彩就會變更。

每個指標的詳細資料都會顯示在浮動的文字區塊中,該文字區塊位於指標旁,且會跟隨指標移動。特定指標事件會在畫面最右側回報。下列為顯示此範例之 UI 的螢幕擷取畫面。

範例應用程式 UI 的螢幕擷取畫面。

這是這個範例的 HTML。

注意  Windows 市集應用程式

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>PointerInput_Universal.Windows</title>

    <!-- WinJS references -->
    <link href="//Microsoft.WinJS.2.0/css/ui-dark.css" rel="stylesheet" />
    <script src="//Microsoft.WinJS.2.0/js/base.js"></script>
    <script src="//Microsoft.WinJS.2.0/js/ui.js"></script>

    <!-- PointerInput_Universal.Windows references -->
    <link href="/css/default.css" rel="stylesheet" />
    <script src="/js/default.js"></script>
</head>
<body class="windows">
    <div id="grid">
        <div id="targetContainer">
            <div id="target"></div>
        </div>
        <div id="bottom">
        </div>
        <div id="eventLog"></div>
    </div>
</body>
</html>

注意  Windows Phone 市集應用程式

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>PointerInput_Universal.WindowsPhone</title>

    <!-- WinJS references -->
    <!-- At runtime, ui-themed.css resolves to ui-themed.light.css or ui-themed.dark.css 
    based on the user’s theme setting. This is part of the MRT resource loading functionality. -->
    <link href="/css/ui-themed.css" rel="stylesheet" />
    <script src="//Microsoft.Phone.WinJS.2.1/js/base.js"></script>
    <script src="//Microsoft.Phone.WinJS.2.1/js/ui.js"></script>

    <!-- PointerInput_Universal.Phone references -->
    <link href="/css/default.css" rel="stylesheet" />
    <script src="/js/default.js"></script>
</head>
<body class="phone">
    <div id="grid">
        <div id="targetContainer">
            <div id="target"></div>
        </div>
        <div id="bottom">
        </div>
        <div id="eventLog"></div>
    </div>
</body>
</html>

這是這個範例的階層式樣式表 (CSS)。

注意  在移動瀏覽或縮放互動期間,不會觸發指標事件。您可以透過 CSS 屬性 msTouchActionoverflow 以及 -ms-content-zooming,在某個區域上停用移動瀏覽和縮放。

 

body {
    overflow: hidden;
    position: relative;
}

#grid {
    display: -ms-grid;
    height: 100vh; /* 100% of viewport height */
    -ms-grid-columns: 4fr 1fr; /* 2 columns */
    -ms-grid-rows: 1fr 320px 1fr;  /* 3 rows */
    /*touch-action: none;*/ /* Disable panning and zooming */
}
#targetContainer {
    border:solid;
    border-width:thin;
    border-color: red;
    -ms-grid-row: 2;
    -ms-grid-column: 1;
    -ms-grid-row-align: center;
    -ms-grid-column-align: center;
    /*touch-action: none; /* Disable panning and zooming */*/
}
#eventLog {
    -ms-grid-row: 1;
    -ms-grid-column: 2; 
    -ms-grid-row-span: 3;
    padding-right: 10px;
    background-color: black;
    color: white;
}
.phone #target {
    width: 200px;
    height: 300px;
    border: none;
    padding: 0px;
    margin: 0px;
    -ms-transform-origin: 0% 0%;
    /*touch-action: none; /* Disable panning and zooming */*/
}
.windows #target {
    width: 400px;
    height: 200px;
    border: none;
    padding: 0px;
    margin: 0px;
    -ms-transform-origin: 0% 0%;
    touch-action: none; /* Disable panning and zooming */
}

接聽指標事件

在多數情況下,建議透過您選擇的語言架構中的指標事件處理常式的事件引數來取得指標資訊。

如果事件引數未公開應用程式所需的指標詳細資料,您可以透過 getCurrentPointgetIntermediatePoints 方法或 currentPointintermediatePoints 屬性,從事件引數取得延伸指標資料的存取權。因為您可以指定指標資料內容,所以建議您使用 getCurrentPointgetIntermediatePoints 方法。

下列為顯示目標區域的螢幕擷取畫面,其中包含此範例的滑鼠指標詳細資料。

指標目標區域的螢幕擷取畫面。

我們在這裡設定目標區域的畫面位置和事件接聽程式。

首先,我們宣告全域變數、初始化目標及指標詳細資料區域,然後識別事件記錄器。

// For this example, we track simultaneous contacts in case the 
// number of contacts has reached the maximum supported by the device.
// Depending on the device, additional contacts might be ignored 
// (PointerPressed not fired). 
var numActiveContacts = 0;

// The input target.
var target;

// Target background colors corresponding to various pointer states.
var pointerColor = {
    hover: "rgb(255, 255, 102)",
    down: "rgb(0, 255, 0)",
    up: "rgb(255, 0, 0)",
    cancel: "rgb(0,0,0)",
    out: "rgb(127,127,127)",
    over: "rgb(0,0,255)"
};

// The event log (updated on each event).
var eventLog;

function initialize() {
    /// <summary>Set up the app.</summary>
    eventLog = document.getElementById("eventLog");
    target = document.getElementById("target");
    setTarget();
}

然後設定目標物件,並為目標宣告不同的指標事件接聽程式。

function setTarget() {
    /// <summary>Set up the target and interaction event handlers.</summary>

    // Initial color of target.
    target.style.backgroundColor = pointerColor.out;

    // Expando dictionary property to track active contacts. 
    // An entry is added during pointer down/hover/over events 
    // and removed during pointer up/cancel/out/lostpointercapture events.
    target.pointers = [];

    // Declare pointer event handlers.
    target.addEventListener("pointerdown", onPointerDown, true);
    target.addEventListener("pointerover", onPointerOver, true);
    target.addEventListener("pointerup", onPointerUp, true);
    target.addEventListener("pointerout", onPointerOut, true);
    target.addEventListener("pointercancel", onPointerCancel, true);
    target.addEventListener("lostpointercapture", onLostPointerCapture, true);
    target.addEventListener("pointermove", onPointerMove, true);
    target.addEventListener("wheel", onMouseWheel, false);
}

最後設定指標詳細資料區域。

function createInfoPop(e) {
    /// <summary>
    /// Create and insert DIV into the DOM for displaying pointer details.
    /// </summary>
    /// <param name="e" type="Event">The event argument.</param>
    var infoPop = document.createElement("div");
    infoPop.setAttribute("id", "infoPop" + e.pointerId);

    // Set screen position of DIV.
    var transform = (new MSCSSMatrix()).translate(e.offsetX + 20, e.offsetY + 20);
    infoPop.style.msTransform = transform;
    target.appendChild(infoPop);

    infoPop.innerText = queryPointer(e);
}

function updateInfoPop(e) {
    /// <summary>
    /// Update pointer details in UI.
    /// </summary>
    /// <param name="e" type="Event">The event argument.</param>
    var infoPop = document.getElementById("infoPop" + e.pointerId);
    if (infoPop === null)
        return;

    // Set screen position of DIV.
    var transform = (new MSCSSMatrix()).translate(e.offsetX + 20, e.offsetY + 20);
    infoPop.style.msTransform = transform;
    infoPop.innerText = queryPointer(e);
}

處理指標事件

接下來,我們使用 UI 回饋來示範基本指標事件處理常式。

  • 這個處理常式會管理指標接觸點 (向下、按下) 事件。我們將事件新增到事件記錄檔,將指標新增到用於追蹤相關指標的指標陣列,並顯示指標詳細資料。

    注意  pointerdownpointerup 事件不會永遠成對出現。您的應用程式應接聽和處理可能完成指標向下動作 (例如 pointeruppointeroutpointercancel 以及 lostpointercapture) 的任何事件。

     

    function onPointerDown(e) {
        /// <summary>
        /// Occurs for mouse when at least one mouse button is pressed or 
        /// for touch and pen when there is physical contact with the digitizer.
        /// For input devices that do not support hover, the pointerover event is 
        /// fired immediately before the pointerdown event.  
        /// Here, we  filter pointer input based on the first pointer type detected. 
        /// </summary>
        /// <param name="e" type="Event">The event argument.</param>
    
        // pointerdown and pointerup events do not always occur in pairs. 
        // Listen for and handle any event that might conclude a pointer down action 
        // (such as pointerup, pointerout, pointercancel, and lostpointercapture).
        //
        // For this example, we track the number of contacts in case the 
        // number of contacts has reached the maximum supported by the device.
        // Depending on the device, additional contacts might be ignored 
        // (PointerPressed not fired). 
    
        // Prevent the next handler in the hierarchy from receiving the event.
        e.cancelBubble = true;
    
        // Check if the number of supported contacts is exceeded.
        var touchCapabilities = new Windows.Devices.Input.TouchCapabilities();
        if ((touchCapabilities.touchPresent != 0) & (numActiveContacts > touchCapabilities.contacts)) {
            return;
        }
    
        // Update event details and target UI.
        eventLog.innerText += "\nDown: " + e.pointerId;
        target.style.backgroundColor = pointerColor.down;
    
        // Check if pointer already exists (if hover/over occurred prior to down).
        for (var i in target.pointers) {
            if (target.pointers[i].id = e.pointerId) {
                return;
            }
        }
    
        // Push new pointer Id onto expando target pointers array.
        target.pointers.push({ id: e.pointerId, type: e.pointerType });
    
        // Ensure that the element continues to receive PointerEvents 
        // even if the contact moves off the element. 
        // Capturing the current pointer can improve usability by reducing 
        // the touch precision required when interacting with an element.
        // Note: Only the assigned pointer is affected. 
        target.setPointerCapture(e.pointerId);
    
        // Display pointer details.
        createInfoPop(e);
    }
    
  • 這個處理常式會管理接觸時在目標界限內移動之指標的指標進入 (暫留) 事件。我們將事件新增到事件記錄檔,將指標新增到指標陣列,並顯示指標詳細資料。

    如需處理未接觸但位於目標 (通常是畫筆/手寫筆裝置) 界限內之指標的暫留狀態,請參閱 pointermove 事件。

    function onPointerOver(e) {
        /// <summary>
        /// Occurs when a pointer is detected within the hit test boundaries 
        /// of an element.
        /// Also occurs prior to a pointerdown event for devices that do not 
        /// support hover.  
        /// This event type is similar to pointerenter, but bubbles. 
        /// See the pointermove event for handling the hover state of a pointer 
        /// that is not in contact but is within the boundary of the target 
        /// (typically a pen/stylus device). 
        /// </summary>
        /// <param name="e" type="Event">The event argument.</param>
    
        // Prevent the next handler in the hierarchy from receiving the event.
        e.cancelBubble = true;
    
        // Update event details and target UI.
        eventLog.innerText += "\nOver: " + e.pointerId;
    
        if (target.pointers.length === 0) {
            // Change background color of target when pointer contact detected.
            if (e.getCurrentPoint(e.currentTarget).isInContact) {
                // Pointer down occured outside target.
                target.style.backgroundColor = pointerColor.down;
            } else {
                // Pointer down occured inside target.
                target.style.backgroundColor = pointerColor.over;
            }
        }
    
        // Check if pointer already exists.
        for (var i in target.pointers) {
            if (target.pointers[i].id = e.pointerId) {
                return;
            }
        }
    
        // Push new pointer Id onto expando target pointers array.
        target.pointers.push({ id: e.pointerId, type: e.pointerType });
    
        // Ensure that the element continues to receive PointerEvents 
        // even if the contact moves off the element. 
        // Capturing the current pointer can improve usability by reducing 
        // the touch precision required when interacting with an element.
        // Note: Only the assigned pointer is affected. 
        target.setPointerCapture(e.pointerId);
    
        // Display pointer details.
        createInfoPop(e);
    }
    
  • 這個處理常式會管理指標移動事件。我們將事件新增到事件記錄,並更新指標詳細資料 (對於暫留,我們也將指標新增到指標陣列)。

    MSPointerHover 在 Windows 8.1 中已經過時。請使用 pointermoveIsInContact 指標屬性來判斷暫留狀態。

    注意   您也可以在此處理常式中處理多個同步滑鼠按鈕按一下的動作。滑鼠輸入與第一次偵測到滑鼠輸入時指派的單一指標相關。在互動時,按一下其他的滑鼠按鈕 (左鍵、滾輪 或右鍵),可透過指標按下事件在那些按鈕與指標之間建立 次要關聯。 只有在放開與互動關聯的最後一個滑鼠按鈕時 (不一定是初始按鈕),才會引發指標放開事件。 由於這個專屬關聯的關係,其他滑鼠按鈕按一下都會 經由指標移動事件路由。

     

     function onPointerMove(e) {
         /// <summary>
         /// Occurs when a pointer moves within the hit test boundaries 
         /// of an element.
         /// </summary>
         /// <param name="e" type="Event">The event argument.</param>
    
         // NOTE: Multiple, simultaneous mouse button inputs are processed here.
         // Mouse input is associated with a single pointer assigned when 
         // mouse input is first detected. 
         // Clicking additional mouse buttons (left, wheel, or right) during 
         // the interaction creates secondary associations between those buttons 
         // and the pointer through the pointer pressed event. 
         // The pointer released event is fired only when the last mouse button 
         // associated with the interaction (not necessarily the initial button) 
         // is released. 
         // Because of this exclusive association, other mouse button clicks are 
         // routed through the pointer move event.  
    
         // Prevent the next handler in the hierarchy from receiving the event.
         e.cancelBubble = true;
    
         if (e.pointerType == "mouse") {
             // Mouse button states are extended PointerPoint properties.
             var pt = e.getCurrentPoint(e.currentTarget);
             var ptProperties = pt.properties;
             if (ptProperties.isLeftButtonPressed) {
                 eventLog.innerText += "\nLeft button: " + e.pointerId;
             }
             if (ptProperties.isMiddleButtonPressed) {
                 eventLog.innerText += "\nWheel button: " + e.pointerId;
             }
             if (ptProperties.isRightButtonPressed) {
                 eventLog.innerText += "\nRight button: " + e.pointerId;
             }
         }
         // Handle hover state of a pointer that is not in contact but is within 
         // the boundary of the target (typically a pen/stylus device). 
         if (e.pointerType == "pen") {
             var pt = e.getCurrentPoint(e.currentTarget);
             if (pt.isInContact == false) {
                 // Update event details and target UI.
                 target.style.backgroundColor = pointerColor.hover;
                 eventLog.innerText = "\nHover: " + e.pointerId;
    
                 // Check if pointer already exists.
                 for (var i in target.pointers) {
                     if (target.pointers[i].id = e.pointerId) {
                         updateInfoPop(e);
                         return;
                     }
                 }
    
                 target.pointers.push({ id: e.pointerId, type: e.pointerType });
    
                 // Ensure that the element continues to receive PointerEvents 
                 // even if the contact moves off the element. 
                 // Capturing the current pointer can improve usability by reducing 
                 // the touch precision required when interacting with an element.
                 // Note: Only the assigned pointer is affected. 
                 target.setPointerCapture(e.pointerId);
             }
         }
    
         // Display pointer details.
         updateInfoPop(e);
     }
    
  • 這個處理常式會管理滑鼠滾輪事件 (旋轉)。我們將事件新增到事件記錄檔,將指標新增到指標陣列 (必要時),並顯示指標詳細資料。

    function onMouseWheel(e) {
        /// <summary>  
        /// Occurs when the mouse wheel is rotated. 
        /// </summary> 
        /// <param name="e" type="Event">The event argument.</param>
        // Check if a mouse pointer already exists.
        for (var i in target.pointers) {
            // Ensure existing pointer type registered with pointerover is mouse. 
            if (target.pointers[i].type === "mouse") {
                e.pointerId = target.pointers[i].id;
                break;
            }
        }
        eventLog.innerText += "\nMouse wheel: " + e.pointerId;
        // For this example, we fire a corresponding pointer down event.
        onPointerDown(e);
    }
    
  • 這個處理常式會管理指標離開 (向上) 事件。我們將事件新增到事件記錄檔,從指標陣列移除指標,並更新指標詳細資料。

    function onPointerUp(e) {
        /// <summary>
        /// Occurs for mouse at transition from at least one button pressed 
        /// to no buttons pressed.
        /// Occurs for touch and pen when contact is removed from the digitizer. 
        /// For input devices that do not support hover, the pointerout event 
        /// is fired immediately after the pointerup event.  
        /// </summary>
        /// <param name="e" type="Event">The event argument.</param>
    
        // Prevent the next handler in the hierarchy from receiving the event.
        e.cancelBubble = true;
    
        // Update event details.
        eventLog.innerText += "\nUp: " + e.pointerId;
    
        // If event source is mouse pointer and the pointer is still 
        // over the target, retain pointer and pointer details.
        // Return without removing pointer from pointers dictionary.
        // For this example, we assume a maximum of one mouse pointer.
        if ((e.pointerType === "mouse") &
            (document.elementFromPoint(e.x, e.y) === target)) {
            target.style.backgroundColor = pointerColor.up;
            return;
        }
    
        // Ensure capture is released on a pointer up event.
        target.releasePointerCapture(e.pointerId);
    
        // Remove pointer from pointers dictionary.
        var targetPointers = target.pointers;
        for (var i in targetPointers) {
            if (target.pointers[i].id === e.pointerId) {
                target.pointers.splice(i, 1);
                var pointerInfoPop = document.getElementById("infoPop" + e.pointerId);
                if (pointerInfoPop === null)
                    return;
                pointerInfoPop.removeNode(true);
            }
        }
    
        // Update target UI.
        if (target.pointers.length === 0) {
            target.style.backgroundColor = pointerColor.up;
        }
    }
    
  • 這個處理常式會管理指標離開 (退出) 事件。我們將事件新增到事件記錄檔,從指標陣列移除指標,並更新指標詳細資料。

    function onPointerOut(e) {
        /// <summary>
        /// Occurs when a pointer (in contact or not) moves out of the 
        /// target hit test boundary, after a pointerup event for a device 
        /// that does not support hover, and after a pointercancel event. 
        /// This event type is similar to pointerleave, but bubbles.  
        /// Note: Pointer capture is maintained until pointer up event.
        /// </summary>
        /// <param name="e" type="Event">The event argument.</param>
    
        // Prevent the next handler in the hierarchy from receiving the event.
        e.cancelBubble = true;
    
        // Update event details.
        eventLog.innerText += "\nPointer out: " + e.pointerId;
    
        // Remove pointer from pointers dictionary.
        var targetPointers = target.pointers;
        for (var i in targetPointers) {
            if (target.pointers[i].id === e.pointerId) {
                target.pointers.splice(i, 1);
                var pointerInfoPop = document.getElementById("infoPop" + e.pointerId);
                if (pointerInfoPop === null)
                    return;
                pointerInfoPop.removeNode(true);
    
                // Update target UI.
                if (target.pointers.length === 0) {
                    target.style.backgroundColor = pointerColor.out;
                }
            }
        }
    }
    
  • 這個處理常式會管理指標取消事件。我們將事件新增到事件記錄檔,從指標陣列移除指標,並更新指標詳細資料。

    function onPointerCancel(e) {
        /// <summary>
        /// Occurs when a pointer is removed.
        /// The app will not receive subsequent events for that pointer, including pointerup.  
        /// </summary>
        /// <param name="e" type="Event">The event argument.</param>
    
        // A pointer can be canceled as a result of one of the following:
        //    - A touch contact is canceled when a pen is detected.
        //    - More than 100ms has passed since the device reported
        //      an active contact.
        //    - The desktop is locked or the user logged off. 
        //    - The number of simultaneous contacts exceeds the number 
        //      supported by the device.
        //    - The system has determined that a pointer is unlikely to 
        //      continue to produce events (for example, due to a hardware event).
        //    - After a pointerdown event, the pointer is subsequently used to 
        //      manipulate the page viewport (for example, panning or zooming).  
    
        // Prevent the next handler in the hierarchy from receiving the event.
        e.cancelBubble = true;
    
        // Update event details.
        eventLog.innerText += "\nPointer canceled: " + e.pointerId;
    
        // Ensure capture is released on a pointer cancel event.
        target.releasePointerCapture(e.pointerId);
    
        // Update target UI.
        if (target.pointers.length === 0) {
            target.style.backgroundColor = pointerColor.cancel;
        }
    
        // Remove pointer from pointers dictionary.
        var targetPointers = target.pointers;
        for (var i in targetPointers) {
            if (target.pointers[i].id === e.pointerId) {
                target.pointers.splice(i, 1);
                var pointerInfoPop = document.getElementById("infoPop" + e.pointerId);
                if (pointerInfoPop === null)
                    return;
                pointerInfoPop.removeNode(true);
    
                // Update target UI.
                if (target.pointers.length === 0) {
                    target.style.backgroundColor = pointerColor.out;
                }
            }
        }
    }
    
  • 這個處理常式會管理遺失指標擷取事件。我們將事件新增到事件記錄檔,從指標陣列移除指標,並更新指標詳細資料。

    注意  lostpointercapture 可能會發生,而非 pointerup。指標擷取可能會因為使用者互動,或因為另一個指標已經以程式設計方式擷取,或已刻意釋放目前的指標擷取而遺失。

     

    function onLostPointerCapture(e) {
        /// <summary>
        /// Occurs after pointer capture is released for the pointer.  
        /// </summary>
        /// <param name="e" type="Event">The event argument.</param>
    
        // lostpointercapture can fire instead of pointerup. 
    
        // Pointer capture can be lost as a result of one of the following:
        //    - User interactions
        //    - Programmatic caputre of another pointer
        //    - Captured pointer was deliberately released
    
        // Prevent the next handler in the hierarchy from receiving the event.
        e.cancelBubble = true;
    
        // Update event details.
        eventLog.innerText += "\nLost pointer capture: " + e.pointerId;
    
        // We need the device type to handle lost pointer capture from mouse input.
        // Use the getCurrentPoint method over currentPoint property to ensure
        // the coordinate space is in relation to the target element.
        // Note: getCurrentPoint and currentPoint are only available in the 
        // local compartment, they are not available in the web compartment.
        var ptTarget = e.getCurrentPoint(e.currentTarget);
        var ptContainer = e.getCurrentPoint(document.getElementsByTagName("body")[0]);
    
        // If event source is mouse pointer and the pointer is still over 
        // the target, retain pointer and pointer details.
        // For this example, we assume only one mouse pointer.
        if ((ptTarget.pointerDevice.pointerDeviceType === Windows.Devices.Input.PointerDeviceType.mouse) &
            (document.elementFromPoint(ptContainer.position.x, ptContainer.position.y) === target)) {
            target.setPointerCapture(e.pointerId);
            return;
        }
    
        // Remove pointer from pointers dictionary.
        var targetPointers = target.pointers;
        for (var i in targetPointers) {
            if (target.pointers[i].id === e.pointerId) {
                target.pointers.splice(i, 1);
                var pointerInfoPop = document.getElementById("infoPop" + e.pointerId);
                if (pointerInfoPop === null)
                    return;
                pointerInfoPop.removeNode(true);
            }
        }
    
        // Update target UI.
        if (target.pointers.length === 0) {
            target.style.backgroundColor = pointerColor.cancel;
        }
    }
    

取得指標屬性

您為應用程式選擇的語言架構指定了如何取得指標屬性。許多屬性是透過指標事件物件直接公開。如前所述,您可以透過事件引數的 getCurrentPointgetIntermediatePoints 方法或 currentPointintermediatePoints 屬性,取得其他指標資訊。因為您可以指定指標資料內容,所以建議您使用 getCurrentPointgetIntermediatePoints 方法。

我們將在此直接從事件物件和只能夠透過 PointerPointPointerPointProperties 物件使用的延伸屬性,查詢各種指標屬性。

function queryPointer(e) {
    /// <summary>
    /// Get extended pointer data.
    /// </summary>
    /// <param name="e" type="Event">The event argument.</param>

    // We get the extended pointer info through the getCurrentPoint method
    // of the event argument. (We recommend using getCurrentPoint 
    // to ensure the coordinate space is in relation to the target.)
    // Note: getCurrentPoint and currentPoint are only available in the 
    // local compartment, they are not available in the web compartment.

    var pt = e.getCurrentPoint(e.currentTarget);
    var ptTargetProperties = pt.properties;

    var details = "Pointer Id: " + e.pointerId;
    switch (e.pointerType) {
        case "mouse":
            details += "\nPointer type: mouse";
            details += "\nLeft button: " + ptTargetProperties.isLeftButtonPressed;
            details += "\nRight button: " + ptTargetProperties.isRightButtonPressed;
            details += "\nWheel button: " + ptTargetProperties.isMiddleButtonPressed;
            details += "\nX1 button: " + ptTargetProperties.isXButton1Pressed;
            details += "\nX2 button: " + ptTargetProperties.isXButton2Pressed;
            break;
        case "pen":
            details += "\nPointer type: pen";
            if (pt.isInContact) {
                details += "\nPressure: " + ptTargetProperties.pressure;
                details += "\nrotation: " + ptTargetProperties.rotation;
                details += "\nTilt X: " + ptTargetProperties.xtilt;
                details += "\nTilt Y: " + ptTargetProperties.ytilt;
                details += "\nBarrel button pressed: " + ptTargetProperties.isBarrelButtonPressed;
            }
            break;
        case "touch":
            details += "\nPointer type: touch";
            details += "\nPressure: " + ptTargetProperties.pressure;
            details += "\nrotation: " + ptTargetProperties.rotation;
            details += "\nTilt X: " + ptTargetProperties.xtilt;
            details += "\nTilt Y: " + ptTargetProperties.ytilt;
            break;
        default:
            details += "\nPointer type: " + "n/a";
            break;
    }
    details += "\nPointer location (target): " + e.offsetX + ", " + e.offsetY;
    details += "\nPointer location (screen): " + e.screenX + ", " + e.screenY;

    return details;
}

如需較複雜範例的連結,請參閱本頁面下方的相關主題。

完整範例

請參閱指標的完整程式碼

摘要與後續步驟

在這個快速入門中,您已經了解使用 JavaScript 的應用程式中的指標輸入。

指標事件對管理簡單的互動 (例如點選、滑動) 和其他裝置特定的互動 (包含從次要滑鼠按鈕、滑鼠滾輪、手寫筆筆身按鈕和手寫筆橡皮擦輸入) 來說很有用。

若要處理更複雜的互動 (例如 Windows 8 觸控語言中描述的手勢),請參閱快速入門:DOM 手勢與操作快速入門:靜態手勢以及快速入門:操作手勢

如需 Windows 8 觸控語言的詳細資訊,請參閱觸控互動設計

相關主題

開發人員

回應使用者互動

開發 Windows 市集應用程式 (JavaScript 和 HTML)

快速入門:DOM 手勢與操作

快速入門:靜態手勢

快速入門:操作手勢

設計人員

觸控互動設計