Chuyển một số thành hiển thị xếp hạng sao bằng jQuery và CSS


101

Tôi đã xem xét plugin jquery và tự hỏi làm thế nào để điều chỉnh plugin đó để biến một số (như 4.8618164) thành 4.8618164 sao được điền trên 5. Về cơ bản, diễn giải một số <5 thành sao được điền vào hệ thống xếp hạng 5 sao bằng jQuery / JS / CSS.

Lưu ý rằng điều này sẽ chỉ hiển thị / hiển thị xếp hạng sao từ một số đã có sẵn và không chấp nhận các bài gửi xếp hạng mới.


Câu trả lời:


255

Đây là một giải pháp cho bạn, chỉ sử dụng một hình ảnh rất nhỏ và đơn giản và một phần tử span được tạo tự động:

CSS

span.stars, span.stars span {
    display: block;
    background: url(stars.png) 0 -16px repeat-x;
    width: 80px;
    height: 16px;
}

span.stars span {
    background-position: 0 0;
}

Hình ảnh

văn bản thay thế
(nguồn: ulmanen.fi )

Lưu ý: làm KHÔNG Hotlink đến hình ảnh trên! Sao chép tệp vào máy chủ của riêng bạn và sử dụng nó từ đó.

jQuery

$.fn.stars = function() {
    return $(this).each(function() {
        // Get the value
        var val = parseFloat($(this).html());
        // Make sure that the value is in 0 - 5 range, multiply to get width
        var size = Math.max(0, (Math.min(5, val))) * 16;
        // Create stars holder
        var $span = $('<span />').width(size);
        // Replace the numerical value with stars
        $(this).html($span);
    });
}

Nếu bạn muốn giới hạn các dấu sao ở kích thước chỉ một nửa hoặc một phần tư sao, hãy thêm một trong các hàng sau trước var sizehàng:

val = Math.round(val * 4) / 4; /* To round to nearest quarter */
val = Math.round(val * 2) / 2; /* To round to nearest half */

HTML

<span class="stars">4.8618164</span>
<span class="stars">2.6545344</span>
<span class="stars">0.5355</span>
<span class="stars">8</span>

Sử dụng

$(function() {
    $('span.stars').stars();
});

Đầu ra

Hình ảnh từ bộ biểu tượng fugue (www.pinvoke.com)
(nguồn: ulmanen.fi )

Bản giới thiệu

http://www.ulmanen.fi/stuff/stars.php

Điều này có thể sẽ phù hợp với nhu cầu của bạn. Với phương pháp này, bạn không phải tính toán bất kỳ phần tư ba phần tư hoặc chiều rộng sao nào, chỉ cần đặt nó là float và nó sẽ cung cấp cho bạn số sao của bạn.


Một lời giải thích nhỏ về cách các ngôi sao được trình bày theo thứ tự.

Tập lệnh tạo hai phần tử nhịp cấp khối. Cả hai nhịp đều có kích thước 80px * 16px và hình nền là stars.png. Các nhịp được lồng vào nhau, do đó cấu trúc của các nhịp trông như thế này:

<span class="stars">
    <span></span>
</span>

Khoảng ngoài nhận được một background-positiontrong số 0 -16px. Điều đó làm cho các ngôi sao màu xám ở khoảng ngoài có thể nhìn thấy được. Vì nhịp ngoài có chiều cao 16px và repeat-x, nó sẽ chỉ hiển thị 5 ngôi sao màu xám.

Tuổi bên trong, mặt khác có một background-positionsố 0 0mà làm cho chỉ những ngôi sao màu vàng có thể nhìn thấy.

Điều này tất nhiên sẽ hoạt động với hai tệp hình ảnh riêng biệt, star_yellow.png và star_gray.png. Nhưng vì các ngôi sao có chiều cao cố định, chúng ta có thể dễ dàng kết hợp chúng thành một hình ảnh. Điều này sử dụng kỹ thuật sprite CSS .

Bây giờ, khi các nhịp được lồng vào nhau, chúng sẽ tự động được xếp chồng lên nhau. Trong trường hợp mặc định, khi chiều rộng của cả hai nhịp là 80px, các ngôi sao màu vàng sẽ che khuất hoàn toàn các ngôi sao màu xám.

