آموزش ساخت سیستم رتبه دهی ستاره ای در js و php

رتبه دهی ستاره ای در js و php – خیلی از مطالب و محصولات اینترنتی دارای بخشی هستند که می توان به محصول و مطلب رتبه دهید تا دیگر کاربران از میزان کیفیت آن مطلب مطلع شوند .
در این آموزش از html , css , js , php , mysql استفاده می کنیم .
فایل index.php
<!DOCTYPE html>
<html lang="fa">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>RapidCode.IR - ساخت جستجوی پیشرفته AJAX با PHP و Javascript</title>
<link rel="stylesheet" href="static/css/style.css">
</head>
<body>
<a id="introduce" target="_blank" href="https://rapidcode.ir">رپید کد - کتابخانه مجازی برنامه نویسان</a>
<div class="container">
<?php
require_once "posts.php";
$posts = get_posts();
?>
<?php
foreach ($posts as $row):
?>
<article id="post-<?php echo $row['id'] ?>">
<img src="<?php echo $row['thumbnail'] ?>" alt="<?php echo $row['title'] ?>">
<h2><?php echo $row['title'] ?></h2>
<p><?php echo $row['content'] ?></p>
<?php
$stars = $row['rstar'];
$reviewer_number = $row['rstar_user'];
$score = $stars == 0 && $reviewer_number == 0 ? 0 : $stars / $reviewer_number;
$integer_score = ceil($score);
?>
<div class="stars-wrapper">
<?php if($stars != 0 && $reviewer_number != 0): ?>
<span id="stars-number"><i id="rate"><?php echo round($score , 1) ?></i> از <i id="avg-count"><?php echo $reviewer_number ?></i> رای</span>
<?php endif; ?>
<span class="stars-shape" id="post_star_<?php echo $row['id'] ?>" data-post-id="<?php echo $row['id'] ?>">
<?php
for($i=1;$i<=5;$i++):
$offset_svg = 0;
if($integer_score == 1){
$offset_svg = $score;
}else if(1 < $integer_score){
$offset_svg = 1;
}
$integer_score--;
$score--;
$offset_svg = round($offset_svg , 1);
$offset_svg *= 100;
?>
<svg fill="url(#filler-<?php echo "pid-{$row['id']}-{$i}" ?>)" id="star<?php echo $i ?>" data-item-number="<?php echo $i ?>" class="star" height="511pt" viewBox="0 -10 511.98685 511" width="511pt" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient id="filler-<?php echo "pid-{$row['id']}-{$i}" ?>"><stop id="half-stp-1" offset="<?php echo $offset_svg ?>%"/><stop offset="0"/></linearGradient></defs><path d="m510.652344 185.902344c-3.351563-10.367188-12.546875-17.730469-23.425782-18.710938l-147.773437-13.417968-58.433594-136.769532c-4.308593-10.023437-14.121093-16.511718-25.023437-16.511718s-20.714844 6.488281-25.023438 16.535156l-58.433594 136.746094-147.796874 13.417968c-10.859376 1.003906-20.03125 8.34375-23.402344 18.710938-3.371094 10.367187-.257813 21.738281 7.957031 28.90625l111.699219 97.960937-32.9375 145.089844c-2.410156 10.667969 1.730468 21.695313 10.582031 28.09375 4.757813 3.4375 10.324219 5.1875 15.9375 5.1875 4.839844 0 9.640625-1.304687 13.949219-3.882813l127.46875-76.183593 127.421875 76.183593c9.324219 5.609376 21.078125 5.097657 29.910156-1.304687 8.855469-6.417969 12.992187-17.449219 10.582031-28.09375l-32.9375-145.089844 111.699219-97.941406c8.214844-7.1875 11.351563-18.539063 7.980469-28.925781zm0 0"/></svg>
<?php endfor; ?>
</span>
</div><br>
<a href="<?php echo $row['link'] ?>" target="_blank">ادامه مطلب</a>
</article>
<?php endforeach;?>
</div>
<script src="static/js/app.js"></script>
</body>
</html>
فایل posts.php برای دسترسی به توابع مورد نیاز جهت تعامل با mysql
فایل posts.php
<?php
$table = "articles";
$mysqli = new mysqli("localhost", "root", "", "posts");
$mysqli->set_charset("utf8");
$stmt = $mysqli->stmt_init();
function get_posts($id = false)
{
global $table;
global $mysqli;
global $stmt;
$where_statment = "";
$rows = [];
if (!empty($id)) {
if (is_row_exits($id)) {
$where_statment = "WHERE id=?";
} else
return $rows;
}
$query = "SELECT * FROM `{$table}` {$where_statment} ORDER BY id DESC";
$stmt->prepare($query);
if (!empty($where_statment)) {
$stmt->bind_param("i", $id);
}
if ($stmt->execute() && $res = $stmt->get_result()) {
if ($stmt->affected_rows || $res->num_rows) {
while ($row_loop = $res->fetch_assoc()) {
$rows[] = $row_loop;
}
}
}
return $rows;
}
function is_row_exits($id)
{
global $table;
global $mysqli;
global $stmt;
$query = "SELECT id FROM {$table} WHERE id=?";
$stmt->prepare($query);
$stmt->bind_param('i', $id);
$is_found = 0;
if ($stmt->execute() && $stmt->store_result()) {
$is_found = $stmt->affected_rows;
$stmt->free_result();
}
return $is_found;
}
function set_post_stars($post_id, $score)
{
global $table;
global $stmt;
$row_updated = false;
$query = "UPDATE {$table} SET `rstar` = `rstar` + ? , `rstar_user` = `rstar_user` + 1 WHERE `id`=?";
$stmt->prepare($query);
$stmt->bind_param('ii', $score, $post_id);
if ($stmt->execute()) {
$row_updated = $stmt->affected_rows ? $stmt->affected_rows : 1;
}
return $row_updated;
}
function set_post_stars_cookie(&$user_review_content_cookie, &$response_list)
{
$res = set_post_stars($_POST['post_id'], $_POST['post_score']);
if (!$res) die(["msg" => "خطایی در ارتباط با پایگاه داده رخ داده است", "status" => 0]);
$post = get_posts($_POST['post_id']);
$post = end($post);
$post = ["star"=> ($post['rstar'] / $post['rstar_user']) , "user"=> $post['rstar_user'] , "id" => $post['id']];
$response_list["data"] = $post;
$response_list["msg"] = "امتیاز {$_POST['post_score']} با موفقیت ثبت گردید";
$response_list["status"] = 1;
array_push($user_review_content_cookie['post_id'], $_POST['post_id']);
setcookie("post_review_stars", json_encode($user_review_content_cookie), time() + 86400); // تا 1 روز آینده
}
فایل review-api.php جهت ساخت api لازم برای ثبت رتبه کاربران .
فایل review-api.php
<?php
header("Content-Type: application/json");
require_once "posts.php";
if (empty($_POST['post_id'])) {
die(json_encode(["msg" => "پست آیدی ارسال نشد", "status" => 0]));
}
if (!is_row_exits($_POST['post_id'])) {
die(json_encode(["msg" => "پست مورد نظر یافت نشد", "status" => 0]));
}
if (empty($_POST['post_score'])) {
die(json_encode(["msg" => "امتیاز ارسال نشد", "status" => 0]));
}
$response_list = [
"msg" => "",
"status" => 0
];
$user_review_content_cookie = @$_COOKIE["post_review_stars"] ? $_COOKIE["post_review_stars"] : ["post_id" => []];
if (!empty($user_review_content_cookie)) {
if(!is_array($user_review_content_cookie))
$user_review_content_cookie = json_decode($user_review_content_cookie, true);
if (in_array($_POST['post_id'], $user_review_content_cookie['post_id'])) {
$response_list['msg'] = "شما از قبل به این پست امتیاز داده بودید";
} else {
set_post_stars_cookie($user_review_content_cookie, $response_list);
}
} else {
set_post_stars_cookie($user_review_content_cookie, $response_list);
}
die(json_encode($response_list));
style.css جهت دادن استایل به برنامه
استایل برنامه با style.css
article {
width: 25%;
border: 2px solid skyblue;
padding: 10px;
float: right;
margin-left: 15px;
}
article img {
width: 200px;
}
article h2{
height: 82px;
}
article p{
height: 56px;
overflow: hidden;
}
article a {
text-decoration: none;
font-weight: bold;
background-color: #FF9800;
color: white;
width: 100%;
padding: 10px 0;
display: block;
}
.stars-wrapper{
direction: ltr;
}
.stars-wrapper #stars-number{
float: left;
direction: rtl;
}
.stars-wrapper .stars-shape {
cursor: pointer;
transition: all 0.3s;
}
.stars-wrapper .stars-shape svg{
overflow: initial;
width: 15px;
height: 15px;
stroke-width: 55px;
stroke: #ffc107;
margin-left: 1px;
}
.stars-wrapper .stars-shape svg:hover{
fill: #ffc107;
}
stop{
stop-opacity: 1;
stop-color: rgba(0, 0, 0, 0);
}
stop#half-stp-1{
stop-color: #ffc107;
}
فایل app.js
document.addEventListener("DOMContentLoaded", function () {
const starElmentDOM = document.getElementsByClassName("stars-shape");
let requestLock = false;
const starDOM = document.getElementsByClassName("star");
for (var i = 0; i < starDOM.length; i++) {
const currentElement = starDOM[i];
currentElement.addEventListener("mouseover", handlerFillStars)
currentElement.addEventListener("click", function (event) {
const currentElementParent = currentElement.parentElement;
const postID = currentElementParent.getAttribute("data-post-id");
const score = parseInt(currentElement.getAttribute("data-item-number"));
reviewRequest(postID, score);
})
}
for (var i = 0; i < starElmentDOM.length; i++) {
const currentElement = starElmentDOM[i];
currentElement.addEventListener("mouseleave", handlerEmptyStars)
}
// handlers
function handlerFillStars(event) {
handlerEmptyStars();
const currentElement = this;
const currentElementParent = currentElement.parentElement;
const currentElementItemNumber = currentElement.getAttribute("data-item-number");
for (var i = 0; i < currentElementItemNumber; i++) {
const currentElement = currentElementParent.querySelector("#star" + (i + 1));
if (currentElement == null) continue;
currentElement.style.fill = "#bc8f07";
}
}
function handlerEmptyStars(event) {
for (var j = 0; j < starDOM.length; j++) {
const currentElement = starDOM[j];
currentElement.removeAttribute("style");
}
}
// ajax Request
function reviewRequest(postID, postScore, currentElement) {
if (requestLock)
return;
const xhr = new XMLHttpRequest();
xhr.responseType = "json";
requestLock = true;
const params = new FormData;
params.append("post_id", postID);
params.append("post_score", postScore);
xhr.open("POST", location.href + "/review-api.php");
xhr.onload = function () {
requestLock = false;
const response = this.response;
if (response.status == 1) {
let starsNumber = response.data.star;
const reviewerNumber = response.data.user;
const postID = response.data.id;
const starWrapper = document.querySelector("article#post-" + postID + " .stars-shape")
let parentElementPreviousElement = starWrapper.previousElementSibling;
if(!parentElementPreviousElement){
parentElementPreviousElement = document.createElement("span");
parentElementPreviousElement.id = "stars-number";
parentElementPreviousElement.innerHTML = '<i id="rate">x1</i> از <i id="avg-count">x2</i> رای';
starWrapper.parentElement.insertBefore(parentElementPreviousElement , starWrapper);
}
// مقداردهی نوشته رای
parentElementPreviousElement.querySelector("#rate").textContent = starsNumber.toFixed(1);
parentElementPreviousElement.querySelector("#avg-count").textContent = reviewerNumber;
// پرکردن مجدد ستاره ها
const svgStar = starWrapper.querySelectorAll("svg");
var starTempValue = 0;
var currentElement = null;
for(var i=0;i<svgStar.length;i++){
currentElement = svgStar[i];
starTempValue = 1 < starsNumber ? 1 : starsNumber.toFixed(1);
starTempValue *= 100;
currentElement.querySelector("#half-stp-1").setAttribute("offset" , starTempValue + "%");
starsNumber--;
}
}
alert(response.msg);
}
xhr.onerror = function () {
requestLock = false;
console.warn("[XHR Error]");
}
xhr.send(params);
}
});
دموی برنامه رتبه دهی ستاره ای

قبل از اجرای برنامه وارد پوشه posts DATABASE to import شده دیتابیس را import کنید
ارسال نظر