星级评分CSS问题

3

我想实现星级评分,我正在处理以下星级评分代码。它可以正常工作,但问题是如果我已经给了1个评级,那么我不能取消选择之前已选定的那颗星。这只会发生在第一颗星上,因为它没有任何附加的星星,所以用户无法选择它以取消之前选择的星。

@import url(//netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.css);
fieldset,
label {
  margin: 0;
  padding: 0;
}

body {
  margin: 20px;
}

h1 {
  font-size: 1.5em;
  margin: 10px;
}


/****** Style Star Rating Widget *****/

.rating {
  border: none;
  float: left;
}

.rating>input {
  display: none;
}

.rating>label:before {
  margin: 5px;
  font-size: 1.25em;
  font-family: FontAwesome;
  display: inline-block;
  content: "\f005";
}

.rating>.half:before {
  content: "\f089";
  position: absolute;
}

.rating>label {
  color: #ddd;
  float: right;
}


/***** CSS Magic to Highlight Stars on Hover *****/

.rating>input:checked~label,

/* show gold star when clicked */

.rating:not(:checked)>label:hover,

/* hover current star */

.rating:not(:checked)>label:hover~label {
  color: #FFD700;
}


/* hover previous stars in list */

.rating>input:checked+label:hover,

/* hover current star when changing rating */

.rating>input:checked~label:hover,
.rating>label:hover~input:checked~label,

/* lighten current selection */

.rating>input:checked~label:hover~label {
  color: #FFED85;
}
<fieldset class="rating">
  <input type="radio" id="star5" name="rating" value="5" /><label class="full" for="star5" title="Awesome - 5 stars"></label>
  <input type="radio" id="star4half" name="rating" value="4 and a half" /><label class="half" for="star4half" title="Pretty good - 4.5 stars"></label>
  <input type="radio" id="star4" name="rating" value="4" /><label class="full" for="star4" title="Pretty good - 4 stars"></label>
  <input type="radio" id="star3half" name="rating" value="3 and a half" /><label class="half" for="star3half" title="Meh - 3.5 stars"></label>
  <input type="radio" id="star3" name="rating" value="3" /><label class="full" for="star3" title="Meh - 3 stars"></label>
  <input type="radio" id="star2half" name="rating" value="2 and a half" /><label class="half" for="star2half" title="Kinda bad - 2.5 stars"></label>
  <input type="radio" id="star2" name="rating" value="2" /><label class="full" for="star2" title="Kinda bad - 2 stars"></label>
  <input type="radio" id="star1half" name="rating" value="1 and a half" /><label class="half" for="star1half" title="Meh - 1.5 stars"></label>
  <input type="radio" id="star1" name="rating" value="1" /><label class="full" for="star1" title="Sucks big time - 1 star"></label>
  <input type="radio" id="starhalf" name="rating" value="half" /><label class="half" for="starhalf" title="Sucks big time - 0.5 stars"></label>
</fieldset>

3个回答

2
如果您有一系列可见的单选按钮,并且想要取消所有单选按钮的选择,您必须有另一个单选按钮(可见或不可见),您可以选择它。
这将使焦点从先前选中的任何可见单选按钮移开。
在下面的示例中,我添加了一个不可见的单选项(称为.reset-option)和一个按钮(称为.reset-button)。当单击时,将检查焦点从当前选中的任何单选按钮移动到不可见的单选选项。
工作示例:

const resetOption = document.getElementsByClassName('reset-option')[0];
const resetButton = document.getElementsByClassName('reset-button')[0];

const resetRating = () => resetOption.checked = true;

resetButton.addEventListener('click', resetRating, false);
@import url(//netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.css);

fieldset, label { margin: 0; padding: 0; }
body{ margin: 20px; }
h1 { font-size: 1.5em; margin: 10px; }

/****** Style Star Rating Widget *****/

.rating { 
  border: none;
  float: left;
}

.rating > [id^="star"] { display: none; } 
.rating > label:before { 
  margin: 5px;
  font-size: 1.25em;
  font-family: FontAwesome;
  display: inline-block;
  content: "\f005";
}

.rating > .half:before { 
  content: "\f089";
  position: absolute;
}

.rating > label { 
  color: #ddd; 
 float: right; 
}

/***** CSS Magic to Highlight Stars on Hover *****/

.rating > [id^="star"]:checked ~ label, /* show gold star when clicked */
.rating:not(:checked) > label:hover, /* hover current star */
.rating:not(:checked) > label:hover ~ label { color: #FFD700;  } /* hover previous stars in list */

.rating > [id^="star"]:checked + label:hover, /* hover current star when changing rating */
.rating > [id^="star"]:checked ~ label:hover,
.rating > label:hover ~ [id^="star"]:checked ~ label, /* lighten current selection */
.rating > [id^="star"]:checked ~ label:hover ~ label { color: #FFED85;  }

.reset-option {
display: none;
}

.reset-button {
margin: 6px 12px;
background-color: rgb(255, 255, 255);
text-transform: uppercase;
}
<fieldset class="rating">
    <input type="radio" id="star5" name="rating" value="5" /><label class = "full" for="star5" title="Awesome - 5 stars"></label>
    <input type="radio" id="star4half" name="rating" value="4 and a half" /><label class="half" for="star4half" title="Pretty good - 4.5 stars"></label>
    <input type="radio" id="star4" name="rating" value="4" /><label class = "full" for="star4" title="Pretty good - 4 stars"></label>
    <input type="radio" id="star3half" name="rating" value="3 and a half" /><label class="half" for="star3half" title="Meh - 3.5 stars"></label>
    <input type="radio" id="star3" name="rating" value="3" /><label class = "full" for="star3" title="Meh - 3 stars"></label>
    <input type="radio" id="star2half" name="rating" value="2 and a half" /><label class="half" for="star2half" title="Kinda bad - 2.5 stars"></label>
    <input type="radio" id="star2" name="rating" value="2" /><label class = "full" for="star2" title="Kinda bad - 2 stars"></label>
    <input type="radio" id="star1half" name="rating" value="1 and a half" /><label class="half" for="star1half" title="Meh - 1.5 stars"></label>
    <input type="radio" id="star1" name="rating" value="1" /><label class = "full" for="star1" title="Sucks big time - 1 star"></label>
    <input type="radio" id="starhalf" name="rating" value="half" /><label class="half" for="starhalf" title="Sucks big time - 0.5 stars"></label>
    <input type="radio" class="reset-option" name="rating" value="reset" />
</fieldset>

<button type="button" class="reset-button">Reset</button>


2
注意:我提供的两个解决方案在用户体验方面都不是好的解决方案(没有办法事先知道应该怎么做才能取消所有星星的选择)。如果您想遵循用户友好的解决方案,则 @Rounin 的答案是正确的方法。
通过添加一小段 JavaScript 代码,您可以为第一个输入框添加事件,并在单击它后检查或取消选中它,具体取决于其先前的值:

const label = document.querySelector('[for="starhalf"]');
const input = document.getElementById('starhalf');

label.addEventListener('click', (evt) => {
  evt.preventDefault();
  input.checked = !input.checked;
});
@import url(//netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.css);
fieldset,
label {
  margin: 0;
  padding: 0;
}

body {
  margin: 20px;
}

h1 {
  font-size: 1.5em;
  margin: 10px;
}


/****** Style Star Rating Widget *****/

.rating {
  border: none;
  float: left;
}

.rating>input {
  display: none;
}

.rating>label:before {
  margin: 5px;
  font-size: 1.25em;
  font-family: FontAwesome;
  display: inline-block;
  content: "\f005";
}

.rating>.half:before {
  content: "\f089";
  position: absolute;
}

.rating>label {
  color: #ddd;
  float: right;
}


/***** CSS Magic to Highlight Stars on Hover *****/

.rating>input:checked~label,

/* show gold star when clicked */

.rating:not(:checked)>label:hover,

/* hover current star */

.rating:not(:checked)>label:hover~label {
  color: #FFD700;
}


/* hover previous stars in list */

.rating>input:checked+label:hover,

/* hover current star when changing rating */

.rating>input:checked~label:hover,
.rating>label:hover~input:checked~label,

/* lighten current selection */

.rating>input:checked~label:hover~label {
  color: #FFED85;
}
<fieldset class="rating">
  <input type="radio" id="star5" name="rating" value="5" /><label class="full" for="star5" title="Awesome - 5 stars"></label>
  <input type="radio" id="star4half" name="rating" value="4 and a half" /><label class="half" for="star4half" title="Pretty good - 4.5 stars"></label>
  <input type="radio" id="star4" name="rating" value="4" /><label class="full" for="star4" title="Pretty good - 4 stars"></label>
  <input type="radio" id="star3half" name="rating" value="3 and a half" /><label class="half" for="star3half" title="Meh - 3.5 stars"></label>
  <input type="radio" id="star3" name="rating" value="3" /><label class="full" for="star3" title="Meh - 3 stars"></label>
  <input type="radio" id="star2half" name="rating" value="2 and a half" /><label class="half" for="star2half" title="Kinda bad - 2.5 stars"></label>
  <input type="radio" id="star2" name="rating" value="2" /><label class="full" for="star2" title="Kinda bad - 2 stars"></label>
  <input type="radio" id="star1half" name="rating" value="1 and a half" /><label class="half" for="star1half" title="Meh - 1.5 stars"></label>
  <input type="radio" id="star1" name="rating" value="1" /><label class="full" for="star1" title="Sucks big time - 1 star"></label>
  <input type="radio" id="starhalf" name="rating" value="half" /><label class="half" for="starhalf" title="Sucks big time - 0.5 stars"></label>
</fieldset>

编辑:阅读您的评论,我明白您想要在用户点击星星外部时取消选择前半部分-开始(我没有从您的问题中得到这一点)。这是实现该目的的另一种代码:

const fieldset = document.querySelector('fieldset.rating');
const halfstar = fieldset.querySelector('#starhalf');

document.addEventListener('click', (evt) => {
  const element = evt.target;
  if((!element.parentNode || element.parentNode !== fieldset) && halfstar.checked) {
    halfstar.checked = false;
  }
});
@import url(//netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.css);
fieldset,
label {
  margin: 0;
  padding: 0;
}

body {
  margin: 20px;
}

h1 {
  font-size: 1.5em;
  margin: 10px;
}


/****** Style Star Rating Widget *****/

.rating {
  border: none;
  float: left;
}

.rating>input {
  display: none;
}

.rating>label:before {
  margin: 5px;
  font-size: 1.25em;
  font-family: FontAwesome;
  display: inline-block;
  content: "\f005";
}

.rating>.half:before {
  content: "\f089";
  position: absolute;
}

.rating>label {
  color: #ddd;
  float: right;
}


/***** CSS Magic to Highlight Stars on Hover *****/

.rating>input:checked~label,

/* show gold star when clicked */

.rating:not(:checked)>label:hover,

/* hover current star */

.rating:not(:checked)>label:hover~label {
  color: #FFD700;
}


/* hover previous stars in list */

.rating>input:checked+label:hover,

/* hover current star when changing rating */

.rating>input:checked~label:hover,
.rating>label:hover~input:checked~label,

/* lighten current selection */

.rating>input:checked~label:hover~label {
  color: #FFED85;
}
<fieldset class="rating">
  <input type="radio" id="star5" name="rating" value="5" /><label class="full" for="star5" title="Awesome - 5 stars"></label>
  <input type="radio" id="star4half" name="rating" value="4 and a half" /><label class="half" for="star4half" title="Pretty good - 4.5 stars"></label>
  <input type="radio" id="star4" name="rating" value="4" /><label class="full" for="star4" title="Pretty good - 4 stars"></label>
  <input type="radio" id="star3half" name="rating" value="3 and a half" /><label class="half" for="star3half" title="Meh - 3.5 stars"></label>
  <input type="radio" id="star3" name="rating" value="3" /><label class="full" for="star3" title="Meh - 3 stars"></label>
  <input type="radio" id="star2half" name="rating" value="2 and a half" /><label class="half" for="star2half" title="Kinda bad - 2.5 stars"></label>
  <input type="radio" id="star2" name="rating" value="2" /><label class="full" for="star2" title="Kinda bad - 2 stars"></label>
  <input type="radio" id="star1half" name="rating" value="1 and a half" /><label class="half" for="star1half" title="Meh - 1.5 stars"></label>
  <input type="radio" id="star1" name="rating" value="1" /><label class="full" for="star1" title="Sucks big time - 1 star"></label>
  <input type="radio" id="starhalf" name="rating" value="half" /><label class="half" for="starhalf" title="Sucks big time - 0.5 stars"></label>
</fieldset>


它没有起作用,请先给1个评分,然后取消选择第一个。 - user3653474
嗨@user3653474,你能更好地解释一下你正在遵循的步骤吗?在我的端上它是可以工作的。只是为了向您解释它的工作原理,您应该能够选择半颗星,因此取消选择是在“半颗星”而不是“整颗星”中进行的。 - ElChiniNet
如果我选择了0.5星级评分,然后在星星外面点击,它不会取消选择所有的星星。 - user3653474
请编辑您的问题以反映您想要取消选择第一个星号如果用户在外部单击,我会稍微修改我的代码来实现这一点。 - ElChiniNet

2

编辑:@ElChiniNet 提出的一种更好的解决方案:点击查看

const allStarLabels = document.querySelectorAll('.rating label');

allStarLabels.forEach(thisLabel =>
    thisLabel.addEventListener('click', e => {
        e.preventDefault();
        let radioElement = e.target.previousElementSibling;
        radioElement.checked = !radioElement.checked;
    })
)

const allStarLabels = document.querySelectorAll('.rating label');

allStarLabels.forEach(thisLabel =>
    thisLabel.addEventListener('click', e => {
      e.preventDefault();
        let radioElement = e.target.previousElementSibling;
        radioElement.checked = !radioElement.checked;
    })
)
@import url(//netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.css);
fieldset,
label {
  margin: 0;
  padding: 0;
}

body {
  margin: 20px;
}

h1 {
  font-size: 1.5em;
  margin: 10px;
}


/****** Style Star Rating Widget *****/

.rating {
  border: none;
  float: left;
}

.rating>input {
  display: none;
}

.rating>label:before {
  margin: 5px;
  font-size: 1.25em;
  font-family: FontAwesome;
  display: inline-block;
  content: "\f005";
}

.rating>.half:before {
  content: "\f089";
  position: absolute;
}

.rating>label {
  color: #ddd;
  float: right;
}


/***** CSS Magic to Highlight Stars on Hover *****/

.rating>input:checked~label,

/* show gold star when clicked */

.rating:not(:checked)>label:hover,

/* hover current star */

.rating:not(:checked)>label:hover~label {
  color: #FFD700;
}


/* hover previous stars in list */

.rating>input:checked+label:hover,

/* hover current star when changing rating */

.rating>input:checked~label:hover,
.rating>label:hover~input:checked~label,

/* lighten current selection */

.rating>input:checked~label:hover~label {
  color: #FFED85;
}
<fieldset class="rating">
  <input type="radio" id="star5" name="rating" value="5" /><label class="full" for="star5" title="Awesome - 5 stars"></label>
  <input type="radio" id="star4half" name="rating" value="4 and a half" /><label class="half" for="star4half" title="Pretty good - 4.5 stars"></label>
  <input type="radio" id="star4" name="rating" value="4" /><label class="full" for="star4" title="Pretty good - 4 stars"></label>
  <input type="radio" id="star3half" name="rating" value="3 and a half" /><label class="half" for="star3half" title="Meh - 3.5 stars"></label>
  <input type="radio" id="star3" name="rating" value="3" /><label class="full" for="star3" title="Meh - 3 stars"></label>
  <input type="radio" id="star2half" name="rating" value="2 and a half" /><label class="half" for="star2half" title="Kinda bad - 2.5 stars"></label>
  <input type="radio" id="star2" name="rating" value="2" /><label class="full" for="star2" title="Kinda bad - 2 stars"></label>
  <input type="radio" id="star1half" name="rating" value="1 and a half" /><label class="half" for="star1half" title="Meh - 1.5 stars"></label>
  <input type="radio" id="star1" name="rating" value="1" /><label class="full" for="star1" title="Sucks big time - 1 star"></label>
  <input type="radio" id="starhalf" name="rating" value="half" /><label class="half" for="starhalf" title="Sucks big time - 0.5 stars"></label>
</fieldset>


我的原始建议:

可以使用一点javascript实现。监听每个

// Get all the <label> elements
const allStarLabels = document.querySelectorAll('.rating label');

// Prepare a function to reset the radio
const resetRadio = radioElement => {
    // Has to be done inside a timeout to make sure the click event has finished
    setTimeout(() => {
        radioElement.checked = false;
    }, 5);
}

// Add an event listener to each label
allStarLabels.forEach(thisLabel =>
    thisLabel.addEventListener('click', e => {
    // Get the corresponding input[type=radio] element
    let radioElement = thisLabel.previousElementSibling;
    if(radioElement.checked) {
        resetRadio(radioElement);
        }
    })
)

点击此处查看完整版:

const allStarLabels = document.querySelectorAll('.rating label');

const resetRadio = radioElement => {
    setTimeout(() => {
        radioElement.checked = false;
    }, 5);
}

allStarLabels.forEach(thisLabel =>
    thisLabel.addEventListener('click', e => {
        let radioElement = e.target.previousElementSibling;
        if(radioElement.checked) {
         resetRadio(radioElement);
        }
    })
)
@import url(//netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.css);
fieldset,
label {
  margin: 0;
  padding: 0;
}

body {
  margin: 20px;
}

h1 {
  font-size: 1.5em;
  margin: 10px;
}


/****** Style Star Rating Widget *****/

.rating {
  border: none;
  float: left;
}

.rating>input {
  display: none;
}

.rating>label:before {
  margin: 5px;
  font-size: 1.25em;
  font-family: FontAwesome;
  display: inline-block;
  content: "\f005";
}

.rating>.half:before {
  content: "\f089";
  position: absolute;
}

.rating>label {
  color: #ddd;
  float: right;
}


/***** CSS Magic to Highlight Stars on Hover *****/

.rating>input:checked~label,

/* show gold star when clicked */

.rating:not(:checked)>label:hover,

/* hover current star */

.rating:not(:checked)>label:hover~label {
  color: #FFD700;
}


/* hover previous stars in list */

.rating>input:checked+label:hover,

/* hover current star when changing rating */

.rating>input:checked~label:hover,
.rating>label:hover~input:checked~label,

/* lighten current selection */

.rating>input:checked~label:hover~label {
  color: #FFED85;
}
<fieldset class="rating">
  <input type="radio" id="star5" name="rating" value="5" /><label class="full" for="star5" title="Awesome - 5 stars"></label>
  <input type="radio" id="star4half" name="rating" value="4 and a half" /><label class="half" for="star4half" title="Pretty good - 4.5 stars"></label>
  <input type="radio" id="star4" name="rating" value="4" /><label class="full" for="star4" title="Pretty good - 4 stars"></label>
  <input type="radio" id="star3half" name="rating" value="3 and a half" /><label class="half" for="star3half" title="Meh - 3.5 stars"></label>
  <input type="radio" id="star3" name="rating" value="3" /><label class="full" for="star3" title="Meh - 3 stars"></label>
  <input type="radio" id="star2half" name="rating" value="2 and a half" /><label class="half" for="star2half" title="Kinda bad - 2.5 stars"></label>
  <input type="radio" id="star2" name="rating" value="2" /><label class="full" for="star2" title="Kinda bad - 2 stars"></label>
  <input type="radio" id="star1half" name="rating" value="1 and a half" /><label class="half" for="star1half" title="Meh - 1.5 stars"></label>
  <input type="radio" id="star1" name="rating" value="1" /><label class="full" for="star1" title="Sucks big time - 1 star"></label>
  <input type="radio" id="starhalf" name="rating" value="half" /><label class="half" for="starhalf" title="Sucks big time - 0.5 stars"></label>
</fieldset>


如果您使用 preventDefault 取消点击事件并手动检查或取消选中输入框,也可以实现相同的效果。例如:e.preventDefault(); e.target.previousElementSibling.checked = !e.target.previousElementSibling.checked;。这样就可以删除 resetRadio 函数了。在我看来,这也是一个不错的解决方案,比 PO 想要的更好。 - ElChiniNet
@ElChiniNet 很不错,比我建议的更有效率。 - agrm
这几乎是一样的 ;) 对于这个加1 - ElChiniNet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接