Nhưng khi ta điều chỉnh độ rộng của nhịp bên trong thì độ rộng của các ngôi sao màu vàng giảm đi, để lộ ra các ngôi sao màu xám.

Về khả năng tiếp cận, sẽ khôn ngoan hơn nếu để số thực bên trong khoảng bên trong và ẩn nó đi text-indent: -9999px, để những người đã tắt CSS ít nhất sẽ thấy số dấu phẩy động thay vì dấu sao.

Hy vọng rằng điều đó có ý nghĩa.


Cập nhật 2010/10/22

Bây giờ thậm chí còn nhỏ gọn hơn và khó hiểu hơn! Cũng có thể được ép xuống một lớp lót:

$.fn.stars = function() {
    return $(this).each(function() {
        $(this).html($('<span />').width(Math.max(0, (Math.min(5, parseFloat($(this).html())))) * 16));
    });
}

@Tatu, bất kỳ cơ hội nào để bổ sung thêm một chút với cách hoạt động của nó. Kiến thức của tôi về jQuery chỉ là một chút thời gian ngắn để hoàn toàn hiểu được nó. Tôi nghĩ rằng tôi hiểu cách CSS hoạt động với việc lặp lại theo hướng x và 16 * 5 = 80 bit và cách bạn điều chỉnh chiều rộng của hình ảnh ngôi sao màu vàng, nhưng làm cách nào để bạn chồng hai hình ảnh lên nhau từ một hình ảnh duy nhất có một ngôi sao phía trên ngôi sao kia? -16px có đưa ngôi sao màu xám lên cùng mức với màu vàng không?
paxdiablo

Cảm ơn vì bản cập nhật, @Tatu, điều đó có ý nghĩa hơn đối với tôi bây giờ. Rất tiếc, tôi đã cho bạn +1 nên tôi không thể làm lại lần nữa nhưng hy vọng lời giải thích sẽ giúp bạn kiếm được thêm một số đại diện (kiếm được tốt). Chúc mừng.
paxdiablo

2
@paxdiablo và những người khác, cảm ơn vì sự hỗ trợ. Có lẽ tôi nên làm điều này một jQuery thích cắm như kỹ thuật này có vẻ gì đáng ngạc nhiên đối với hầu hết :)
Tatu Ulmanen

@Tatu, cảm ơn vô cùng. Tất cả các plugin năm sao hiện có dường như đều muốn có một biểu mẫu phù hợp để đưa vào xếp hạng, nhưng quá mức cần thiết để thay đổi biểu diễn của một số.
vfilby

7
Hoặc thậm chí nhỏ hơn: jsbin.com/IBIDalEn/2/edit (PS đã loại bỏ những thứ không cần thiết trong JS, bộ chọn CSS được rút gọn và được sử dụng max-width).
Roko C. Buljan

30

Nếu bạn chỉ phải hỗ trợ các trình duyệt hiện đại, bạn có thể sử dụng:

  • Không có hình ảnh;
  • Chủ yếu là css tĩnh;
  • Gần như không có jQuery hoặc Javascript;

Bạn chỉ cần chuyển đổi số thành a class, ví dụ class='stars-score-50'.

Đầu tiên là bản demo về đánh dấu "được kết xuất":

body { font-size: 18px; }

.stars-container {
  position: relative;
  display: inline-block;
  color: transparent;
}

.stars-container:before {
  position: absolute;
  top: 0;
  left: 0;
  content: '★★★★★';
  color: lightgray;
}

.stars-container:after {
  position: absolute;
  top: 0;
  left: 0;
  content: '★★★★★';
  color: gold;
  overflow: hidden;
}

.stars-0:after { width: 0%; }
.stars-10:after { width: 10%; }
.stars-20:after { width: 20%; }
.stars-30:after { width: 30%; }
.stars-40:after { width: 40%; }
.stars-50:after { width: 50%; }
.stars-60:after { width: 60%; }
.stars-70:after { width: 70%; }
.stars-80:after { width: 80%; }
.stars-90:after { width: 90%; }
.stars-100:after { width: 100; }
Within block level elements:

