事件

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

下一个教程中,我们来学习控件

该文件修订时间: 2021-06-04 18:03:52

results matching ""

    No results matching ""