同意其他两个答案,事件是最好的,因为这样组件之间的耦合性较弱。
另请参阅:https://pm.dartus.fr/blog/a-complete-guide-on-shadow-dom-and-event-propagation/
请注意,在自定义事件的 detail
中,您可以发送任何内容。
基于事件驱动的函数执行:
因此,我使用(伪代码):
定义纸牌游戏 Solitaire/Freecell 的元素:
-> game Element
-> pile Element
-> slot Element
-> card element
-> pile Element
-> slot Element
-> empty
当用户需要移动卡片到另一个牌堆时,它会发送一个事件(通过DOM冒泡到游戏元素)。
//triggered by .dragend Event
card.say(___FINDSLOT___, {
id,
reply: slot => card.move(slot)
});
注意:reply
是一个函数定义
因为所有的堆栈都被告知在游戏元素上监听___FINDSLOT___
事件...
pile.on(game, ___FINDSLOT___, evt => {
let foundslot = pile.free(evt.detail.id);
if (foundslot.length) evt.detail.reply(foundslot[0]);
});
只有一个与
evt.detail.id
匹配的堆会做出反应:
通过执行在
evt.detail.reply
中发送的函数
card
,来实现!!!
技术方面:该函数在
pile
范围内执行!
(上述代码是伪代码!)
为什么?!
看起来可能很复杂;
重要的是:
pile
元素与
card
元素中的
.move()
方法
没有耦合。
唯一的耦合是事件名称:
___FINDSLOT___
!!!
这意味着
card
始终控制,并且
相同的事件(名称)可用于:
- 卡牌可以走到哪里?
- 什么是最佳位置?
- 在
河流堆
中,哪张牌组成了Full-House?
- ...
在我的E-ments代码中,
pile
也没有与
evt.detail.id
耦合,
CustomEvents只发送函数
.say()
和
.on()
是我自定义方法(每个元素都有),用于
dispatchEvent
和
addEventListener
现在我有了一些可以用来创建任何纸牌游戏的E-lements
不需要任何库,编写自己的
“消息总线”
我的
element.on()
方法只是几行代码包装在
addEventListener
函数周围,因此它们可以轻松删除:
$Element_addEventListener(
name,
func,
options = {}
) {
let BigBrotherFunc = evt => {
if (evt.detail && evt.detail.reply) {
el.warn(`can catch ALL replies '${evt.type}' here`, evt);
}
func(evt);
}
el.addEventListener(name, BigBrotherFunc, options);
return [name, () => el.removeEventListener(name, BigBrotherFunc)];
},
on(
) {
let args = [...arguments];
let target = el;
if (args[0] instanceof HTMLElement) target = args.shift();
args[0] = ___eventName(args[0]) || args[0];
$Element_ListenersArray.push(target.$Element_addEventListener(...args));
},
.say( )
是一个单行命令:
say(
eventNR,
detail,
options = {
detail,
bubbles: 1, // event bubbles UP the DOM
composed: 1, // !!! required so Event bubbles through the shadowDOM boundaries
}
) {
el.dispatchEvent(new CustomEvent(___eventName(eventNR) || eventNR, options));
},