<div><span class="stars-container stars-0">★★★★★</span></div>
<div><span class="stars-container stars-10">★★★★★</span></div>
<div><span class="stars-container stars-20">★★★★★</span></div>
<div><span class="stars-container stars-30">★★★★★</span></div>
<div><span class="stars-container stars-40">★★★★★</span></div>
<div><span class="stars-container stars-50">★★★★★</span></div>
<div><span class="stars-container stars-60">★★★★★</span></div>
<div><span class="stars-container stars-70">★★★★★</span></div>
<div><span class="stars-container stars-80">★★★★★</span></div>
<div><span class="stars-container stars-90">★★★★★</span></div>
<div><span class="stars-container stars-100">★★★★★</span></div>

<p>Or use it in a sentence: <span class="stars-container stars-70">★★★★★</span> (cool, huh?).</p>

Sau đó, một bản demo sử dụng một chút mã:

$(function() {
  function addScore(score, $domElement) {
    $("<span class='stars-container'>")
      .addClass("stars-" + score.toString())
      .text("★★★★★")
      .appendTo($domElement);
  }

  addScore(70, $("#fixture"));
});
body { font-size: 18px; }

.stars-container {
  position: relative;
  display: inline-block;
  color: transparent;
}

.stars-container:before {
  position: absolute;
  top: 0;
  left: 0;
  content: '★★★★★';
  color: lightgray;
}

.stars-container:after {
  position: absolute;
  top: 0;
  left: 0;
  content: '★★★★★';
  color: gold;
  overflow: hidden;
}

.stars-0:after { width: 0%; }
.stars-10:after { width: 10%; }
.stars-20:after { width: 20%; }
.stars-30:after { width: 30%; }
.stars-40:after { width: 40%; }
.stars-50:after { width: 50%; }
.stars-60:after { width: 60%; }
.stars-70:after { width: 70%; }
.stars-80:after { width: 80%; }
.stars-90:after { width: 90%; }
.stars-100:after { width: 100; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Generated: <div id="fixture"></div>

Nhược điểm lớn nhất của giải pháp này là:

  1. Bạn cần các dấu sao bên trong phần tử để tạo ra chiều rộng chính xác;
  2. Không có đánh dấu ngữ nghĩa, ví dụ như bạn muốn điểm số dưới dạng văn bản bên trong phần tử;
  3. Nó chỉ cho phép có bao nhiêu điểm số mà bạn sẽ có các lớp (vì chúng tôi không thể sử dụng Javascript để đặt chính xác widthcho một phần tử giả).

Để khắc phục điều này, giải pháp trên có thể được tinh chỉnh dễ dàng. Các bit :before:afterbit cần phải trở thành các phần tử thực tế trong DOM (vì vậy chúng tôi cần một số JS cho điều đó).

Phần sau được để lại như một lời khích lệ cho người đọc.


3
Tôi đã mở rộng giải pháp này để phù hợp với các điểm số nổi và được tạo động không vừa với phần 10 của 100. Codepen . Cảm ơn vì đã giúp tôi bắt đầu: D
cameck

Đây là một kịch bản khá ngọt ngào
Nick Div

1
Giải pháp hoàn hảo. Bạn đã làm nên ngày của tôi. Cảm ơn @Jeroen ... tiếp tục rung chuyển.
Prabhu Nandan Kumar

22

Hãy thử hàm / tệp trình trợ giúp jquery này

jquery.Rating.js

//ES5
$.fn.stars = function() {
    return $(this).each(function() {
        var rating = $(this).data("rating");
        var fullStar = new Array(Math.floor(rating + 1)).join('<i class="fas fa-star"></i>');
        var halfStar = ((rating%1) !== 0) ? '<i class="fas fa-star-half-alt"></i>': '';
        var noStar = new Array(Math.floor($(this).data("numStars") + 1 - rating)).join('<i class="far fa-star"></i>');
        $(this).html(fullStar + halfStar + noStar);
    });
}

//ES6
$.fn.stars = function() {
    return $(this).each(function() {
        const rating = $(this).data("rating");
        const numStars = $(this).data("numStars");
        const fullStar = '<i class="fas fa-star"></i>'.repeat(Math.floor(rating));
        const halfStar = (rating%1!== 0) ? '<i class="fas fa-star-half-alt"></i>': '';
        const noStar = '<i class="far fa-star"></i>'.repeat(Math.floor(numStars-rating));
        $(this).html(`${fullStar}${halfStar}${noStar}`);
    });
}

index.html

   <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Star Rating</title>
        <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/css/all.min.css" rel="stylesheet">
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
        <script src="js/jquery.Rating.js"></script>
        <script>
            $(function(){
                $('.stars').stars();
            });
        </script>
    </head>
    <body>

        <span class="stars" data-rating="3.5" data-num-stars="5" ></span>

    </body>
    </html>

Ảnh chụp màn hình


Chỉ cần lưu ý rằng thẻ đóng </script> bị thiếu :)
Rob Stocki

