JS代码中card元素样式赋值失败问题:index返回-1的原因排查
解决card元素style属性赋值失败问题
问题描述
编写前端交互代码时遇到问题:.process__card元素的style属性无法正常赋值,原因是card[index]取值为undefined。测试发现当鼠标移出元素时,index会返回-1,导致后续操作报错。
相关代码片段
JavaScript代码
const card = document.querySelectorAll('.process__card'); card.forEach((cardList) => { cardList.addEventListener('mouseover', animationBackround); cardList.addEventListener('mouseout', animationBackround); }) function animationBackround(event) { const eventType = event.type; const index = Array.from(card).indexOf(event.target); if (eventType === 'mouseover') { let color1 = getRandomColor(); let color2 = getRandomColor(); card[index].style.backgroundColor = `linear-gradient(45deg, ${color1}, ${color2})` } if (eventType === 'mouseout') { card[index].style.backgroundColor = 'none'; } } function getRandomColor() { const letters = '0123456ABCDEF'; let color = "#"; for (let i = 0; i < 6; i++) { color += letters[Math.floor(Math.random() * 16)]; } return color; }
CSS代码
.process { padding-top: 140px; &__wrapper { display: flex; margin: 0 auto; flex-direction: column; gap: 30px; width: 1234px; } &__card { display: flex; flex-direction: column; align-items: center; background-color: #F3F3F3; height: 159px; border-radius: 45px; border: 1px solid #191A23; box-shadow: 0 5px 0 0 #191A23; &_active { height: 279px; background-color: #B9FF66; } } &__content { display: flex; padding-top: 41px; justify-content: space-between; align-items: center; width: 1117px; } &__lable { display: flex; align-items: center; font-size: 60px; font-weight: 500; color: #000; span { padding-left: 25px; font-size: 30px; font-weight: 500; color: #000; } } &__plus { display: flex; position: relative; flex-wrap: wrap; align-items: center; justify-content: center; width: 58px; height: 58px; background-color: #F3F3F3; border-radius: 100%; border: 1px solid #191A23; cursor: pointer; &:after { content: ''; display: block; position: absolute; width: 25px; height: 5px; background-color: #000; } &:before { content: ''; display: block; position: absolute; width: 5px; height: 25px; background-color: #000; } &_active { &:before { content: ''; display: block; position: absolute; width: 5px; height: 25px; background-color: #000; transform: rotate(90deg); transition: transform 0.3s ease-in-out; } } &:not(:active) { &:before { transition: transform 0.3s ease-in-out; } } &:hover { background-color: #B9FF66; transition: 0.7s all; } } &__subcontent { display: flex; flex-direction: column; width: 1117px; hr { width: 1114px; background-color: #000; height: 1px; border: none; } &_hidden { display: none; } &_active { display: block; transition: transform 0.3s ease-in-out; } } &__descrp { padding: 30px 0 41px 0; font-size: 18px; font-weight: 400; color: #000; } }
HTML代码
<div class="process__card"> <div class="process__content"> <div class="process__lable">01<span>Consultation</span> </div> <div class="process__plus"></div> </div> <div class="process__subcontent process__subcontent_hidden"> <hr> <div class="process__descrp">During the initial consultation, we will discuss your business goals and objectives, target audience, and current marketing efforts. This will allow us to understand your needs and tailor our services to best fit your requirements.</div> </div> </div>
问题原因
核心问题出在const index = Array.from(card).indexOf(event.target);这行代码:
event.target指向的是实际触发事件的元素,可能是.process__card的子元素(比如内部的.process__content、.process__lable等);- 而
Array.from(card)转换的是所有.process__card元素的集合,子元素不在这个集合里,所以indexOf会返回-1,导致card[-1]为undefined; - 鼠标移出时,很容易从子元素直接移出到card外部,此时
event.target还是子元素,就会触发这个问题。
另外还有两个小问题:
backgroundColor属性不支持渐变效果,应该使用background属性;- 重置背景时用
'none'不正确,none是background-image的有效值,想要恢复CSS类中的初始背景,应该将background设为空字符串。
解决方案
方案1:使用event.currentTarget(推荐)
event.currentTarget永远指向绑定事件的元素(也就是.process__card本身),不需要通过index查找,直接操作即可:
const card = document.querySelectorAll('.process__card'); card.forEach((cardList) => { cardList.addEventListener('mouseover', animationBackround); cardList.addEventListener('mouseout', animationBackround); }) function animationBackround(event) { const eventType = event.type; const targetCard = event.currentTarget; if (eventType === 'mouseover') { let color1 = getRandomColor(); let color2 = getRandomColor(); targetCard.style.background = `linear-gradient(45deg, ${color1}, ${color2})`; } if (eventType === 'mouseout') { targetCard.style.background = ''; } } function getRandomColor() { const letters = '0123456ABCDEF'; let color = "#"; for (let i = 0; i < 6; i++) { color += letters[Math.floor(Math.random() * 16)]; } return color; }
方案2:通过closest()获取父级card元素
如果一定要通过index操作,可以用closest('.process__card')获取事件目标所属的card元素,再查找index:
const card = document.querySelectorAll('.process__card'); card.forEach((cardList) => { cardList.addEventListener('mouseover', animationBackround); cardList.addEventListener('mouseout', animationBackround); }) function animationBackround(event) { const eventType = event.type; const targetCard = event.target.closest('.process__card'); const index = Array.from(card).indexOf(targetCard); // 提前判断index是否有效,避免报错 if (index === -1) return; if (eventType === 'mouseover') { let color1 = getRandomColor(); let color2 = getRandomColor(); card[index].style.background = `linear-gradient(45deg, ${color1}, ${color2})`; } if (eventType === 'mouseout') { card[index].style.background = ''; } } function getRandomColor() { const letters = '0123456ABCDEF'; let color = "#"; for (let i = 0; i < 6; i++) { color += letters[Math.floor(Math.random() * 16)]; } return color; }
内容的提问来源于stack exchange,提问作者Gor
相关产品推荐
相关产品推荐

