Помогите сделать функционал кнопок отзыва на сайте
В моем макете присутствуют кнопки-оценки пользователей, то есть отзывы, как сделать так,чтобы пользователь сам мог выбрать кликом оценку которая ему нужна, вот скрин пример как должно выглядеть (кнопки представлены в виде звездочек)
Ответы (2 шт):
Автор решения: Евгений Ли
→ Ссылка
В одном из проектов я писал такую колбасу jQuery для звёзд.
Уверен кто-то сможет и сократить код, но я не умею)).
В общем рабочий вариант, а если нужно с надписями, то нужно раскомментировать в html - class="rating_message"

$(function() {
let stars = $('.rating_wrap .star');
let starsCurrent = $('.stars_current');
let message = $('.rating_message');
stars.on('click', function () {
let currentStar = $(this);
if (currentStar.data('current_width') === 20) {
starsCurrent.css("width",currentStar.data('current_width') + '%');
starsCurrent.attr('data-rating',currentStar.data('rating_value'));
starsCurrent.data('rating',currentStar.data('rating_value'));
message.text(currentStar.data('message'));
} else if (currentStar.data('current_width') === 40) {
starsCurrent.css("width",currentStar.data('current_width') + '%');
starsCurrent.attr('data-rating',currentStar.data('rating_value'));
starsCurrent.data('rating',currentStar.data('rating_value'));
message.text(currentStar.data('message'));
} else if (currentStar.data('current_width') === 60) {
starsCurrent.css("width",currentStar.data('current_width') + '%');
starsCurrent.attr('data-rating',currentStar.data('rating_value'));
starsCurrent.data('rating',currentStar.data('rating_value'));
message.text(currentStar.data('message'));
} else if (currentStar.data('current_width') === 80) {
starsCurrent.css("width",currentStar.data('current_width') + '%');
starsCurrent.attr('data-rating',currentStar.data('rating_value'));
starsCurrent.data('rating',currentStar.data('rating_value'));
message.text(currentStar.data('message'));
} else if (currentStar.data('current_width') === 100) {
starsCurrent.css("width",currentStar.data('current_width') + '%');
starsCurrent.attr('data-rating',currentStar.data('rating_value'));
starsCurrent.data('rating',currentStar.data('rating_value'));
message.text(currentStar.data('message'));
}
});
stars.on('mouseover', function () {
let currentStar = $(this);
if (currentStar.data('current_width') === 20) {
starsCurrent.css("width",currentStar.data('current_width') + '%');
message.text(currentStar.data('message'));
} else if (currentStar.data('current_width') === 40) {
starsCurrent.css("width",currentStar.data('current_width') + '%');
message.text(currentStar.data('message'));
} else if (currentStar.data('current_width') === 60) {
starsCurrent.css("width",currentStar.data('current_width') + '%');
message.text(currentStar.data('message'));
} else if (currentStar.data('current_width') === 80) {
starsCurrent.css("width",currentStar.data('current_width') + '%');
message.text(currentStar.data('message'));
} else if (currentStar.data('current_width') === 100) {
starsCurrent.css("width",currentStar.data('current_width') + '%');
message.text(currentStar.data('message'));
}
});
stars.on('mouseout', function () {
if (starsCurrent.data('rating') === 0) {
starsCurrent.css("width",0);
message.text('Без оценки');
} else {
let width = stars.filter('[data-rating_value='+starsCurrent.data('rating')+']').data('current_width');
let messageVal = stars.filter('[data-rating_value='+starsCurrent.data('rating')+']').data('message');
starsCurrent.css("width",width+'%');
message.text(messageVal);
}
});
});
.rating {
float: left;
position: relative;
width: 150px;
height: 24px;
font-size: 0;
line-height: 0;
background: url("https://i.stack.imgur.com/ceEGP.jpg") 0 -26px no-repeat;
}
.rating .star {
position: relative;
z-index: 1;
margin: 0;
padding: 0;
height: 24px;
display: inline-block;
width: 20%;
background: none;
cursor: pointer;
border-radius: 0;
}
.rating .stars_current {
position: absolute;
left: 0;
top: 0;
bottom: 0;
display: block;
width: 0;
background: url("https://i.stack.imgur.com/ceEGP.jpg") 0 0 no-repeat;
}
.rating_message {
margin: 0 0 0 13px;
float: left;
position: relative;
padding: 0 0 0 30px;
color: #999999;
}
.rating_message:before {
content: "—";
position: absolute;
left: 0;
top: 0;
}
<div class="rating_wrap clearfix">
<div class="rating">
<span class="star" data-current_width="20" data-rating_value="1" data-message="Очень плохо"></span>
<span class="star" data-current_width="40" data-rating_value="2" data-message="Плохо"></span>
<span class="star" data-current_width="60" data-rating_value="3" data-message="Нормально"></span>
<span class="star" data-current_width="80" data-rating_value="4" data-message="Хорошо"></span>
<span class="star" data-current_width="100" data-rating_value="5" data-message="Отлично"></span>
<span class="stars_current" data-rating="0"></span>
</div>
<!-- <div class="rating_message" data-message="Без оценки">Без оценки</div> -->
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
Автор решения: Михаил Камахин
→ Ссылка
Можно так
const svgStarNode = document.querySelector('.svg-star');
svgStarNode.addEventListener('mousemove', (e) => {
const widthStarNode = svgStarNode.clientWidth;
const xPercent = Math.round((e.clientX / widthStarNode) * 100);
svgStarNode.style.setProperty('--x', `${xPercent}%`);
});
.svg-star {
--x: 0%;
}
.svg-star .rect-percent {
x: var(--x);
}
<svg class="svg-star" width="160" height="32" viewBox="0 0 160 32">
<defs>
<mask id="perc">
<rect x="0" y="0" width="100%" height="100%" fill="white" />
<rect class="rect-percent" x="0%" y="0" width="100%" height="100%" fill="grey" />
</mask>
<symbol viewBox="0 0 32 32" id="star">
<path d="M31.547 12a.848.848 0 00-.677-.577l-9.427-1.376-4.224-8.532a.847.847 0 00-1.516 0l-4.218 8.534-9.427 1.355a.847.847 0 00-.467 1.467l6.823 6.664-1.612 9.375a.847.847 0 001.23.893l8.428-4.434 8.432 4.432a.847.847 0 001.229-.894l-1.615-9.373 6.822-6.665a.845.845 0 00.214-.869z" />
</symbol>
<symbol viewBox="0 0 160 32" id="stars">
<use xlink:href="#star" x="-64" y="0"></use>
<use xlink:href="#star" x="-32" y="0"></use>
<use xlink:href="#star" x="0" y="0"></use>
<use xlink:href="#star" x="32" y="0"></use>
<use xlink:href="#star" x="64" y="0"></use>
</symbol>
</defs>
<use xlink:href="#stars" fill="yellow" stroke="black" mask="url(#perc)"></use>
</svg>
Или по звёздам только целым
const svgStarNode = document.querySelector('.svg-star');
const quantityStars = document.querySelectorAll('#stars use').length;
svgStarNode.addEventListener('mousemove', (e) => {
const widthStarNode = svgStarNode.clientWidth;
const xPercent = Math.round((e.clientX / widthStarNode) * 100);
const basePercent = 100 / quantityStars;
const roundedPercent = Math.round(xPercent / basePercent) * basePercent;
svgStarNode.style.setProperty('--x', `${roundedPercent}%`);
});
.svg-star {
--x: 0%;
}
.svg-star .rect-percent {
x: var(--x);
}
<svg class="svg-star" width="160" height="32" viewBox="0 0 160 32">
<defs>
<mask id="perc">
<rect x="0" y="0" width="100%" height="100%" fill="white" />
<rect class="rect-percent" x="0%" y="0" width="100%" height="100%" fill="grey" />
</mask>
<symbol viewBox="0 0 32 32" id="star">
<path d="M31.547 12a.848.848 0 00-.677-.577l-9.427-1.376-4.224-8.532a.847.847 0 00-1.516 0l-4.218 8.534-9.427 1.355a.847.847 0 00-.467 1.467l6.823 6.664-1.612 9.375a.847.847 0 001.23.893l8.428-4.434 8.432 4.432a.847.847 0 001.229-.894l-1.615-9.373 6.822-6.665a.845.845 0 00.214-.869z" />
</symbol>
<symbol viewBox="0 0 160 32" id="stars">
<use xlink:href="#star" x="-64" y="0"></use>
<use xlink:href="#star" x="-32" y="0"></use>
<use xlink:href="#star" x="0" y="0"></use>
<use xlink:href="#star" x="32" y="0"></use>
<use xlink:href="#star" x="64" y="0"></use>
</symbol>
</defs>
<use xlink:href="#stars" fill="yellow" stroke="black" mask="url(#perc)"></use>
</svg>
Плюс можно обнулять процент при уведении
const svgStarNode = document.querySelector('.svg-star');
const quantityStars = document.querySelectorAll('#stars use').length;
svgStarNode.addEventListener('mousemove', (e) => {
const widthStarNode = svgStarNode.clientWidth;
const xPercent = Math.round((e.clientX / widthStarNode) * 100);
const basePercent = 100 / quantityStars;
const roundedPercent = Math.round(xPercent / basePercent) * basePercent;
svgStarNode.style.setProperty('--x', `${roundedPercent}%`);
});
svgStarNode.addEventListener('mouseout', () => {
svgStarNode.style.setProperty('--x', `0%`);
});
.svg-star {
--x: 0%;
}
.svg-star .rect-percent {
x: var(--x);
}
<svg class="svg-star" width="160" height="32" viewBox="0 0 160 32">
<defs>
<mask id="perc">
<rect x="0" y="0" width="100%" height="100%" fill="white" />
<rect class="rect-percent" x="0%" y="0" width="100%" height="100%" fill="grey" />
</mask>
<symbol viewBox="0 0 32 32" id="star">
<path d="M31.547 12a.848.848 0 00-.677-.577l-9.427-1.376-4.224-8.532a.847.847 0 00-1.516 0l-4.218 8.534-9.427 1.355a.847.847 0 00-.467 1.467l6.823 6.664-1.612 9.375a.847.847 0 001.23.893l8.428-4.434 8.432 4.432a.847.847 0 001.229-.894l-1.615-9.373 6.822-6.665a.845.845 0 00.214-.869z" />
</symbol>
<symbol viewBox="0 0 160 32" id="stars">
<use xlink:href="#star" x="-64" y="0"></use>
<use xlink:href="#star" x="-32" y="0"></use>
<use xlink:href="#star" x="0" y="0"></use>
<use xlink:href="#star" x="32" y="0"></use>
<use xlink:href="#star" x="64" y="0"></use>
</symbol>
</defs>
<use xlink:href="#stars" fill="yellow" stroke="black" mask="url(#perc)"></use>
</svg>
Плюс, так как я изменяю CSS свойство x у svg элемента, его можно плавно изменять с помощью transition
const svgStarNode = document.querySelector('.svg-star');
const quantityStars = document.querySelectorAll('#stars use').length;
svgStarNode.addEventListener('mousemove', (e) => {
const widthStarNode = svgStarNode.clientWidth;
const xPercent = Math.round((e.clientX / widthStarNode) * 100);
const basePercent = 100 / quantityStars;
const roundedPercent = Math.round(xPercent / basePercent) * basePercent;
svgStarNode.style.setProperty('--x', `${roundedPercent}%`);
});
svgStarNode.addEventListener('mouseout', () => {
svgStarNode.style.setProperty('--x', `0%`);
});
.svg-star {
--x: 0%;
}
.svg-star .rect-percent {
x: var(--x);
transition: x 0.1s ease;
}
<svg class="svg-star" width="160" height="32" viewBox="0 0 160 32">
<defs>
<mask id="perc">
<rect x="0" y="0" width="100%" height="100%" fill="white" />
<rect class="rect-percent" x="0%" y="0" width="100%" height="100%" fill="grey" />
</mask>
<symbol viewBox="0 0 32 32" id="star">
<path d="M31.547 12a.848.848 0 00-.677-.577l-9.427-1.376-4.224-8.532a.847.847 0 00-1.516 0l-4.218 8.534-9.427 1.355a.847.847 0 00-.467 1.467l6.823 6.664-1.612 9.375a.847.847 0 001.23.893l8.428-4.434 8.432 4.432a.847.847 0 001.229-.894l-1.615-9.373 6.822-6.665a.845.845 0 00.214-.869z" />
</symbol>
<symbol viewBox="0 0 160 32" id="stars">
<use xlink:href="#star" x="-64" y="0"></use>
<use xlink:href="#star" x="-32" y="0"></use>
<use xlink:href="#star" x="0" y="0"></use>
<use xlink:href="#star" x="32" y="0"></use>
<use xlink:href="#star" x="64" y="0"></use>
</symbol>
</defs>
<use xlink:href="#stars" fill="yellow" stroke="black" mask="url(#perc)"></use>
</svg>