7

Tại sao không chỉ có năm hình ảnh riêng biệt của một ngôi sao (trống, đầy một phần tư, một nửa đầy đủ, ba phần tư đầy đủ và đầy đủ) sau đó chỉ cần đưa các hình ảnh vào DOM của bạn tùy thuộc vào giá trị xếp hạng bị cắt ngắn hoặc bị cắt nhân với 4 ( để có được một số nguyên cho các phần tư)?

Ví dụ: 4,8618164 nhân với 4 và làm tròn là 19 sẽ là bốn và ba sao phần tư.

Ngoài ra (nếu bạn lười như tôi), chỉ cần chọn một hình ảnh từ 21 (0 sao đến 5 sao với gia số 1/4) và chọn hình ảnh duy nhất dựa trên giá trị nói trên. Sau đó, nó chỉ là một phép tính theo sau là thay đổi hình ảnh trong DOM (thay vì cố gắng thay đổi năm hình ảnh khác nhau).


5

Tôi đã kết thúc hoàn toàn không sử dụng JS để tránh độ trễ hiển thị phía máy khách. Để thực hiện điều đó, tôi tạo HTML như sau:

<span class="stars" title="{value as decimal}">
    <span style="width={value/5*100}%;"/>
</span>

Để trợ giúp khả năng tiếp cận, tôi thậm chí còn thêm giá trị xếp hạng thô trong thuộc tính title.


4

sử dụng jquery không có nguyên mẫu, hãy cập nhật mã js thành

$( ".stars" ).each(function() { 
    // Get the value
    var val = $(this).data("rating");
    // Make sure that the value is in 0 - 5 range, multiply to get width
    var size = Math.max(0, (Math.min(5, val))) * 16;
    // Create stars holder
    var $span = $('<span />').width(size);
    // Replace the numerical value with stars
    $(this).html($span);
});

Tôi cũng đã thêm một thuộc tính dữ liệu theo tên của xếp hạng dữ liệu trong khoảng thời gian.

<span class="stars" data-rating="4" ></span>

2

BẢN GIỚI THIỆU

Bạn có thể làm điều đó chỉ với 2 hình ảnh. 1 sao trống, 1 sao điền.

Xếp chồng hình ảnh đã lấp đầy lên trên hình ảnh còn lại. và chuyển đổi số xếp hạng thành tỷ lệ phần trăm và sử dụng nó làm chiều rộng của hình ảnh lấp đầy.

nhập mô tả hình ảnh ở đây

.containerdiv {
  border: 0;
  float: left;
  position: relative;
  width: 300px;
} 
.cornerimage {
  border: 0;
  position: absolute;
  top: 0;
  left: 0;
  overflow: hidden;
 } 
 img{
   max-width: 300px;
 }

0

Đây là cách tôi sử dụng JSX và phông chữ tuyệt vời, bị giới hạn ở độ chính xác chỉ .5, mặc dù:

       <span>
          {Array(Math.floor(rating)).fill(<i className="fa fa-star"></i>)}
          {(rating) - Math.floor(rating)==0 ? ('') : (<i className="fa fa-star-half"></i>)}
       </span>

Hàng đầu tiên là toàn bộ sao và hàng thứ hai là nửa sao (nếu có)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.