【问题标题】:How can I call function on event listener to change class using map method如何使用 map 方法调用事件侦听器上的函数来更改类
【发布时间】:2021-03-05 11:16:31
【问题描述】:

我有两个按钮,button 1button 2 不同类别的颜色和背景颜色不同。当鼠标悬停 button 1 我希望颜色和背景颜色更改为 button 2 的颜色和背景颜色以及 button 2 更改为 按钮 1 的颜色和背景颜色。同样,当我将鼠标悬停在 按钮 2 上时,也会发生同样的情况。

所以我想出了这个解决方案,但我收到了通知

未捕获的类型错误:btn_primarys.map 不是函数

未捕获的类型错误:btn_secondarys.map 不是函数

const mouseOverBtnPrimary = () => {
    btn_primary.classList.remove("btn-primary");
    btn_primary.classList.add("btn-secondary");

    btn_secondary.classList.add("btn-primary");
    btn_secondary.classList.remove("btn-secondary");

}

const mouseOutBtnPrimary = () => {
    btn_primary.classList.add("btn-primary");
    btn_primary.classList.remove("btn-secondary");

    btn_secondary.classList.add("btn-secondary");
    btn_secondary.classList.remove("btn-primary");
}

const mouseOverBtnSecondary = () => {
    btn_secondary.classList.remove("btn-secondary");
    btn_secondary.classList.add("btn-primary");

    btn_primary.classList.add("btn-secondary");
    btn_primary.classList.remove("btn-primary");
}

const mouseOutBtnSecondary = () => {
    btn_secondary.classList.add("btn-secondary");
    btn_secondary.classList.remove("btn-primary");

    btn_primary.classList.add("btn-primary");
    btn_primary.classList.remove("btn-secondary");
}

let projectPage = document.getElementById('projectsPage');

let btn_primarys = projectPage.getElementsByClassName('btn-primary');
btn_primarys.map( btn_primary => btn_primary.addEventListener('mouseover', mouseOverBtnPrimary()));
btn_primarys.map( btn_primary => btn_primary.addEventListener('mouseout', mouseOutBtnPrimary()));


let btn_secondarys = projectPage.getElementsByClassName('btn-secondary');
btn_secondarys.map( btn_secondary => btn_secondary.addEventListener('mouseover', mouseOverBtnSecondary()));
btn_secondarys.map( btn_secondary => btn_secondary.addEventListener('mouseout', mouseOutBtnSecondary()));

【问题讨论】:

标签: javascript arrays dictionary addeventlistener


【解决方案1】:

@Християн Христов

在发布问题之前,我最初已经为两个按钮的一个实例提出了解决方案。虽然在你谈到它之前我不知道提升,但它确实有效。请参阅下面的代码。

btn_primary = document.querySelector('.btn-primary');
btn_secondary = document.querySelector('.btn-secondary');

btn_primary.addEventListener("mouseover", () => {
btn_primary.classList.remove("btn-primary");
  btn_primary.classList.add("btn-secondary");
  btn_secondary.classList.add("btn-primary");
  btn_secondary.classList.remove("btn-secondary");

});

btn_primary.addEventListener("mouseout", () => {
  btn_primary.classList.add("btn-primary");
  btn_primary.classList.remove("btn-secondary");

  btn_secondary.classList.add("btn-secondary");
  btn_secondary.classList.remove("btn-primary");
 });

 btn_secondary.addEventListener("mouseover", () => {
   btn_secondary.classList.remove("btn-secondary");
   btn_secondary.classList.add("btn-primary");

   btn_primary.classList.add("btn-secondary");
   btn_primary.classList.remove("btn-primary");

  });

  btn_secondary.addEventListener("mouseout", () => {
    btn_secondary.classList.add("btn-secondary");
    btn_secondary.classList.remove("btn-primary");
 
    btn_primary.classList.add("btn-primary");
    btn_primary.classList.remove("btn-secondary");
   });
 .btn-primary{
   background: red;
  }
 
 .btn-secondary{
   background: orange;
  }
  <button class="btn btn-primary"> Button 1 </button>

  <button class="btn btn-secondary"> Button 2 </button>

如果您运行它,您将看到我的结果以及我实际希望它如何工作。颜色在mouseovermouseout 上互换。但问题出在使用两个按钮的多个实例。我想出了一个使用吊装和array.prototype.forEach 的解决方案,但我没有得到满意的结果。它只是部分工作。如果你能帮我复习一下,我会很高兴。

请看下面的代码

const mouseOverBtnPrimary = (btn_primary, btn_secondary) => {
    btn_primary.classList.remove("btn-primary");
    btn_primary.classList.add("btn-secondary");

    btn_secondary.classList.add("btn-primary");
    btn_secondary.classList.remove("btn-secondary");

}

const mouseOutBtnPrimary = (btn_primary, btn_secondary) => {
    btn_primary.classList.add("btn-primary");
    btn_primary.classList.remove("btn-secondary");

    btn_secondary.classList.add("btn-secondary");
    btn_secondary.classList.remove("btn-primary");
}

const mouseOverBtnSecondary = (btn_primary, btn_secondary) => {
    btn_secondary.classList.remove("btn-secondary");
    btn_secondary.classList.add("btn-primary");

    btn_primary.classList.add("btn-secondary");
    btn_primary.classList.remove("btn-primary");
}

const mouseOutBtnSecondary = (btn_primary, btn_secondary) => {
    btn_secondary.classList.add("btn-secondary");
    btn_secondary.classList.remove("btn-primary");

    btn_primary.classList.add("btn-primary");
    btn_primary.classList.remove("btn-secondary");
}

const projectPage = document.getElementById('projectsPage');

