大道至简,新一代企业应用无栈开发

平台之上,一种语言,可视化、脚本化、全端一体化开发

事件机制

前端事件触发和处理机制

docutils document without title

通过事件机制,来实现前后端通讯,同时减少组件、平台、应用之间的耦合。

1   事件触发 trigger

全局事件常用于通知站点内容发生变化,相关的UI需要同步更新。

1.1   触发组件事件

view.select('xxx').trigger(event_name, data={'uids':[122]})

1.2   触发全局事件

全局事件是平台自身的一些标准事件,比如事件 dataitem-modified , 附带uid/title参数:

view.trigger('dataitem-modified', data={'uid':12312, 'title':'123123'})

1.3   触发远端全局事件

可通过通讯频道,将事件传输到指定人员的远端界面。

如果自己给自己触发事件,可以进行多端状态同步。 比如文档一旦修改,正在在预览这个文件界面,都需要刷新。

先找到指定用户的私人通讯频道:

channel = root.messenger.get_private_channel(request.me.id)

触发一个 file-content-modified 事件:

channel.trigger(
    'file-content-modified',  # 事件名
    data={'uids': [123]}  # 事件数据
)

这个事件触发和在指定用户前端执行下面语句是等价的:

view.trigger('file-content-modified', data={'uid':[123]})

2   事件处理

2.1   组件的事件处理 on

组件包括 内置组件、嵌入式组件、载入式组件。

链接、按钮等都有click事件,表单则有submit事件这些都是由交互触发。

可在定义组件的时候,设置处理:

ui.link(...).on('click', context, request, 'xxx.xxx:xxx')

也可以之后动态绑定:

view.select('#xxxx').on(event_name, context, request, 'xxx.xxx:xx', **kw)

2.2   全局事件的处理 on/off/off_on

首先需要在网页上设置事件处理方法:

view.on('dataitem-modified', context, request, "xxx.xxx:xxx", condition_={})

注意,上面这个用法,通常是错的。因为如果页面发生变化,就不再希望处理事件,还需要手工注销:

view.off('dataitem-change', context, request, "zopen.test:refresh", condition_={})

全局事件销毁处理相当繁琐。off_on 可将事件和一个节点绑定,当这个节点删除,自动注销事件:

view.find('#test').off_on('dataitem-modified', context, request, "xxx.xxx:xxx", condition_={})

2.3   捕获条件 condition_

可以增加一个事件处理请求的调用条件,这个条件是事件参数:

view.find('#test').off_on('dataitem-modified', context, request, "xxx.xxx:xxx", condition_={'uids':['1232121']})

2.4   事件参数传递 event_

这个事件处理脚本,会额外传递一个 event_=None 参数,这个参数用于传递事件的数据,是一个json字符串,形式为:

{'event':'click',
 'data':{'key':12} # data数据
}

3   事件参考

3.1   内置组件事件

具体包括如下事件:

3.1.1   点击事件 click

用户点击链接、按钮、文本、段落等,都会触发click事件。

点击链接,会向后端发起ajax请求,调用其他的脚本,并传递参数:

link.on('click', context, request, 'zopen.sales:test', param1='xx', param2='xxx')

3.1.2   表单提交 submit

提交一个表单的时候触发submit事件,表单的所有信息会进入request.form。

3.1.3   输入变更 change

各种输入框、下拉选择,发生变化的时候,触发这个事件

会传递变更之后的 value

3.1.4   失去焦点 blur

输入组件一旦失去焦点,可能表示输入完成了。

会传递当时的输入value

3.1.5   展开事件expand

一些可展开的组件,会触发这个事件

3.1.6   拖放事件 drop

拖放完成触发drop事件,会传递推拽对象附加的data信息。

任何一个对象都可以变成可拖动Dag的,附加上data信息:

ui.link('aa').draggable(data={'uid':13123})

任何一个对象都可接受放置事件:

ui.text_area('bb', id="tt").on('drop', context, request, 'zopen.tests:on_drop')

发生drop事件,会请求远端地址,并传入拖动对象的data信息

也可以这样:

view.select('#tt').on('drop', context, request, 'zopen.tests:on_drop')

3.1.7   输入框键盘事件 keydown

当用户敲击某些按键的时候触发,会提交表单信息:

ui.text_area('vv').on('keydown', context, request, 'zopen.tests:on_enter',
         conditions_={'key':['ctrl:83', 'command:45', 'shift:47', 'alt:44', '84']})

