首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> J2EE

JSF 2 打造可重用 Ajax 組件實戰(五):前端 JavaScript 協同邏輯深度解析

     編輯:J2EE

前言:薄而精的 JS 層 — 觸發 Ajax、傳參、定位、防抖

JSF 2 內建 `jsf.ajax` 引擎處理底層 XmlHttpRequest、響應解析、局部更新。組件所需 JS 僅負責:**事件綁定、防抖節流、計算列表框位置、構造 Ajax 參數、失焦隱藏**。本文逐行解析 `autoComplete.js` 核心邏輯。

1. 完整代碼 (autoComplete.js)

if (!com) var com = {};
if (!com.corejsf) {
    var focusLostTimeout;

    com.corejsf = {
        // 統一錯誤處理
        errorHandler: function(data) {
            alert("Ajax error: " + data.description);
        },

        // 輸入框 keyup -> 觸發 Ajax 過濾
        updateCompletionItems: function(input, event) {
            var keystrokeTimeout;

            // 註冊全局 Ajax 錯誤處理器 (僅首次生效)
            jsf.ajax.addOnError(com.corejsf.errorHandler);

            // 實際發送 Ajax 的函數
            var ajaxRequest = function() {
                jsf.ajax.request(input, event, {
                    render: com.corejsf.getListboxId(input), // 僅渲染列表框
                    x: Element.cumulativeOffset(input)[0],   // 輸入框頁面左上角 X
                    y: Element.cumulativeOffset(input)[1]    // 輸入框頁面左上角 Y
                        + Element.getHeight(input)           // + 高度 = 列表框顯示位置
                });
            };

            // 防抖:350ms 內連續輸入只發最後一次
            window.clearTimeout(keystrokeTimeout);
            keystrokeTimeout = window.setTimeout(ajaxRequest, 350);
        },

        // 輸入框失焦 -> 延遲隱藏列表框
        inputLostFocus: function(input) {
            var hideListbox = function() {
                Element.hide(com.corejsf.getListboxId(input));
            };
            // 200ms 延遲:給「點擊列表項」事件留出時間窗口
            focusLostTimeout = window.setTimeout(hideListbox, 200);
        },

        // 根據輸入框 clientId 推導列表框 clientId
        getListboxId: function(input) {
            var clientId = new String(input.name); // name = clientId (JSF 生成)
            var lastIndex = clientId.lastIndexOf(':');
            return clientId.substring(0, lastIndex) + ':listbox';
        }
    };
}

2. 核心函數逐行解析

2.1 命名空間模式:`com.corejsf`

  • 防止全局污染:`var com = com || {}; com.corejsf = ...`
  • 2. 組件多實例共享同一 JS 對象,**無狀態**,純函數式,線程安全。

2.2 `updateCompletionItems(input, event)` — 核心觸發器

  • 參數:`input` = 輸入框 DOM 元素 (JSF 傳入 `this`),`event` = 原生 `keyup` 事件對象。
  • 防抖:`clearTimeout` + `setTimeout(350ms)` — 用戶連續輸入時合併請求,避免洪峰。
  • Ajax 參數:
    • `render`:列表框 `clientId` (由 `getListboxId` 計算) — **局部渲染關鍵**。
    • `x`, `y`:輸入框頁面絕對座標 — 用於 Java 端 `setListboxStyle` 定位列表框 (絕對定位)。
  • 錯誤處理:`jsf.ajax.addOnError` 註冊全局回調,彈窗提示 (生產環境建議改為 Toast/日誌)。

2.3 `inputLostFocus(input)` — 失焦隱藏

  • 使用 Prototype 庫的 `Element.hide(id)` 隱藏列表框。
  • 200ms 延遲:關鍵設計 — 用戶點擊列表項時,`mousedown` → `click` → `valueChangeEvent` 需時間,**若立即隱藏列表框會導致點擊事件丟失**。200ms 覆蓋大多數瀏覽器事件延遲。

2.4 `getListboxId(input)` — ClientId 推導算法

  • JSF 生成的 `input.name` = 完整 `clientId` (如 `formId:autoCompleteId:input`)。
  • 算法:截取最後一個 `:` 前的前綴 + `:listbox` → `formId:autoCompleteId:listbox`。
  • 依賴復合組件固定的 `id="input"` 和 `id="listbox"` 約定,**零配置**。

3. JSF 2 Ajax 引擎關鍵點

特性說明
`jsf.ajax.request(source, event, options)`核心入口。`options.render` 指定需局部更新的 clientId 列表 (空格分隔)。
`jsf.ajax.addOnError(fn)`全局 Ajax 錯誤回調,參數 `data` 含 `description`、`responseText`、`status`。
`jsf.ajax.addOnEvent(fn)`全局 Ajax 事件回調 (begin/complete/success),可用於 Loading 指示器。
執行階段預設 `execute="@this"` (僅提交觸發組件),可覆蓋 `execute="@form"` 等。
渲染階段`render` 指定的 clientId 組件將重新渲染,替換 DOM 中對應節點。
參數傳遞`options` 中除 `execute`/`render`/`delay`/`event` 外的鍵值對,作為**請求參數**發送到服務端 (如 `x`, `y`)。

4. 依賴庫說明

  • 代碼使用 `Element.cumulativeOffset`、`Element.getHeight`、`Element.hide` — 來自 **Prototype.js 1.6+**。
  • JSF 2 (Mojarra/MyFaces) 運行時**不內置 Prototype**,需專案自行引入 (或改用原生 DOM API / jQuery)。
  • 現代化替代:原生 `input.getBoundingClientRect()` 獲取座標,`element.style.display='none'` 隱藏,移除 Prototype 依賴。

5. 生產化改進建議

  1. 移除 Prototype 依賴:全原生 DOM API,減少 30KB+ 體積。
  2. 防抖配置化:`data-debounce-ms` 屬性傳遞到 JS。
  3. 錯誤處理 UI 組件化:集成 Toast/Notification 庫,避免 `alert()` 阻塞主線程。
  4. 請求取消:`AbortController` (Fetch) 或 `XMLHttpRequest.abort()` 配合 JSF Ajax 难度較大,可考慮 `jsf.ajax.request` 返回的 `xhr` 對象 (Mojarra 專有)。
  5. TypeScript 重寫:類型安全、IDE 提示、編譯時檢查。

結語

`autoComplete.js` 體現了 JSF 2 **「薄客戶端、厚服務端、標準化 Ajax」** 的設計哲學:JS 僅處理瀏覽器原生交互 (事件、座標、防抖),業務邏輯 (過濾、狀態) 完全在 Java 端監聽器實現。這種關注點分離極大降低了前端複雜度,同時保證了組件的可測試性、可維護性、安全性。下篇將解析 Java 端監聽器 `AutocompleteListener` 的完整實現。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved