2.3.7 事件
ThingJS 系统内置了很多事件,如鼠标点击、键盘输入、层级变化等。用户可以监听这些事件,在事件回调中进行相应的业务逻辑处理。
绑定事件
全局绑定事件和局部绑定事件
用户的操作以及场景的变化,都会触发相应的事件。你可以监听这些事件,然后在回调方法中做相应的处理,通过 on() 方法绑定事件。
全局绑定:通过 app.on() 绑定事件,可在全局下添加条件指定针对哪些物体绑定该事件,条件规则同于 query 使用的条件。
// 绑定事件
app.on("click", function(ev) {
console.log("you click!");
});
注意事项
在全局绑定后,新创建的符合条件物体也可以生效。
局部绑定:针对一个对象,或者 query 的查询结果(Selector),通过 on 接口绑定事件,我们叫局部绑定。同全局绑定,事件中可以加条件,表示这个事件绑定是针对集合中的所有物体的。
obj.on("click", function(ev) {
console.log(ev.object.name);
});
应用示例
在下面的章节中,将详细介绍事件的常用方法
绑定事件并添加条件
事件添加了条件,只有在符合该条件的物体上 click 才会触发,无论是已经存在的 Thing 对象,还是后面新创建的 Thing 对象都会生效。
app.on("click", ".Thing", function(ev) {
console.log("you click " + ev.object.id);
});
obj.on("click", ".Marker", function(ev) {
console.log(ev.object.name);
});
上面的例子,当这个物体子孙里有 Marker 物体,当它被点击就会触发。同全局绑定 Marker 物体,绑定后 obj 的子孙里新创建的 Marker 也响应这个事件。
同一个事件注册多个回调
试想一下,如果我们有一个模块在物体 click 时,改变物体颜色,另外一个模块需要在物体 click 时,放大物体。两个模块又是不同人写的,那该如何注册事件呢?
// 事件1:
obj.on("click", function(ev) {
ev.object.style.color = "#FF0000";
});
// 事件2:
obj.on("click", function(ev) {
ev.object.scale = [2, 2, 2];
});
// 卸载 obj 全部的 click 事件
obj.off("click");
这两个事件,都会在 obj 被点击后触发。但使用 off() 卸载事件时,两个事件都会同时被卸载。因此我们更推荐使用[tag]的方式。
tag 标签
如果取消或者暂停事件,都要知道原回调函数,在大部分时候会比较麻烦,我们可以给每个事件打上 tag,在删除或者暂停时,可用 tag 直接指定你要操作的回调。
//模块1中:
obj.on("click",function(ev) {
ev.object.style.color = "#FF0000";
},"模块1");
//模块2中:
obj.on("click",function(ev) {
ev.object.scale = [2, 2, 2];
},"模块2");
//取消"模块1"的事件回调,不影响“模块2”的回调
obj.off("click",null ,"模块1");
设置事件优先级
两个都是 click 事件,如果我们希望保证模块 2 的事件先于模块 1 触发,则需要添加一个参数 priority
,一般事件默认的优先级是 50,设置的越大,越优先触发。
//模块1:
obj.on("click",function(ev) {
ev.object.style.color = "#FF0000";
},"模块1");
//模块2:
obj.on("click",function(ev) {
ev.object.scale = [2, 2, 2];
},"模块2",51);
注册单次事件
如果需要一个事件只执行一次,就需要卸载掉,你可以使用 one 这个接口代替 on,参数和 on 是一样的。但是,如下情况需要注意:
我们提供 priority 的能力:
// 下例中是给每个楼层的注册了一次 EnterLevel 事件,即 每个楼层第一次进入时 都会响应
app.one(THING.EventType.EnterLevel, '.Floor', function (ev) {
console.log(ev.object.id);
})
// 如果只给某个楼层注册 如下
var floor = app.query('.Floor')[0];
floor.one(THING.EventType.EnterLevel, function (ev) {
console.log(ev.object.id);
})
卸载事件
当我们想卸载一个事件的时候使用 off() 方法。
app.on("click", function(event) {
console.log("you click!");
});
// 卸载
app.off("click");
app.on("click", ".Building", function(event) {
console.log("you click!");
});
// 卸载
app.off("click", ".Building");
app.on("click",".Building",function(event) {
console.log("you click 1 !");
},"tag1");
// 卸载
app.off("click", ".Building", "tag1");
注意事项
若绑定事件时,添加了条件,则off 第二个参数必须传条件,如果没有条件,又需要传 tag ,需要将条件传 null。
暂停和恢复事件
如果off
掉一个事件,要想恢复,有时候比较难,你找不到之前的回调方法了。面对这种情况,我们提供 pauseEvent
方法,用于暂停事件,它的控制方法和标准类似于 off。
app.on("click",".Building",function(event) {
console.log("you click!");
},"tag1");
// 暂停
app.pauseEvent("click", ".Building", "tag1");
// 恢复
app.resumeEvent("click", ".Building", "tag1");
自定义事件
ThingJS 内置了很多事件,但如果自己写模块的时候,也需要触发事件,该如何操作?外部注册还是使用 on,在需要触发的地方我们使用 trigger 接口来对外触发事件。
比如你在写一个报警管理器:
class AlamrManager {
constructor() {
......
}
enable() {
......
app.trigger("AlarmEnable")
......
}
setObjAlarm(obj, alarmLevel) {
......
obj.trigger("alarm", {"level":alarmLevel} )
......
}
}
外部注册如下:
app.on("AlarmEnable", function(ev){
......
})
app.query(".Thing").on("alarm",function(ev){
if(ev.level == "critical"){
......
}
......
})
参考信息
名称 | 说明 |
---|---|
Complete | 通知 App 初始化完成。 |
Update | 通知 App 更新。 |
Progress | 通知加载进度更新。 |
Load | 通知加载。 |
Click | 通知鼠标点击。 |
DBLClick | 通知鼠标双击。 |
SingleClick | 通知鼠标单击。 |
MouseMove | 通知鼠标移动。 |
MouseWheel | 通知鼠标滚轮事件。 |
MouseOver | 通知鼠标首次移入物体, 会一直传递到父物体。 |
DragStart | 通知物体拖拽开始。 |
Drag | 通知物体拖拽进行中。 |
DragEnd | 通知物体拖拽结束。 |
KeyDown | 通知键盘按键按下。 |
LevelChange | 通知场景层次发生改变。 |
EnterLevel | 通知进入物体层级。 |
LeaveLevel | 通知退出物体层级。 |
LevelFlyEnd | 通知摄像机飞入物体层级进入完成。 |
完整事件清单,参阅 ThingJS API 中的 EventType。
下一个教程中,我们来学习控件。