当执行一个耗时较久动作时,提供良好的使用者体验

你我应该都有类似的不佳体验:点下一个按钮时,画面什麽也没有改变,你以为刚刚没点到,又再点了一次,发现还是没反应,开始感到有点生气。接下来的动作因人而异,可能会重载画面、继续等下去、打给客服、发出某种四声的单词...正在考虑的时候,这时候画面突然通知你:「你的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 上。有时候也可以送到别的元件上。

<<:  那些被忽略但很好用的 Web API / Share

>>:  Day27 Let's ODOO: Backup

Day 25 bert 文字情感分类-4

接续昨天的结果,范例程序码的其他部分可以不做更动, 或是把一些测试用的区段改成中文以确认编码是否成功...

Day9 - 串接 LINE Login 与 LIFF

Heroku 网址:https://www.heroku.com/ LINE Developers...

Day 26 Wireless Attacks - 无线攻击 (aircrack-ng)

前言 终於进入新的篇章06-Wireless Attacks,但由於先前的Kali虚拟机环境无法进行...

【Day32】[演算法]-内插搜寻法Interpolation Search

内插搜寻法(Interpolation Search  ),又称插补搜寻法,是二分搜寻法的改良版,二...

浮点数的二进位表达方法

浮点数的二进位表达方法 浮点运算知识点 小数二进制表达 与整数的二进制表达相同我们可以假设任意小数的...