首页 > 解决方案 > 有人可以修复我使用 HTML CSS Vanilla Javscript 创建的星级评分(星级只会突出显示以前的元素)

问题描述

我使用 CSS HTML 和 Javascript 创建了一个星级评分应用程序。当我点击一颗星时,它没有按预期突出显示。假设我点击了第三颗星,然后只有两颗星才被突出显示。

我不明白我应该如何处理 css 属性,这将使当前点击的星星突出显示。

let stars = document.querySelectorAll('.star');
document.querySelector('.star-container').addEventListener('click', starRating);
let rating = document.querySelector('.rating');

function starRating(e) {
	if (e.target.classList[0] == 'star') {
		stars.forEach((star) => star.classList.remove('star__checked'));
		for (i = stars.length - 1, j = 0; i >= 0; i--, j++) {
			if (stars[i] !== e.target) {
				stars[i].classList.add('star__checked');
			} else {
				stars[i].classList.add('star__checked');
				rating.textContent = `${j + 1}/5`;
				break;
			}
		}
	} else {
		stars.forEach((star) => star.classList.remove('star__checked'));
		rating.textContent = `${0}/5`;
	}
}
.star-container {
	display: flex;
	width: 350px;
	flex-direction: row-reverse;
}

.star {
}

.star:before {
	content: '\f005';
	font-family: fontAwesome;
	font-size: 60px;
	position: relative;
	display: block;
	color: pink;
}

.star:after {
	content: '\f005';
	font-family: fontAwesome;
	position: absolute;
	top: 7px;
	font-size: 60px;
	color: gold;
	opacity: 0;
}
.star:hover:after,
.star:hover ~ .star:after {
	opacity: 1;
}

.star__checked ~ .star:after {
	opacity: 1;
}
<html lang="en">
	<head>

		<link rel="stylesheet" href="./styles.css" />
		<link
			rel="stylesheet"
			href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
		/>
		<title>Document</title>
	</head>
	<body>
		<div class="star-container">
			<div class="star"></div>
			<div class="star"></div>
			<div class="star"></div>
			<div class="star"></div>
			<div class="star"></div>
		</div>
		<h1 class="rating">0/5</h1>
		<script src="app.js"></script>
	</body>
</html>

标签: javascripthtmlcssdomecmascript-6

解决方案


实际上,您的问题在于这条线:

.star__checked~.star:after {
  opacity: 1;
}

这里发生了什么事?

当您应用star__checked到每个所需元素时,无需为后续兄弟应用样式。~用于一般的后继兄弟,所以无论何时定义这样的样式,它只会选择后继元素(因为您使用flex-direction: row-reverse;的元素将从右到左开始,所以它只会突出显示您的后继元素)。因此,您应该只应用带有类的opacity: 1;for 元素。star__checked

如何解决?

如果要修复当前代码,只需将上述部分替换为以下内容即可:

.star__checked.star:after {
  opacity: 1;
}

您的最终代码将是这样的:

let stars = document.querySelectorAll('.star');
document.querySelector('.star-container').addEventListener('click', starRating);
let rating = document.querySelector('.rating');

function starRating(e) {
  if (e.target.classList[0] == 'star') {
    stars.forEach((star) => star.classList.remove('star__checked'));
    for (i = stars.length - 1, j = 0; i >= 0; i--, j++) {
      if (stars[i] !== e.target) {
        stars[i].classList.add('star__checked');
      } else if (stars[i] === e.target) {
        stars[i].classList.add('star__checked');
        rating.textContent = `${j + 1}/5`;
        break;
      }
    }
  } else {
    stars.forEach((star) => star.classList.remove('star__checked'));
    rating.textContent = `${0}/5`;
  }
}
.star-container {
  display: flex;
  width: 350px;
  flex-direction: row-reverse;
}

.star:before {
  content: '\f005';
  font-family: fontAwesome;
  font-size: 60px;
  position: relative;
  display: block;
  color: pink;
}

.star:after {
  content: '\f005';
  font-family: fontAwesome;
  position: absolute;
  top: 7px;
  font-size: 60px;
  color: gold;
  opacity: 0;
}

.star:hover:after,
.star:hover~.star:after {
  opacity: 1;
}

.star__checked.star:after {
  opacity: 1;
}
<html lang="en">

<head>

  <link rel="stylesheet" href="./styles.css" />
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" />
  <title>Document</title>
</head>

<body>
  <div class="star-container">
    <div class="star"></div>
    <div class="star"></div>
    <div class="star"></div>
    <div class="star"></div>
    <div class="star"></div>
  </div>
  <h1 class="rating">0/5</h1>
  <script src="app.js"></script>
</body>

</html>


但是,如果您要寻找最佳实践,则必须使用previousElementSiblingorindexOf()进行一些进一步的实施和一些魔术,这需要花费大量的工作才能实现,但强烈推荐。

我将给它一个触摸indexOf()这个方法将为我们提供数组中当前选定元素的索引。然后我们像往常一样突出显示它,然后~我们将选择所有后继兄弟姐妹。但请记住,star__checked该类仅适用于所选元素。

所以它会是这样的:

const stars = document.querySelectorAll('.star');
document.querySelector('.star-container').addEventListener('click', starRating);
const rating = document.querySelector('.rating');

function starRating(e) {
  stars.forEach((star) => star.classList.remove('star__checked'));
  const i = [...stars].indexOf(e.target);
  if (i > -1) {
    stars[i].classList.add('star__checked');
    rating.textContent = `${stars.length - i}/5`;
  } else {
    star.classList.remove('star__checked');
    rating.textContent = `0/5`;
  }
}
.star-container {
  display: flex;
  width: 350px;
  flex-direction: row-reverse;
}

.star:before {
  content: '\f005';
  font-family: fontAwesome;
  font-size: 60px;
  position: relative;
  display: block;
  color: pink;
}

.star:after {
  content: '\f005';
  font-family: fontAwesome;
  position: absolute;
  top: 7px;
  font-size: 60px;
  color: gold;
  opacity: 0;
}

.star:hover:after,
.star:hover~.star:after {
  opacity: 1;
}

.star.star__checked~.star:after,
.star.star__checked:after {
  opacity: 1;
}
<html lang="en">

<head>

  <link rel="stylesheet" href="./styles.css" />
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" />
  <title>Document</title>
</head>

<body>
  <div class="star-container">
    <div class="star"></div>
    <div class="star"></div>
    <div class="star"></div>
    <div class="star"></div>
    <div class="star"></div>
  </div>
  <h1 class="rating">0/5</h1>
  <script src="app.js"></script>
</body>

</html>


推荐阅读