我正在尝试为我的一个UI项目使用本机Web组件,对于这个项目,我没有使用像Polymer这样的任何框架或库。我想知道是否有任何最佳方式或其他方式在两个之间进行通信我们在angularjs / angular中做的web组件(如消息总线概念)。
目前在UI网页组件中,我使用dispatchevent发布数据和接收数据,我正在使用addeventlistener。例如,有2个Web组件,ChatForm和ChatHistory。
// chatform webcomponent on submit text, publish chattext data
this.dispatchEvent(new CustomEvent('chatText', {detail: chattext}));
// chathistory webcomponent, receive chattext data and append it to chat list
this.chatFormEle.addEventListener('chatText', (v) => {console.log(v.detail);});
请让我知道其他方法可以用于此目的。任何像postaljs等好的库,可以轻松地与本机UI Web组件集成。
如果您将Web Components视为像<div>
和<audio>
这样的内置组件,那么您可以回答自己的问题。组件不会相互通信。
一旦你开始允许组件直接相互通信,那么你实际上没有组件,你有一个系统连接在一起,你不能使用没有组件B的组件A.这是紧密联系在一起。
相反,在拥有这两个组件的父代码中,您添加的代码允许您从组件A接收事件并调用函数或在组件B中设置参数,反之亦然。
虽然说这个规则有两个例外,内置组件:
<label>
标签:它使用for
属性来获取另一个组件的ID,如果设置且有效,那么当你点击<label>
时它会将焦点传递给另一个组件<form>
标签:这会查找作为子项的表单元素来收集发布表单所需的数据。但这两者仍然没有任何关系。 <label>
被告知focus
事件的接收者,并且只有在ID被设置和有效时才传递它,或者作为孩子传递给第一个表单元素。而<form>
元素并不关心子元素存在的是什么,或者它只是通过它的所有后代找到元素并找到它们的value
属性。
但作为一般规则,你应该避免让一个兄弟组件直接与另一个兄弟姐妹交谈。上面两个例子中的交叉通信方法可能是唯一的例外。
相反,您的父代码应该侦听事件并调用函数或设置属性。
是的,你可以将这个功能包装在一个新的父组件中,但请节省大量的悲伤并避免使用意大利面条代码。
作为一般规则,我从不允许兄弟姐妹元素彼此交谈,他们与父母交谈的唯一方式是通过事件。家长可以通过属性,属性和功能直接与孩子交谈。但是在所有其他条件下都应该避免。
其他答案都是+1,事件是最好的,因为组件松散耦合
请注意,在自定义事件的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
的一堆响应:
!通过执行card
发送的函数evt.detail.reply
并获得技术:该功能在pile
范围内执行!
(上面的代码是伪代码!)
可能看起来很复杂;
重要的是pile
元素不与.move()
元素中的card
方法耦合。
唯一的耦合是事件的名称:___FINDSLOT___
!!!
这意味着card
始终处于控制状态,并且相同的事件(名称)可用于:
pile
河中的哪张牌成为满屋?在我的E-lements代码中,pile
也没有与evt.detail.id
耦合,
CustomEvents仅发送功能
.say()
和.on()
是dispatchEvent
和addEventListener
的自定义方法(在每个元素上)
我现在有一些可用于创建任何纸牌游戏的元素
..将于本月晚些时候在GitHub上发布
抢先看:
不需要任何库,编写自己的“消息总线”
我的element.on()
方法只是围绕addEventListener
函数的几行代码,因此可以很容易地删除它们:
$Element_addEventListener(
name,
func,
options = {}
) {
let BigBrotherFunc = evt => { // wrap every Listener function
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(
//!! no parameter defintions, because function uses ...arguments
) {
let args = [...arguments]; // get arguments array
let target = el; // default target is current element
if (args[0] instanceof HTMLElement) target = args.shift(); // if first element is another element, take it out the args array
args[0] = ___eventName(args[0]) || args[0]; // proces eventNR
$Element_ListenersArray.push(target.$Element_addEventListener(...args));
},
qazxsw poi是一个单行:
.say( )
say(
eventNR,
detail, //todo some default something here ??
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));
},
如果您想处理松散耦合的自定义元素,自定义事件是最佳解决方案。
相反,如果一个自定义元素通过其引用知道另一个,它可以调用其自定义属性或方法:
Danny.say(
__NATIVE_ELEMENTS_LOVERS__,
() => mail('[email protected]' , 'Re: early access to your E-lements GitHub')
);
在上面的最后一个例子中,通过//in chatForm element
chatHistory.attachedForm = this
chatHistory.addMessage( message )
chatHistory.api.addMessage( message )
属性公开的专用对象完成通信。
您还可以使用事件(以一种方式)和方法(以其他方式)的混合,具体取决于自定义元素的链接方式。
最后,在某些消息是基本的情况下,您可以通过HTML属性进行通信(字符串)数据:
api