Javascript 事件侦听子级或父级以响应兄弟级的更改
我已经创建了这个非常常见的菜单链接场景,它是一种原生的vanilla JS web组件格式Javascript 事件侦听子级或父级以响应兄弟级的更改,javascript,html,dom-events,web-component,native-web-component,Javascript,Html,Dom Events,Web Component,Native Web Component,我已经创建了这个非常常见的菜单链接场景,它是一种原生的vanilla JS web组件格式 <side-nav> <nav-item id="1">1</nav-item> <nav-item id="2">2</nav-item> <nav-item id="3">3</nav-item> <nav-item id="4">4</nav-item> <
<side-nav>
<nav-item id="1">1</nav-item>
<nav-item id="2">2</nav-item>
<nav-item id="3">3</nav-item>
<nav-item id="4">4</nav-item>
</side-nav>
和父项的代码
方法2:
完全忽略父级,仅在
这两种方法都很好,但就我个人而言,在考虑良好的编程实践和性能时,我无法确定哪种方法更好
我有一个普遍的概念,孩子不应该知道兄弟姐妹或父母,但父母应该管理孩子。我对这里的最佳实践有点模糊,我很想让大家了解。如果这是一组标准组件,请像您那样思考。大多数标准组件对任何其他组件都一无所知。因此,父组件的工作是侦听子组件的事件,并根据需要对所有子组件进行更改 唯一的奇数球组件是具有
for
属性的组件。将for
属性设置为单击
时将接收焦点的组件的id
。具有单击事件处理程序的标签,如果有for
属性,它将查找具有该id的组件。如果找到该组件,则调用该组件上的.focus()
函数
这样,您的组件就不会绑在一起,而是可以连接在一起
如果我在写代码,我会用第一种方法来做。我更喜欢你的第一种选择。这有点类似于,在父级“选择”中集中处理“选项”的单击事件。第二个解决方案非常脏。还要注意,在解决方案1中,您可以使用标准的单击事件来管理选择,这取决于用例。在我看来,当您需要嵌套的
菜单时,方法2(经过一些清理)会更容易。注意:classList有一个toggle方法和一个toggleAttribute方法元素
async connectedCallback() {
this.addEventListener('click' , (event) => {
this.setAttribute('selected', true);// immediately mark current component selected
this.dispatchEvent(new CustomEvent('navitem-selected', { bubbles: true, composed: true , detail: { id: this.id} })); // dispatch event, so that parent can loop and deselect other items
});
}
async connectedCallback() {
this.addEventListener('navitem-selected', (event) => {
let items = this.shadowRoot.querySelector('slot').assignedElements();
items.forEach((item) => {
if(item.getAttribute('id') !== event.detail.id) {
item.removeAttribute('selected');
}
});
});
}
static get observedAttributes() {
return ['id', 'selected'];
}
attributeChangedCallback(name, oldValue, newValue) {
if(name == 'id'){
this.id = newValue;
}
if(name == 'selected')
{
if(newValue){
this.shadowRoot.querySelector('.root').classList.add('selected');
} else {
this.shadowRoot.querySelector('.root').classList.remove('selected');
}
}
}
async connectedCallback() {
this.addEventListener('click' , (event) => {
this.dispatchEvent(new CustomEvent('navitem-selected', { bubbles: true, composed: true , detail: { id: this.id} }));
});
const hostNode = this.shadowRoot.querySelector('.root').getRootNode().host.parentNode;
hostNode.addEventListener('navitem-selected', (event) => {
if(this.id == event.detail.id){
this.setAttribute('selected', true);
} else if(this.hasAttribute('selected')){
this.removeAttribute('selected');
}
});
}