60 lines
3.5 KiB
Plaintext
60 lines
3.5 KiB
Plaintext
// 同一托管对象系统中的事件阶段:祖先 capture → 目标 onEvent → 目标监听器 → 祖先 bubble。
|
|
// EventLog 用一个递增序列记录实际次序;改变监听器/传播标记可对比跳过与停止的语义。
|
|
// 首行仅列本例的非空阶段;额外的目标 capture、旧式 onClick 及其他祖先处理仍由通用分发器决定。
|
|
// 保存各阶段序号与最近 phase;count 是共享状态,其他字段直接写在本模型中。
|
|
class EventLog {
|
|
// count 保存跨阶段递增的总序列;四个 Step 保存各阶段最近一次序号,不是各自独立递增的计数器。
|
|
count: Object
|
|
captureStep: Number
|
|
methodStep: Number
|
|
targetStep: Number
|
|
bubbleStep: Number
|
|
phase: String
|
|
// 祖先捕获阶段先递增序列,再保存 captureStep 和 Event.phase。
|
|
function capture(self: EventLog, event: Event): Unit {
|
|
// 由 root 的 capture 连接调用,当前 event.phase 来自本次派发路径,不由业务模型自行推断。
|
|
self.count.increment()
|
|
self.captureStep = self.count.value
|
|
self.phase = event.phase
|
|
}
|
|
// 目标监听器的执行点;它排在目标类型 onEvent 方法之后。
|
|
function target(self: EventLog, event: Event): Unit {
|
|
// button 的普通连接在目标 onEvent 后调用,读取已被前面阶段推进的同一个 count。
|
|
self.count.increment()
|
|
self.targetStep = self.count.value
|
|
self.phase = event.phase
|
|
}
|
|
// 祖先冒泡阶段记录最后序号,未被 stopPropagation 时才到达。
|
|
function bubble(self: EventLog, event: Event): Unit {
|
|
// 由 root 的非捕获连接调用;本例不设置停止标记,因此点击目标后可继续冒泡到这里。
|
|
self.count.increment()
|
|
self.bubbleStep = self.count.value
|
|
self.phase = event.phase
|
|
}
|
|
}
|
|
// 覆盖目标方法,比额外 on(click,...) 监听器更早处理目标阶段事件。
|
|
class EventButton: Button {
|
|
// 原生 Button 参数之外追加模型引用,onEvent 和三个监听器共同写入该模型。
|
|
model: EventLog
|
|
// 把模型序列递增后写 methodStep,供断言与 capture/target/bubble 比较。
|
|
function onEvent(self: EventButton, event: Event): Unit {
|
|
// 分发器查找对象方法后进入这里,无需再给此方法单独注册 on 连接;方法返回后继续目标监听器。
|
|
// 本覆盖不检查 event.kind;显式 on 连接只监听 click,而该对象方法也可能处理源码派发的其他事件。
|
|
self.model.count.increment()
|
|
self.model.methodStep = self.model.count.value
|
|
self.model.phase = event.phase
|
|
}
|
|
}
|
|
model = EventLog(ui.state(0), 0, 0, 0, 0, "等待点击")
|
|
// 只在顶层创建一次日志,重复点击累计序列,四个 Step 会被各自最近一次阶段调用覆盖。
|
|
button = EventButton("捕获 → 对象方法 → 监听器 → 冒泡", model)
|
|
root = Column(24, 16, TextBlock("同一对象系统中的事件分派", 2), button, ui.textOf(model.count, "value"), ui.textOf(model, "phase"))
|
|
// capture 选项显式选择捕获;不带选项的祖先监听器默认在冒泡阶段执行。
|
|
// 返回的令牌可 disconnect,同次派发中断开尚未执行的监听器也应生效。
|
|
capture = root.on("click", model.capture, "capture")
|
|
target = button.on("click", model.target)
|
|
// root 是目标的祖先;若把监听器放在另一无关容器,它不会仅因共享 model 而加入这条传播路径。
|
|
bubble = root.on("click", model.bubble)
|
|
page = Page()
|
|
page.render(root)
|