事件机制
前端事件触发和处理机制
通过事件机制,来实现前后端通讯,同时减少组件、平台、应用之间的耦合。
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.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.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.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
消息依赖的相关库已经加载完毕