เปลี่ยนตัวเลขให้เป็นการแสดงระดับดาวโดยใช้ jQuery และ CSS


101

ฉันดูปลั๊กอิน jquery และสงสัยว่าจะปรับปลั๊กอินนั้นอย่างไรเพื่อเปลี่ยนตัวเลข (เช่น 4.8618164) ให้เป็น 4.8618164 ดาวที่เต็มไปด้วย 5 โดยทั่วไปการตีความตัวเลข <5 เป็นดาวที่เต็มไปด้วยระบบการให้คะแนนระดับ 5 ดาวโดยใช้ jQuery / JS / CSS

โปรดทราบว่าสิ่งนี้จะแสดง / แสดงการจัดอันดับดาวจากจำนวนที่มีอยู่แล้วเท่านั้นและไม่ยอมรับการส่งการให้คะแนนใหม่


คำตอบ:


255

นี่เป็นวิธีแก้ปัญหาสำหรับคุณโดยใช้ภาพขนาดเล็กและเรียบง่ายเพียงภาพเดียวและองค์ประกอบช่วงที่สร้างขึ้นโดยอัตโนมัติเพียงภาพเดียว:

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;
}

ภาพ

ข้อความแสดงแทน
(ที่มา: ulmanen.fi )

หมายเหตุ:ไม่ไม่ hotlink กับภาพดังกล่าวข้างต้น! คัดลอกไฟล์ไปยังเซิร์ฟเวอร์ของคุณเองและใช้งานจากที่นั่น

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);
    });
}

หากคุณต้องการ จำกัด ดาวให้มีขนาดดาวเพียงครึ่งเดียวหรือสี่ส่วนให้เพิ่มแถวใดแถวหนึ่งเหล่านี้ก่อนvar sizeแถว:

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>

การใช้งาน

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

เอาต์พุต

ภาพจากชุดไอคอน fugue (www.pinvoke.com)
(ที่มา: ulmanen.fi )

การสาธิต

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

สิ่งนี้อาจเหมาะกับความต้องการของคุณ ด้วยวิธีนี้คุณไม่จำเป็นต้องคำนวณความกว้างสามในสี่หรืออะไรไม่ใช่ความกว้างของดาวเพียงแค่ให้มันลอยแล้วมันจะให้ดาวของคุณ


คำอธิบายเล็กน้อยเกี่ยวกับวิธีการนำเสนอของดวงดาว

สคริปต์สร้างสององค์ประกอบช่วงระดับบล็อก ทั้งสองช่วงเริ่มต้นมีขนาด 80px * 16px และภาพพื้นหลัง stars.png ช่วงจะซ้อนกันเพื่อให้โครงสร้างของช่วงมีลักษณะดังนี้:

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

ช่วงด้านนอกได้รับของbackground-position 0 -16pxนั่นทำให้มองเห็นดวงดาวสีเทาในช่วงนอก เนื่องจากช่วงนอกมีความสูง 16px และrepeat-xจะแสดงเพียง 5 ดาวสีเทา

ช่วงด้านบนมืออื่น ๆ มีbackground-positionของ0 0ซึ่งทำให้เพียงดาวสีเหลืองมองเห็นได้

แน่นอนว่าสิ่งนี้จะใช้ได้กับไฟล์ภาพสองไฟล์ที่แยกจากกัน star_yellow.png และ star_gray.png แต่เนื่องจากดวงดาวมีความสูงคงที่เราจึงสามารถรวมเป็นภาพเดียวได้อย่างง่ายดาย นี้ใช้เทคนิค CSS เทพดา

ขณะนี้เมื่อมีการซ้อนทับกันแล้วช่วงเวลาดังกล่าวจะซ้อนทับกันโดยอัตโนมัติ ในกรณีเริ่มต้นเมื่อความกว้างของทั้งสองช่วงคือ 80px ดาวสีเหลืองจะบดบังดาวสีเทาอย่างสมบูรณ์

แต่เมื่อเราปรับความกว้างของช่วงภายในความกว้างของดาวสีเหลืองจะลดลงเผยให้เห็นดาวสีเทา

