iT邦幫忙

2021 iThome 鐵人賽

DAY 27
1
Modern Web

ZK 30天速成系列 第 27

當執行一個耗時較久動作時,提供良好的使用者體驗

你我應該都有類似的不佳體驗:點下一個按鈕時,畫面什麼也沒有改變,你以為剛剛沒點到,又再點了一次,發現還是沒反應,開始感到有點生氣。接下來的動作因人而異,可能會重載畫面、繼續等下去、打給客服、發出某種四聲的單詞...正在考慮的時候,這時候畫面突然通知你:「你的XX已經完成」。這時突然有一種「莊孝維...」,剛剛我是被耍了嗎...的感覺。

雖然只是缺少一個小小的「忙碌中」訊息提示,但是卻可能造成系統很大影響,例如因為沒回應,很多人會多點一次,而這種耗時的動作通常比較消耗系統資源(消耗較多計算力或記憶體),每個人都多點一次反而造成系統更慢、更無法回應。另一種等不及的人總是會重載畫面,可能兩次之後就放棄你的程式,或是打爆客服的電話,增加額外的處理成本。

預設忙碌訊息

為了避免使用者這種不好的感覺,ZK 預設內建「請等待」訊息。當元件送出的 AJAX request 在 900ms 內沒有收到回應,就會自動根據瀏覽器語言顯示一個「處理中」訊息,並配有轉圈圈動畫。

https://ithelp.ithome.com.tw/upload/images/20211012/20050621pzKTzXVh53.jpg

這個行為不需要任何設定,只要你傾聽器程式在伺服器端執行過久,讓瀏覽器等超過 900ms,ZK 就會幫你在左上角顯示這個訊息,給予使用者明確的回饋。

    <button label="耗時動作" onClick="doLongOperation()"/>
    <zscript><![CDATA[
public doLongOperation(){
    org.zkoss.lang.Threads.sleep(3000); //模擬一個耗時的動作
}
    ]]></zscript>

如果你認為你的網路環境較慢,可以在 zk.xml 調整預設等待時間,請看 The processing-prompt-delay Element

如果你覺得忙碌訊息不要在左上角,也可以設定調整位置,請看 org.zkoss.zul.progressbox.position

如果你希望不只顯示訊息而是要遮罩著整個畫面,以免使用者再點其他的按鈕,可啟用設定:org.zkoss.zk.ui.processMask.enabled

如果你想要顯示別的訊息,可覆寫以下 js 變數:

<script defer="true"><![CDATA[
msgzk.PLEASE_WAIT = "進行中";
]]></script>

請參考 ZK_Developer's_Reference/Internationalization/Warning_and_Error_Messages

自訂忙碌效果

你也許覺得只顯示「處理中」有點無趣,希望能能更大幅度的變化 UI 來顯示進行中。例如原本是這樣:

https://ithelp.ithome.com.tw/upload/images/20211012/20050621imqsmXFJOj.jpg

當按下按鈕之後會變色且文字改變:

https://ithelp.ithome.com.tw/upload/images/20211012/20050621Eg8JkGt3CC.jpg

初步你會把按鈕變色與耗時動作寫在同一個 onClick listener:

button.addSclass("busy");
button.setLabel("進行中...");
doLongOperation();

但你會發現耗時動作做完了才變色。因為點下按鈕後,送出AU request 並等待 listener 執行完回來,才能取得元件對 js widget 的更新,這樣就無法在進行耗時動作前就變色,因此要分成兩個 listener:

  1. 先按鈕變色
  2. 再執行耗時動作

但豈不是要按兩次按鈕去呼叫兩次 listener,多奇怪啊! 因此有一個方法可以在第一個 listener 中呼叫第二個 listener 的方法: Echo event:

https://ithelp.ithome.com.tw/upload/images/20211012/20050621LWDojDV0wJ.jpg

  • 當你在第一個 listener 中發出一個自訂事件名稱的 echo event,等 AU response 回到 client 端,ZK 會從瀏覽器發出一個該自訂事件到伺服器端
  • 該自訂事件就會呼叫你註冊的第二個 listener,通常用來執行耗時動作

細部流程如下:

  1. 按下按鈕,呼叫 onClick listener,變按鈕顏色、文字
  2. 發出 echo event, onLongOperation (這個事件名稱可自訂)
  3. ZK client 呼叫 onLongOperation listener

程式碼如下:

<button label="送出" autodisable="self" >
    <attribute name="onClick">
        self.addSclass("busy");
        self.setLabel("進行中...");
        Events.echoEvent("onLongOperation", self, null); //送出一個自訂 echo event
    </attribute>
    <attribute name="onLongOperation">
        doLongOperation();
        self.removeSclass("busy");
        self.setLabel("送出");
    </attribute>
</button>
<zscript><![CDATA[
public doLongOperation(){
    org.zkoss.lang.Threads.sleep(3000); //模擬一個耗時的動作
}
    ]]></zscript>
    <style>
        .busy{
            background-color: orange;
        }
    </style>
  • 本例中我將 echo event 仍是送到 button 上,因此 onLongOperation listener 也註冊在 button 上。有時候也可以送到別的元件上。

上一篇
效能分析除錯方法
下一篇
讓伺服器主動更新畫面
系列文
ZK 30天速成30

1 則留言

0
juck30808
iT邦新手 3 級 ‧ 2021-10-12 18:27:41

第27天了! 恭喜即將完賽 (拍手!!!

Hawk iT邦新手 4 級 ‧ 2021-10-12 21:50:37 檢舉

感謝你的鼓勵 :)

我要留言

立即登入留言