const btn_primarys = projectPage.getElementsByClassName('btn-primary');
[].forEach.call(btn_primarys, (btn_primary) => {
    btn_primary.addEventListener('mouseover', (e) => {
        mouseOverBtnPrimary(e.target)
    })
});

[].forEach.call(btn_primarys, (btn_primary) => {
    btn_primary.addEventListener('mouseout', (e) => {
        mouseOutBtnPrimary(e.target)
    })
});

const btn_secondarys = projectPage.getElementsByClassName('btn-secondary');
[].forEach.call(btn_secondarys, (btn_secondary) => {
    btn_secondary.addEventListener('mouseover', (e) => {
        mouseOverBtnSecondary(e.target)
    })
});

[].forEach.call(btn_secondarys, (btn_secondary) => {
    btn_secondary.addEventListener('mouseout', (e) => {
    mouseOutBtnSecondary(e.target)
    })
});

【讨论】:

  • 你能用这个扩展你原来的问题吗,我稍后会尝试看看它
【解决方案2】:

您的代码几乎没有问题。

首先在您负责添加和删除类的函数中,您引用尚未声明的变量。使用 letconst 时,变量的提升方式与使用 var 时不同,因此即使您修复了地图 error,您仍然会遇到麻烦。

关于地图错误,在查询 DOM 时,浏览器 API 返回 HTML collection,这是一个类似 array 的集合,但它不是一个数组,所以这就是 map 方法不存在的原因收藏。

有两种方法可以解决此问题: 首先使用Array.from() 方法,在您的情况下看起来像这样

Array.from(btn_primarys).map(x => {...})

使用map 方法的另一种方法是通过Array.prototype 使用它,如下所示:

Array.prototype.map.call(btn_primarys, (x => x))

关于解决方案本身,您实际上不需要使用数组,因为这两个按钮只有一个实例,因此建议您尝试执行以下 sn-p 之类的操作。在下面的 sn-p 中,我使用了 document.querySelector,它将返回单个元素(因此不需要类似数组的东西)。

另一件重要的事情(与您的解决方案不同)是我将指向我想要更改的按钮的引用作为函数参数传递(这解决了我上面提到的提升问题)

const buttonOne = document.querySelector('.first-button');
const buttonTwo = document.querySelector('.second-button');

const setPrimaryClass = (btn) => {
  btn.classList.add('primary-button');
  btn.classList.remove('secondary-button');
}

const setSecondaryClass = (btn) => {
  btn.classList.add('secondary-button');
  btn.classList.remove('primary-button');
}


buttonOne.addEventListener('mouseover', (e) => {
  setSecondaryClass(e.target)
})
buttonOne.addEventListener('mouseout', (e) => {
  setPrimaryClass(e.target)
})

buttonTwo.addEventListener('mouseover', (e) => {
  setPrimaryClass(e.target)
})
buttonTwo.addEventListener('mouseout', (e) => {
  setSecondaryClass(e.target)  
})
.primary-button{
  background:red;
}

.secondary-button{
  background: orange;
}
<button class="first-button primary-button"> Button 1 </button>

<button class="second-button secondary-button"> Button 2 </button>

这里是关于 HTML collections 的 MDN 链接 这是一个关于Hoisting的链接,我希望这个答案能解决你的问题。

附言我看到您是 stackOverflow 社区的新手,您可以点击上面的 Run code snippet 按钮并查看我的代码演示。

编辑

多按钮案例

const buttonOne = document.querySelectorAll('.first-button');
const buttonTwo = document.querySelectorAll('.second-button');

const setPrimaryClass = (btn) => {
  btn.classList.add('primary-button');
  btn.classList.remove('secondary-button');
}

const setSecondaryClass = (btn) => {
  btn.classList.add('secondary-button');
  btn.classList.remove('primary-button');
}

buttonOne.forEach(button => button.addEventListener('mouseover', (e) => {
  setSecondaryClass(e.target)
}))
buttonOne.forEach(button => button.addEventListener('mouseout', (e) => {
  setPrimaryClass(e.target)
}))


buttonTwo.forEach(button => button.addEventListener('mouseover', (e) => {
  setPrimaryClass(e.target)
}))
buttonTwo.forEach(button => button.addEventListener('mouseout', (e) => {
  setSecondaryClass(e.target)  
}))
.primary-button{
  background:red;
}

.secondary-button{
  background: orange;
}
<div>
<button class="first-button primary-button"> Button 1 </button>
<button class="first-button primary-button"> Button 1 </button>
<button class="first-button primary-button"> Button 1 </button>
<button class="first-button primary-button"> Button 1 </button>
<button class="first-button primary-button"> Button 1 </button>
</div>

<div>
<button class="second-button secondary-button"> Button 2 </button>
<button class="second-button secondary-button"> Button 2 </button>
<button class="second-button secondary-button"> Button 2 </button>
<button class="second-button secondary-button"> Button 2 </button>
<button class="second-button secondary-button"> Button 2 </button>
</div>

在上面的示例中,您可以看到我如何使用多个按钮实现所需的结果。 对于您有多个元素分派事件的情况(例如,您需要在同一视图中有很多事件侦听器),我的建议是尝试使用以下技术Event Delegation

捕获和冒泡允许我们实现最强大的事件处理模式之一,称为事件委托。 这个想法是,如果我们有很多元素以类似的方式处理,那么我们不是为每个元素分配一个处理程序,而是在它们的共同祖先上放置一个处理程序。 在处理程序中,我们获取 event.target 以查看事件实际发生的位置并处理它。- javascript.info

【讨论】:

  • 您的想法有所帮助,但我仍然遇到错误。帮我检查下面的代码以及如何解决它。谢谢
猜你喜欢
  • 2020-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-30
  • 1970-01-01
  • 2018-08-21
  • 1970-01-01
  • 2019-09-22
相关资源
最近更新 更多