การช่วยสำหรับการเข้าถึงมันจะเป็นการดีกว่าที่จะปล่อยให้ตัวเลขลอยอยู่ในช่วงภายในและซ่อนไว้ด้วยtext-indent: -9999pxเพื่อให้อย่างน้อยคนที่ปิด CSS จะเห็นตัวเลขทศนิยมแทนที่จะเป็นดาว

หวังว่าจะสมเหตุสมผลบ้าง


อัปเดตเมื่อ 2010/10/22

ตอนนี้กระชับและเข้าใจยากยิ่งขึ้น! สามารถบีบลงไปที่ซับเดียวได้:

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

@Tatu โอกาสใด ๆ ที่จะสร้างมันขึ้นมาอีกเล็กน้อยด้วยวิธีการทำงานนี้ ความรู้เกี่ยวกับ jQuery ของฉันเป็นเพียงสั้น ๆ ที่จะเข้าใจได้ทั้งหมด ฉันคิดว่าฉันเข้าใจว่า CSS ทำงานอย่างไรกับการทำซ้ำในทิศทาง x และ 16 * 5 = 80 บิตและวิธีที่คุณปรับความกว้างของภาพดาวสีเหลือง แต่คุณจะซ้อนทับภาพสองภาพที่ด้านบนซึ่งกันและกันจาก a ภาพเดียวที่มีหนึ่งดาวเหนืออีกภาพ? -16px ทำให้ดาวสีเทาอยู่ในระดับเดียวกับสีเหลืองหรือไม่?
paxdiablo

ขอบคุณสำหรับการอัปเดต @Tatu ที่ทำให้รู้สึกดีขึ้นมากสำหรับฉันตอนนี้ น่าเสียดายที่ฉันให้ +1 กับคุณไปแล้วดังนั้นฉันจึงไม่สามารถทำได้อีก แต่หวังว่าคำอธิบายจะทำให้คุณได้รับตัวแทน (รายได้ดี) เพิ่มขึ้น ไชโย
paxdiablo

2
@paxdiablo และอื่น ๆ ขอบคุณสำหรับการสนับสนุน บางทีฉันควรทำให้เป็นปลั๊กอิน jQuery ที่เหมาะสมเนื่องจากเทคนิคนี้ดูเหมือนจะเป็นเรื่องที่น่าแปลกใจสำหรับคนส่วนใหญ่ :)
Tatu Ulmanen

@Tatu ขอบคุณมาก ปลั๊กอินระดับห้าดาวที่มีอยู่ทั้งหมดดูเหมือนจะต้องการรูปแบบที่ดีสำหรับการป้อนการให้คะแนน แต่วิธีที่มากเกินไปในการเปลี่ยนการแสดงตัวเลข
vfilby

7
หรือเล็กกว่านั้น: jsbin.com/IBIDalEn/2/edit (PS ลบสิ่งที่ไม่จำเป็นออกใน JS ตัวเลือก CSS ที่ย่อขนาดและใช้แล้วmax-width)
Roko C.Buljan

30

หากคุณต้องรองรับเบราว์เซอร์ที่ทันสมัยเท่านั้นคุณสามารถหลีกเลี่ยงสิ่งต่อไปนี้

  • ไม่มีภาพ;
  • css คงที่ส่วนใหญ่ ;
  • แทบไม่มี jQuery หรือ Javascript

คุณจะต้องแปลงตัวเลขให้เป็นเช่นclassclass='stars-score-50'

ก่อนอื่นการสาธิตมาร์กอัป "แสดงผล":

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>

จากนั้นการสาธิตที่ใช้รหัสเล็กน้อย:

$(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>

ข้อเสียที่ใหญ่ที่สุดของโซลูชันนี้คือ:

  1. คุณต้องมีดาวในองค์ประกอบเพื่อสร้างความกว้างที่ถูกต้อง
  2. ไม่มีมาร์กอัปเชิงความหมายเช่นคุณต้องการให้คะแนนเป็นข้อความภายในองค์ประกอบ
  3. อนุญาตให้ทำคะแนนได้มากเท่าที่คุณจะมีชั้นเรียนเท่านั้น (เนื่องจากเราไม่สามารถใช้ Javascript เพื่อกำหนดwidthองค์ประกอบหลอกได้อย่างแม่นยำ)

ในการแก้ไขปัญหานี้สามารถปรับแต่งโซลูชันข้างต้นได้อย่างง่ายดาย :beforeและ:afterบิตต้องกลายเป็นองค์ประกอบที่เกิดขึ้นจริงได้ใน DOM (ดังนั้นเราจึงจำเป็น JS บางสำหรับที่)

หลังถูกปล่อยให้เป็นแบบฝึกหัดสำหรับผู้อ่าน


3
ผมขยายการแก้ปัญหานี้เพื่อรองรับลอยและคะแนนที่สร้างแบบไดนามิกที่ไม่พอดีกับ 10ths ของ 100 Codepen ขอบคุณที่ทำให้ฉันเริ่มต้น: D
cameck

นี่เป็นบทที่น่ารัก
Nick Div

1
โซลูชั่นที่สมบูรณ์แบบ คุณทำให้วันของฉัน ขอบคุณ @Jeroen ... โยกต่อไป
Prabhu Nandan Kumar

22

ลองใช้ฟังก์ชัน / ไฟล์ jquery helper

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>

ภาพหน้าจอ


โปรดทราบว่าแท็กปิด </script> หายไป :)
Rob Stocki

7

ทำไมไม่เพียงแค่มีภาพดาวห้าภาพแยกกัน (ว่างเปล่าเต็มไตรมาสครึ่งเต็มสามในสี่เต็มและเต็ม) จากนั้นฉีดภาพลงใน DOM ของคุณโดยขึ้นอยู่กับค่าการจัดอันดับที่ถูกตัดทอนหรือเป็นสีแดงคูณด้วย 4 ( เพื่อรับตัวเลขทั้งหมดสำหรับไตรมาส)?

ตัวอย่างเช่น 4.8618164 คูณด้วย 4 และปัดเศษคือ 19 ซึ่งจะเป็นดาวสี่และสามดวง

อีกทางเลือกหนึ่ง (ถ้าคุณขี้เกียจเหมือนฉัน) เพียงแค่เลือกภาพหนึ่งภาพจาก 21 (0 ดาวถึง 5 ดาวโดยเพิ่มขึ้นทีละหนึ่งในสี่) แล้วเลือกภาพเดียวตามค่าที่กล่าวมา จากนั้นเป็นการคำนวณเพียงครั้งเดียวตามด้วยการเปลี่ยนแปลงรูปภาพใน DOM (แทนที่จะพยายามเปลี่ยนรูปภาพห้ารูป)


5

ฉันลงเอยด้วยการใช้ JS ฟรีโดยสิ้นเชิงเพื่อหลีกเลี่ยงความล่าช้าในการแสดงผลฝั่งไคลเอ็นต์ เพื่อให้บรรลุเป้าหมายนั้นฉันสร้าง HTML ดังนี้:

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

เพื่อช่วยในการเข้าถึงฉันได้เพิ่มค่าคะแนนดิบในแอตทริบิวต์ชื่อเรื่อง


4

ใช้ jquery โดยไม่มีต้นแบบอัปเดตรหัส js เป็น

$( ".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);
});

ฉันยังเพิ่มแอตทริบิวต์ข้อมูลโดยใช้ชื่อการจัดอันดับข้อมูลในช่วง

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

2

การสาธิต

คุณสามารถทำได้ด้วย 2 ภาพเท่านั้น 1 ดาวว่าง 1 ดาวเต็ม

วางซ้อนภาพที่ด้านบนของอีกภาพหนึ่ง และแปลงหมายเลขคะแนนเป็นเปอร์เซ็นต์และใช้เป็นความกว้างของภาพตัวเติม

ใส่คำอธิบายภาพที่นี่

.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

นี่คือสิ่งที่ฉันใช้ JSX และแบบอักษรที่ยอดเยี่ยม จำกัด เฉพาะความแม่นยำ. 5 แม้ว่า:

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

แถวแรกใช้สำหรับทั้งดาวและแถวที่สองสำหรับครึ่งดาว (ถ้ามี)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.