Javascript 如何在Web组件(本机UI)之间通信?
我尝试在我的一个UI项目中使用原生web组件,而在这个项目中,我没有使用任何框架或库,如Polymer等。我想知道是否有任何最佳方式或其他方式可以在两个web组件之间进行通信,就像我们在angularjs/angular中所做的那样(如消息总线概念) 目前在UI web组件中,我使用dispatchevent发布数据和接收数据,我使用addeventlistener。 例如,有两个web组件,ChatForm和ChatHistoryJavascript 如何在Web组件(本机UI)之间通信?,javascript,html,web-component,custom-element,native-web-component,Javascript,Html,Web Component,Custom Element,Native Web Component,我尝试在我的一个UI项目中使用原生web组件,而在这个项目中,我没有使用任何框架或库,如Polymer等。我想知道是否有任何最佳方式或其他方式可以在两个web组件之间进行通信,就像我们在angularjs/angular中所做的那样(如消息总线概念) 目前在UI web组件中,我使用dispatchevent发布数据和接收数据,我使用addeventlistener。 例如,有两个web组件,ChatForm和ChatHistory // chatform webcomponent on sub
// 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组件集成。如果要处理松散耦合的自定义元素,自定义事件是最好的解决方案 相反,如果一个自定义元素通过其引用知道另一个,则它可以调用其自定义属性或方法:
//in chatForm element
chatHistory.attachedForm = this
chatHistory.addMessage( message )
chatHistory.api.addMessage( message )
chatHistory.setAttributes( 'chat', 'active' )
chatHistory.dataset.username = `$(this.name)`
在上面的最后一个示例中,通信是通过通过api
属性公开的dedecated对象完成的
根据自定义元素的链接方式,还可以混合使用事件(一种方式)和方法(另一种方式)
最后,在一些消息是基本的情况下,您可以通过HTML属性来传递(字符串)数据:
//in chatForm element
chatHistory.attachedForm = this
chatHistory.addMessage( message )
chatHistory.api.addMessage( message )
chatHistory.setAttributes( 'chat', 'active' )
chatHistory.dataset.username = `$(this.name)`
如果您将Web组件看作是内置组件,如
和
,那么您可以回答自己的问题。这些组件彼此不通信
一旦你开始允许组件之间直接对话,那么你就没有真正的组件了。你有一个绑在一起的系统,没有组件B你就不能使用组件a。这绑得太紧了
相反,在拥有这两个组件的父代码中,您添加了允许您从组件A接收事件、在组件B中调用函数或设置参数的代码,反之亦然
尽管如此,对于内置组件,此规则有两个例外:
标记:它使用for
属性获取另一个组件的ID,如果设置且有效,则当您单击
标记:它查找作为子元素的表单元素,以收集发布表单所需的数据
被告知焦点
事件的接收者,并且仅当ID设置且有效时,才会将其传递给第一个表单元素,或者将其作为子元素传递给第一个表单元素。而
元素并不关心存在哪些子元素,也不关心有多少子元素,它只是通过其所有子元素查找构成元素的元素并获取它们的值
属性
但一般来说,您应该避免让一个同级组件直接与另一个同级组件对话。上述两个例子中的交叉通信方法可能是唯一的例外
相反,父代码应该侦听事件并调用函数或设置属性
是的,您可以将该功能包装在一个新的父组件中,但请避免太多的痛苦,避免使用意大利面代码
一般来说,我从不允许兄弟姐妹元素彼此交谈,他们与父母交谈的唯一方式是通过事件。父母可以通过属性、属性和函数直接与子女交谈。但是在所有其他情况下都应该避免这种情况。+1对于其他两种答案,事件都是最好的,因为它们的组成部分都是松散的 耦合
另见:
请注意,在自定义事件的
详细信息中,您可以发送任何想要的内容
事件驱动的函数执行:
所以我使用(psuedo代码):
定义单人纸牌/免费手机游戏的元素:
-> game Element
-> pile Element
-> slot Element
-> card element
-> pile Element
-> slot Element
-> empty
当卡片(由用户拖动)需要移动到另一堆时
它发送一个事件(将DOM冒泡到游戏元素)
注意:回复
是一个函数定义
因为所有的都在游戏元素的\uuuuuuuu FINDSLOT\uuuuuuuuuuuuuuuuu
事件中排列
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
获取技术:该函数在堆
范围内执行
(上面的代码是伪代码!)
为什么?
可能看起来很复杂
重要的部分是堆
元素与卡
元素中的.move()
方法不耦合
仅耦合是事件的名称:\uuuuuu FINDSLOT\uuuuuu
强>
这意味着卡
始终处于控制状态,同一事件(名称)可用于:
- 一张卡片可以寄到哪里
- 最好的位置是什么
- 河里的哪一张牌堆得满满的
在我的电子元件中,代码pile
也没有耦合到evt.detail.id
CustomEvents仅发送功能
.say()
和.on()
是我对dispatchEvent
和addEventListener
的自定义方法(在每个元素上)
我现在有一手电子元素,可以用来创建任何纸牌游戏
不需要任何库,编写自己的“消息总线”
我的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));
},
.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));
},
工作考试