San*_*eep 4 html javascript web-component custom-element native-web-component
我正在尝试为我的UI项目之一使用本机Web组件,并且对于此项目,我没有使用任何框架或库(例如Polymer等)。我想知道在两者之间有什么最佳的交流方式或其他方式像我们在angularjs / angular中所做的那样的Web组件(例如消息总线概念)。
当前,在UI Web组件中,我正在使用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);});
Run Code Online (Sandbox Code Playgroud)
请让我知道实现此目的的其他方法。任何可以轻松与本机UI Web组件集成的优秀库,如postaljs等。
对于其他两个答案+1,事件是最好的,因为组件是松散耦合的
另请参阅:https://pm.dartus.fr/blog/a-complete-guide-on-shadow-dom-and-event-propagation/
请注意,在detail自定义事件中,您可以发送任何您想要的内容。
所以我使用(伪代码):
定义纸牌/空当接龙游戏的元素:
-> game Element
-> pile Element
-> slot Element
-> card element
-> pile Element
-> slot Element
-> empty
Run Code Online (Sandbox Code Playgroud)
当一张牌(由用户拖动)需要移动到另一堆时,
它发送一个事件(将 DOM 冒泡到游戏元素)
//triggered by .dragend Event
card.say(___FINDSLOT___, {
id,
reply: slot => card.move(slot)
});
Run Code Online (Sandbox Code Playgroud)
注: reply是函数定义
因为所有的桩都被告知要监听___FINDSLOT___游戏元素中的事件......
pile.on(game, ___FINDSLOT___, evt => {
let foundslot = pile.free(evt.detail.id);
if (foundslot.length) evt.detail.reply(foundslot[0]);
});
Run Code Online (Sandbox Code Playgroud)
只有一堆匹配的evt.detail.id响应:
!!!通过执行card发送的函数evt.detail.reply
并获取技术信息:该函数在pile范围内执行!
(以上代码为伪代码!)
可能看起来很复杂;
重要的部分是pile元素没有耦合到元素.move()中的方法card。
唯一的耦合是事件的名称:___FINDSLOT___ !!!
这意味着card始终处于控制之中,并且相同的事件(名称)可用于:
pile构成葫芦?在我的 E-lements 代码中,两者都pile没有耦合evt.detail.id,
CustomEvents仅发送函数
.say()和是.on()我的自定义方法(在每个元素上)dispatchEventaddEventListener
我现在有一些电子元素可以用来创建任何纸牌游戏
不需要任何库,编写您自己的“消息总线”
我的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));
},
Run Code Online (Sandbox Code Playgroud)
.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));
},
Run Code Online (Sandbox Code Playgroud)
在您的父代码 (html/css) 中,您应该订阅由执行其方法<chat-form>发出的事件并发送事件数据<chat-history>(add在下面的工作示例中)
// WEB COMPONENT 1: chat-form
customElements.define('chat-form', class extends HTMLElement {
connectedCallback() {
this.innerHTML = `Form<br><input id="msg" value="abc"/>
<button id="btn">send</button>`;
btn.onclick = () => {
// can: this.onsend() or not recommended: eval(this.getAttribute('onsend'))
this.dispatchEvent(new CustomEvent('send',{detail: {message: msg.value} }))
msg.value = '';
}
}
})
// WEB COMPONENT 2: chat-history
customElements.define('chat-history', class extends HTMLElement {
add(msg) {
let s = ""
this.messages = [...(this.messages || []), msg];
for (let m of this.messages) s += `<li>${m}</li>`
this.innerHTML = `<div><br>History<ul>${s}</ul></div>`
}
})
// -----------------
// PARENT CODE
// which subscribe chat-form send event,
// receive message and set it to chat-history
// -----------------
myChatForm.addEventListener('send', e => {
myChatHistory.add(e.detail.message)
});Run Code Online (Sandbox Code Playgroud)
body {background: white}Run Code Online (Sandbox Code Playgroud)
<h3>Hello!</h3>
<chat-form id="myChatForm"></chat-form>
<div>Type something</div>
<chat-history id="myChatHistory"></chat-history>Run Code Online (Sandbox Code Playgroud)
如果您将Web组件视为内置组件之类<div>,<audio>则可以回答自己的问题。这些组件不会互相通信。
一旦开始允许组件彼此直接通信,那么您实际上就没有真正拥有绑定在一起的系统的组件,没有组件B就无法使用组件A。这太紧密地绑在一起了。
而是在拥有两个组件的父代码中添加代码,以使您能够接收来自组件A的事件并调用函数或在组件B中设置参数,反之亦然。
话虽如此,内置组件对此规则有两个例外:
该<label>标签:它使用for属性采取另一个组件的ID,如果设置和有效的,那么它通过专注于其他组件时,你点击<label>
该<form>标签:这看起来对于那些孩子们聚集在一起,发布形式所需要的数据表单元素。
但是,这两者仍然没有束缚。在<label>被告知的收件人focus时,只将它传递如果ID设置和有效或第一成形件作为一个孩子。而且,该<form>元素并不关心存在哪些子元素,或者仅通过其所有后代而找到多少子元素,这些子元素即为表单元素并获取其value属性。
但是通常,您应该避免让一个同级组件直接与另一同级对话。上面两个示例中的交叉通信方法可能是唯一的例外。
相反,您的父代码应侦听事件并调用函数或设置属性。
是的,您可以将该功能包装在一个新的父组件中,但是请您节省很多时间并避免使用意大利面条式的代码。
通常,我绝不允许兄弟姐妹之间互相交谈,而他们与父母交谈的唯一方法是通过事件。父母可以通过属性,属性和功能直接与子女交谈。但是在所有其他情况下都应避免使用它。
| 归档时间: |
|
| 查看次数: |
777 次 |
| 最近记录: |