#jquery #html #css
#jquery #HTML #css
Вопрос:
Живая демонстрация: http://jsfiddle.net/stapiagutierrez/KKdsb/29 /
Я просто пытаюсь создать свой собственный пользовательский интерфейс с рейтингом звезд для веб-сайтов, и пока он работает именно так, как я хочу, но я хотел бы посмотреть, смогу ли я урезать свой код, не жертвуя удобочитаемостью.
Поскольку я новичок в jQuery, возможно, я делаю все окольным путем.
Есть предложения по улучшению?
ul {
list-style-type:none;
margin-top:10px;
margin-left:10px;
border:1px solid #333;
border-radius:8px;
overflow:hidden;
width:111px;
cursor:pointer;
}
li {
float:left;
margin-left:5px;
padding-top:2px;
}
<ul>
<li>
<img class="onestar rating" src="http://i.imgur.com/8LA1i.png" alt="no-star" />
</li>
<li>
<img class="twostar rating" src="http://i.imgur.com/8LA1i.png" alt="no-star" />
</li>
<li>
<img class="threestar rating" src="http://i.imgur.com/8LA1i.png" alt="no-star" />
</li>
<li>
<img class="fourstar rating" src="http://i.imgur.com/8LA1i.png" alt="no-star" />
</li>
<li>
<img class="fivestar rating" src="http://i.imgur.com/8LA1i.png" alt="no-star" />
</li>
</ul>
$(document).ready(function() {
$(".rating").click(function() {
if ($(this).hasClass("onestar")) {
alert("Clicked on 1 star!");
}
else if ($(this).hasClass("twostar")) {
alert("Clicked on 2 stars!");
}
else if ($(this).hasClass("threestar")) {
alert("Clicked on 3 stars!");
}
else if ($(this).hasClass("fourstar")) {
alert("Clicked on 4 stars!");
}
else if ($(this).hasClass("fivestar")) {
alert("Clicked on 5 stars!");
}
});
$(".rating").mouseleave(function() {
$(".rating").each(function() {
$(this).attr("src", "http://i.imgur.com/8LA1i.png");
});
});
$(".rating").mouseover(function() {
if ($(this).hasClass("onestar")) {
$(".onestar").attr('src', 'http://i.imgur.com/X68bI.png');
}
else if ($(this).hasClass("twostar")) {
$(".onestar").attr('src', 'http://i.imgur.com/X68bI.png');
$(".twostar").attr('src', 'http://i.imgur.com/X68bI.png');
}
else if ($(this).hasClass("threestar")) {
$(".onestar").attr('src', 'http://i.imgur.com/X68bI.png');
$(".twostar").attr('src', 'http://i.imgur.com/X68bI.png');
$(".threestar").attr('src', 'http://i.imgur.com/X68bI.png');
}
else if ($(this).hasClass("fourstar")) {
$(".onestar").attr('src', 'http://i.imgur.com/X68bI.png');
$(".twostar").attr('src', 'http://i.imgur.com/X68bI.png');
$(".threestar").attr('src', 'http://i.imgur.com/X68bI.png');
$(".fourstar").attr('src', 'http://i.imgur.com/X68bI.png');
}
else if ($(this).hasClass("fivestar")) {
$(".onestar").attr('src', 'http://i.imgur.com/X68bI.png');
$(".twostar").attr('src', 'http://i.imgur.com/X68bI.png');
$(".threestar").attr('src', 'http://i.imgur.com/X68bI.png');
$(".fourstar").attr('src', 'http://i.imgur.com/X68bI.png');
$(".fivestar").attr('src', 'http://i.imgur.com/X68bI.png');
}
});
});
Комментарии:
1. Пожалуйста, также включите сюда код jquery — если jsfiddle выйдет из строя, этот вопрос не может много значить для кого-либо еще.
Ответ №1:
Это было довольно забавно, вот jsFiddle: http://jsfiddle.net/KKdsb/30 /
ПРИМЕЧАНИЕ: использование двух parent()
функций в mouseover
обработчике зависит от вашей структуры html. Я бы рекомендовал класс или аналогичный для прямого доступа к родительскому <ul>
элементу $(this).closest('.classname')
.
Код jQuery:
$(document).ready(function() {
$(".rating").click(function() {
var position = $(this).parent().index();
});
$(".rating").mouseleave(function() {
$(".rating").each(function() {
$(this).attr("src", "http://i.imgur.com/8LA1i.png");
});
});
$(".rating").mouseover(function() {
var position = $(this).parent().index() 1;
$(this).parent().parent().find("li:lt(" position ") > img").each(function (i, e) {
$(e).attr('src', 'http://i.imgur.com/X68bI.png');
});
});
});
Ссылка:
Комментарии:
1. Привет, Андре — я отредактировал ваш ответ, чтобы поменять .parent() на .parents() , но я думаю .closest() — это то, что вы хотите. .closest() остановится, когда достигнет первого совпадения, где .parents() продолжит движение вверх по дереву DOM в поисках дальнейших совпадений.
2. Привет, Beejamin, я отредактировал свой ответ, чтобы включить
closest()
, спасибо за предложение!
Ответ №2:
Это отличный кандидат для использования спрайтов изображений. По сути, вы помещаете все свои звездные рейтинги в один файл изображения и перемещаете этот файл с помощью CSS ‘background-position’. Основное преимущество этого способа заключается в том, что вы делаете только один запрос для изображения звезды — вы не меняете путь к начальному изображению повторно (что может сделать работу немного неудобной и медленной, в зависимости от браузера.
Вот пример использования спрайтов изображений: http://www.spookandpuff.com/examples/starRatings/starRatings.html
Вот спрайт изображения, который я использовал:
А вот HTML, CSS и Javascript:
HTML очень прост:
<div class="starRating">
<ol class="ratingValues">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ol>
</div>
Можно обойтись без дополнительного DIV, но это вызовет проблемы в старых браузерах, которые не поддерживают селекторы CSS с несколькими классами, поэтому я оставил его.
CSS также довольно прост:
.starRating {
width:105px;
height:20px;
float:left;
margin:20px 0;
}
.ratingValues {
float:left;
width:100%;
list-style:none;
background:url(starSprite.png) no-repeat 0 0;
}
.ratingValues li{
display:block;
float:left;
width:21px;
height:20px;
text-indent:-999em;
overflow:hidden;
cursor:pointer;
}
.rating_1 .ratingValues {background-position:0 -20px}
.rating_2 .ratingValues {background-position:0 -40px}
.rating_3 .ratingValues {background-position:0 -60px}
.rating_4 .ratingValues {background-position:0 -80px}
.rating_5 .ratingValues {background-position:0 -100px}
Здесь мы настраиваем поле таким же размером, как один ряд звездочек из спрайта. Элементы списка становятся квадратами нужного размера (по одному квадрату на «звезду» на графике). Я использовал отрицательный текстовый отступ, чтобы скрыть текст внутри каждого <li>
.
Наиболее интересным является последний блок. Здесь мы настраиваем положение фона спрайта в зависимости от класса содержащего элемента, поэтому, когда .ratingValues находится внутри чего-либо с классом ‘rating_3’, фон переместится в положение: 0 -60px.
Бьюсь об заклад, вы видите, к чему это ведет. Вот javascript:
$(function(){
starRatings = $('.starRating'); //Cache this to make future references faster
starRatings.each(function(){ //Iterate through each rating, in case there's more than one per page
var thisRating = $(this),
triggers = $('.ratingValues > li', this); //More caching
triggers
.hover(
function(){ //The hover-over event
var trigger = this;
thisRating.addClass(function(){
return 'rating_' (triggers.index(trigger) 1); //This sets the class to rating_ the number of the element (1 - 5)
})
},
function(){ //The hover-out event, just clears the classes
thisRating.removeClass('rating_1 rating_2 rating_3 rating_4 rating_5');
})
.click(function(){ //The click event
alert('Clicked ' (triggers.index(this) 1));
});
});
});
Это находит любой элемент с классом of .starRating
и назначает обработчики событий для <li>
s внутри него. Наведение курсора мыши на <li>
s присваивает класс div-элементу ‘StarRating’, который в основном сообщает нам, какое значение выбрано (от rating_1 до rating_5). На этом этапе запускается CSS и перемещает фоновый спрайт в нужное положение.
Для дополнительных очков вы можете поставить стандартный якорь, что-то вроде этого: <a href="{rateThis?rating=1}">1</a>
внутри каждого LI
, который отправит запрос на ваш сервер и установит рейтинг по прямому HTTP (без javascript). Таким образом, все по-прежнему работает, если Javascript отключен.
Надеюсь, это достаточно ясно — кричите, если вам нужна дополнительная помощь!
Комментарии:
1. Мне кажется, что ОП просит упростить его код. Вы увеличили сложность, но в итоге получили такой же объем общего кода. Является ли использование спрайтов изображений хорошей идеей? Да! Но ваше решение вряд ли лучше оригинального.
2. ОП сказал, что он новичок в jQuery, поэтому я привел пример с большим количеством объяснений и безопасности в виде кэширования, чтобы это решение было надежным и пригодным для повторного использования. В нем показаны некоторые полезные приемы для начинающих в работе с DOM, обработке событий jQuery и взаимодействии CSS / JS. Я поддерживаю это. Уменьшение сложности зависит не только от объема кода, но и от того, насколько он понятен.
3. Не совсем ответ на вопрос, но я думаю, что это отличный вариант. Мне на самом деле очень нравится, как звезды заполняют спрайты, JS выглядит здесь немного медленно. Я бы полностью пошел на это в будущих проектах 🙂
4. Другая, более реальная проблема: как вы собираетесь отображать частичные оценки? Т.е. Оценка 4,5 amazon.com/Greatest-Hits-2/product-reviews/B005SO6HT6 /…
5. Изображение спрайта можно легко расширить, чтобы покрыть половину или четверть точек. Это не было бы хорошим решением, если бы вам нужно было показать большую точность, чем это.
Ответ №3:
Улучшенное решение
HTML:
<div>
<div class="rating"><div class="value"></div></div>
</div>
CSS:
.rating {
width:105px;
height:20px;
background: url(http://i.stack.imgur.com/oZ9Id.png) no-repeat;
cursor:pointer;
}
.rating .value {
width:0;
height:20px;
background: url(http://i.stack.imgur.com/oZ9Id.png) no-repeat 0px -100px;
}
Javascript
$(document).ready(function() {
var starWidth = $(".rating").width() / 5;
$(".rating").click(function(e) {
$(this).find(".value").css({width:(Math.ceil(e.offsetX / starWidth) * starWidth) "px"});
});
});
Оригинальное решение: здесь
Плюсы этого решения по сравнению с другими в этой теме:
- Минимальное количество кода, разметки и CSS. Очень легко читать и поддерживать.
- Решает общую проблему дизайна в операционной системе, а не пытается исправить ее с помощью jQuery sugar.
- Поддерживает оценки с плавающей запятой (просто установите ширину на значение / MaxWidth)
- Поддерживает переключение между интерактивными и доступными только для чтения представлениями путем простого отключения события щелчка (нет необходимости изменять HTML).
- После 3 и 4 — это единый элемент управления для отображения как индивидуальных пользовательских оценок, так и составных оценок.
- Меньший размер изображения, чем требуется для ответа Beejamin (он использует только первую и последнюю строки).
- Никаких сложных манипуляций с DOM или поисков в CSS
Минусы: я ничего не вижу.
Минусы исправлены с момента последней итерации:
- Удалена зависимость js от ширины изображения. Теперь он вычисляется динамически, хотя я все еще думаю, что в этом нет необходимости.
Полная и полностью функциональная версия здесь. Необычная версия с анимацией щелчка здесь
Комментарии:
1. Тогда как вы определяете, сколько звезд показывать? Вы проверяете положение X, в котором мышь находится в элементе? Это звучит сложнее без причины.
2. Разве это не было бы лучшим комментарием, чем ответом?
3. @SergioTapia почему это сложно?
4. @Flimzy у него нет проблемы с jQuery. У него есть общая проблема с дизайном, которую он пытается решить с помощью jQuery, что довольно бессмысленное занятие.
5. Ну, вы должны рассчитать ширину каждой отдельной звезды и убедиться, что она центрирована.