可以在 request['event_'] 得到事件的信息,这是应该json:

{'event':'keydown',
'key':''
}

下面过时:

这时候,会自动提交所在的表单,得到表单提交的内容::

  button, errors, result = form.get_submitted(request.form)

返回的button的形式为: "keydown_46",固定 ``keydown_`` 为前缀, 46是key的值。

3.1.8   排序事件 sort

ui.list_group如果允许排序,会触发这个事件。sort事件会传递:

  • value: 排序之后的id清单

对于2组链接,link2支持拖放:

links = [ui.link('item %s' % x, id="item-%s" % x) for x in range(1, 6)]
links2 = [ui.link('item %s' % x, id="item-%s" % x).draggable(sort_group='xxxx')) for x in range(1, 6)]

list_group可以拖放排序,sort_group名字相同的可以相互拖放排序:

ui.layout()\
    .add(ui.list_group(*links)
        .on('sort', context, request, 'zopen.tests:kss_sort').sort_group('sort-groups'), width=3)\
    .add(ui.list_group(*links)
        .on('sort', context, request, 'zopen.tests:kss_sort').sort_group('sort-groups'), width=3)

如果一个可拖拽,另外一个排序:

ui.layout()\
    .add(ui.list_group(*links2), 3)\
    .add(ui.list_group(*links').on('sort', context, request, 'zopen.tests:kss_sort').sort_group('xxxx'), width=3)

3.1.9   调整grid表头 change-header-width

ui.grid 更改表头时候触发,这个事件会向后端传递如下参数:

{
    "value": [10, 30, 50, 75, 25] // 各列宽值
}

3.2   数据相关的全局事件

3.2.1   file-added: 新增文件

  • 参数 uids : 新增文件的uid集合

3.2.2   file-metadata-modified: 文件属性修改

如标题、标签、状态等

  • 参数 uids : uid集合

3.2.3   file-content-modified: 文件内容修改

文件内容发生变更,在进行外部编辑和在线编辑的过程中,用户保存文件会触发这个事件,携带以下数据:

{
    "uids": [123]
}
  • 参数 uids : 发生变化的uid数据集合

3.2.4   file-removed: 文件被删除

  • 参数 uids : uid集合

3.2.5   dataitem-added: 增加表单数据

  • 视图 @@datamanager.add 会触发
  • 参数 uids : 新增表单的uid集合
  • 参数 container_uids : 新增表单所在的容器

3.2.6   dataitem-removed: 删除表单数据

  • 视图 @@simple-preview 会触发
  • 参数 uids : 删除表单的uid集合

3.2.7   dataitem-modified: 表单修改

  • 视图 @@simple-preview 会触发
  • 参数 uids : 修改表单的uid集合

3.2.8   workitem-modified: 工作项变化

参数:

  • dataitem_uid :所属的表单

3.2.9   refresh-folder

请求刷新文件夹视图界面。桌面助手在上传完文件后会触发此事件,携带以下数据:

{
    "uids": [124]
}

3.3   交互相关的全局事件

3.3.1   站点idle事件

设置idle时间60秒:

view.set_idle(60)

关闭idle:

view.set_idle(0)

设置idle事件处理:

view.on('idle', context, request, 'zopen.test:process_idle')

3.4   通讯相关的全局事件

底层通讯相关的内置事件

3.4.1   rtc:new_login

有新客户端登录时触发,并携带服务端发送的消息数据

3.4.2   rtc:refused

消息连接被服务端拒绝,携带数据:

{
    "reason": "被拒绝的原因,可能是 license_expired / count_exceeded"
}

失败的原因如下:

  • license_expired 站点许可过期
  • count_exceeded 当前同时在线人数已经达到许可允许的最大并发数

3.4.3   rtc:disconnected

长连接已经断开

3.4.4   rtc:connected

长连接已经建立

3.4.5   rtc:failed

消息连接失败

3.5   消息客户端的全局事件

3.5.1   message:update_unreads

客户端上线后会主动查询一次未读消息情况,这个事件表明查询完成,并会携带以下数据:

{
    "channel_type": "notify",
    "unreads": [
        {
            "count": 1,
            "time_start": 1499334070.796577,
            "channel_name": "announcement<>users.admin"
        }
    ]
}

3.5.2   message:client_inited

消息客户端初始化完毕,并已开始连接

3.5.3   message:inited

消息依赖的相关库已经加载完毕