BLOG DE DISEÑO WEB CORUÑA

Un poco de todo, recursos, tutoriales, noticias, anuncios...

Sistema de Votaci贸n con estrellas en CSS, jQuery y Ajax sin plugins guardando el resultado en una base de datos mysql con PHP

17/JUL/2013 17.047 visitas Ver comentarios
Sistema de Votaci贸n con estrellas en CSS, jQuery y Ajax sin plugins guardando el resultado en una base de datos mysql con PHP

ADVERTENCIA: Este artículo tiene más de 6 meses de antigüedad. Puede que esta información ya se encuentre obsoleta o haya nuevas y mejores opciones.

Hoy traigo un nuevo sistema de votación con estrellas, conocido como star rating, utilizando CSS y jQuery para mostrar y animar la elección del valor y almacenando el voto en una base de datos MySQL.

A diferencia del realizado anteriormente, he simplificado el código al máximo y está realizado en 3 tamaños distintos de estrellas, válidas para 16px, para 24px o para 32px para que utilices la que mejor se adapte a tu diseño.

Lógicamente, y verás en el código, no te hace falta el código de los 3 tipos de tamaños. El código está encapsulado por separado ya que, al usar 3 sprites de imágenes con las estrellas, cada tamaño requiere una posición de background distinta y, como no se dará el caso que utilices las 3, he separado tanto código como imágenes para que sólo puedas utilizar el que te haga falta.

Como siempre, e intentando utilizar los elementos HTML correctos, las estrellas no dejan de ser una lista desordenada UL formadas por CSS y haciendo uso del nuevo elemento DATA de HTML5 para guardar valores necesarios como el ID del registro, la cantidad de votos recibidos, el valor obtenido, etc... con el fin de poder usar estos datos en la llamada Ajax que almacenará el nuevo voto en nuestra tabla MySQL.

En la descarga, está el modelo de la base de datos necesario, aunque sólo son necesarios (además de un ID), 2 campos que son total_votes y total_value que almacenarán el total de votos y la suma de dichos votos respectivamente.

Debo destacar que el sistema controla el voto por usuario únicamente en la presente sesión. Si un usuario da un F5 a la página, estará habilitado a votar nuevamente, ya que el objetivo de esta entrada es mostrar la forma de hacer un sistema y no el voto en sí. En todas las webs donde he aplicado sistemas similares, el dueño de la web quiere recibir muchos votos, no le importa si son todos del mismo usuario o no. Pero vamos, es muy fácil agregar un control en la parte servidor controlando si la IP del usuario ya ha votado almacenándola en nuestra tabla.

Para ello, verás que el modelo de tabla tiene un campo llamado used_ips que yo no estoy utilizando.

Pues nada, te invito a ver la demo pulsando en el botón azul que ves más arriba, espero tus comentarios para mejorar el script y, como siempre, si me ayudas a difundirlo, llegaremos a más gente :)

Código 1 - PHP
require_once("config.php");
	if (!$db) echo "<h1>No puedo conectarme a la base de datos</h1>";
	else
	{
		$entradas=$db->query("select * from galeria order by titulo asc");
		if ($filas=$entradas->fetch_array())
		{
			$tamanos=16;
			do
			{
				echo "<h2>".$filas["titulo"]."</h2>";
				$cuenta=0;
				if ($filas["total_votes"]>0) $cuenta=$filas["total_value"]/$filas["total_votes"];
				
				echo "<ul class='stars stars-".$tamanos."' data-value='".$cuenta."' data-votes='".$filas["total_votes"]."' data-id='".$filas["id"]."'>";
					echo "<li data-vote='1'>1</li>";
					echo "<li data-vote='2'>2</li>";
					echo "<li data-vote='3'>3</li>";
					echo "<li data-vote='4'>4</li>";
					echo "<li data-vote='5'>5</li>";
					if ($cuenta>0) 
					{
						$maximo_posible=5*$filas["total_votes"];
						$porciento=$filas["total_value"]*100/$maximo_posible;
						echo "<div class='voted_percent votes-".$tamanos."' style='width:".$porciento."%'></div>";
					}
				echo "<span data-txtoriginal='$cuenta/5 en ".$filas["total_votes"]." votos'>".number_format($cuenta,2)."/5 en ".$filas["total_votes"]." votos</span></ul>";
				$tamanos+=8;
				echo "<hr>";
			}
			while($filas=$entradas->fetch_array());
		}
		else echo "<p>Lo siento, no hay registros.</p>";
	}
