我以原生 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>
自然,当我单击任何导航项时,我需要
- 使单击的项目处于活动状态/选中状态
- 检查是否有另一个项目已经处于活动状态,如果有,则使该导航项目处于非活动状态
使用 web 组件,我观察到我可以通过两种方式处理它。
方法一:
<nav-item>
当被点击时发送一个事件- 在父节点上添加事件监听器
<side-nav>
- 在每个点击事件上,循环遍历 side-nav 的所有子组件,如果它不是 event.target 节点,则
<nav-item>
停用已经激活的组件。<nav-item>
代码<nav-item>
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
});
}
和父母的代码<side-nav>
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');
}
});
});
}
方法二:
完全忽略父级并仅在<nav-item>
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');
}
});
}
两种方法都可以正常工作,但对于我的生活,在考虑良好的编程实践和性能时,我无法弄清楚哪一种更好。
我有一个普遍的概念,孩子不应该知道兄弟姐妹或父母,但父母应该管孩子。我对这里的最佳实践有点模糊,很想被曝光。