【问题标题】:Can somebody please fix my Star rating created using HTML CSS Vanilla Javscript (Star rating will only highlight previous elements)有人可以修复我使用 HTML CSS Vanilla Javascript 创建的星级评分(星级只会突出显示以前的元素)
【发布时间】:2020-09-11 12:32:30
【问题描述】:

我使用 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>

【问题讨论】:

    标签: javascript html css dom ecmascript-6


    【解决方案1】:

    我做了一些改进:

    • 不需要另一个循环,只需使用e.target
    • 您可以将data-val 属性用于值
    • 添加 star__checked:after 以使用最后一个元素

    这是工作代码:

    let stars = document.querySelectorAll('.star');
    document.querySelector('.star-container').addEventListener('click', starRating);
    let rating = document.querySelector('.rating');
    
    function starRating(e) {
      const star = e.target;
      const val = star.getAttribute('data-val');
    
      stars.forEach((star) => star.classList.remove('star__checked'));
    
      star.classList.add('star__checked');
      rating.textContent = `${val}/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,
    .star.star__checked:after {
      opacity: 1;
    }
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" />
    
    <div class="star-container">
      <div class="star" data-val="5"></div>
      <div class="star" data-val="4"></div>
      <div class="star" data-val="3"></div>
      <div class="star" data-val="2"></div>
      <div class="star" data-val="1"></div>
    </div>
    <h1 class="rating">0/5</h1>

    【讨论】:

      【解决方案2】:

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

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

      这里发生了什么?

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

      如何解决?

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

      .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>

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

      我会用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>

      【讨论】:

      • 非常感谢 SMAKSS 的回答,我怎样才能更多地了解组合器以及如何有效地应用它们。
      • @SumitGhewade 欢迎您。网络上有很多很好的资源,但是MDNCSS-Tricks 上的这两个资源将是跳入 CSS 组合器的良好开端。
      【解决方案3】:

      另一个简化版:

      let stars = document.querySelectorAll('.star');
      document.querySelector('.star-container').addEventListener('click', starRating);
      let rating = document.querySelector('.rating');
      
      function starRating(e) {
        stars.forEach((star) => star.classList.remove('star__checked'));
        let i = [].indexOf.call(stars, e.target);
        if (i > -1) {
          stars[i].classList.add('star__checked');
          rating.textContent = `${stars.length - i}/5`;
        } else {
          rating.textContent = `${0}/5`;
        }
      }
      .star-container {
        display: flex;
        width: 350px;
        flex-direction: row-reverse;
      }
      
      .star {}
      
      .star:after {
        content: '\f005';
        font-family: fontAwesome;
        font-size: 60px;
        display: block;
        color: pink;
      }
      
      .star.star__checked ~ .star:after,
      .star.star__checked:after,
      .star:hover ~ .star:after,
      .star:hover:after {
        color: gold;
      }
      <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>

      【讨论】:

        猜你喜欢
        • 2021-08-01
        • 2021-11-24
        • 2018-09-24
        • 2021-04-04
        • 2018-07-27
        • 1970-01-01
        • 2018-07-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多