Código 2 - JAVASCRIPT
$(function() 
	{
		$(".stars-16").children("li").hover(function() 
		{ 
			$(this).parent().children("li").css('background-position','0 0'); 
			var a=$(this).parent().children("li").index($(this));
			if (!$(this).hasClass("voted")) $(this).parent().children("li").slice(0,a+1).css('background-position','0 -15px')
		},function() { $(this).parent().children("li").css('background-position','0 0'); });
		
		$(".stars-24").children("li").hover(function() 
		{ 
			$(this).parent().children("li").css('background-position','0 0'); 
			var a=$(this).parent().children("li").index($(this));
			if (!$(this).hasClass("voted")) $(this).parent().children("li").slice(0,a+1).css('background-position','0 -21px')
		},function() { $(this).parent().children("li").css('background-position','0 0'); });
		
		$(".stars-32").children("li").hover(function() 
		{ 
			if (!$(this).hasClass("voted")) 
			{
				$(this).parent().children("li").css('background-position','0 0'); 
				var a=$(this).parent().children("li").index($(this));
				$(this).parent().children("li").slice(0,a+1).css('background-position','0 -27px');
			}
		},function() { $(this).parent().children("li").css('background-position','0 0'); });
		
		/* click */
		$(".stars").children("li:not(.voted)").click(function() 
		{ 
			if (!$(this).hasClass("voted")) 
			{
				var li=$(this);
				var ul=$(this).closest("ul");
				
				var txt=ul.find("span").data("txtoriginal");
				var id=ul.data("id");
				var valor=li.data("vote");
				
				alert("Voy a votar "+id+" con un valor de "+valor+" y el texto original era "+txt);
				$.getJSON( "voto.php", { id: id, voto: valor } )
				.done(function( json ) 
				{
					/* mostramos mensaje */
					ul.find("span").html(json.estado);
					/* actualizamos data */
					ul.find("span").data("txtoriginal",json.value+"/5 en "+json.votes+" votos");
					ul.addClass("ul_voted");
					ul.children("li").addClass("voted");
					/* cambiamos tamaño del div */
					var maximo_posible=5*json.votes;
					var porciento=json.suma*100/maximo_posible;
					porciento=porciento.toFixed(2);
					var txt=ul.find(".voted_percent").css("width",porciento+"%");
					setTimeout(function() { ul.find("span").html(ul.find("span").data("txtoriginal")); }, 3000);
				})
				.fail(function( jqxhr, textStatus, error ) {
					var err = textStatus + ', ' + error;
					ul.find("span").text(err);
				});
			}
		});
	});
Código 3 - PHP
require_once("config.php");
if (!$db) echo "<h1>No puedo conectarme a la base de datos</h1>";
else
{
	$votando=$db->query("update galeria set total_votes=total_votes+1,total_value=total_value+".intval($_GET["voto"])." where id='".intval($_GET["id"])."' limit 1");
	if ($votando)
	{
		$mensaje=array();
		$mensaje["estado"]="&iexcl;Votado! Gracias";
		/* recuperamos datos nuevos */
		$votando=$db->query("select * from galeria where id='".intval($_GET["id"])."' limit 1");
		if ($filas=$votando->fetch_array())
		{
			$cuenta=0;
			if ($filas["total_votes"]>0) $cuenta=$filas["total_value"]/$filas["total_votes"];
			
			$mensaje["suma"]=$filas["total_value"];
			$mensaje["value"]=number_format($cuenta,2);
			$mensaje["votes"]=$filas["total_votes"];
			$mensaje["id"]=$filas["id"];
			
			echo json_encode($mensaje);
		}
	}
}

Acerca del Autor...

Macadia, es una agencia de Diseño Web Coruña, especializada en maquetación css y desarrollo de páginas web a medida con más de 22 años de experiencia en el desarrollo de páginas web profesionales. Si te ha gustado este artículo, por favor, ayúdanos a difundirlo compartiéndolo con tus amigos y contactos en las distintas redes sociales que utilices. ¡Muchas gracias!

Los comentarios han sido desactivados momentaneamente a la espera de que Disqus adapte su plataforma a la próxima RGPD que entra en vigor desde el 25/05/2018