В прошлой статье я показывал как можно сделать лайки и дизлаки для новостей. Тема использования ajax весьма актуальна, и поэтому я решил написать еще одну статью о применении ajax.
В этой статье приведен пример создания рейтинга для новостей. Пользователь сможет оценивать запись по шкале от 1 до 5.
Для работы скрипта создадим базу данных с тремя таблицами — пользователи, новости и связь пользователя с голосом. Последняя таблица нужна для того, чтобы делать ограничение по голосования — один пользователь может проголосовать только один раз за статью. Чтобы создать таблицы и наполнить их тестовыми данными можно воспользоваться патчем:
-- Создание таблицы с новостями CREATE TABLE IF NOT EXISTS `news` ( `id` int(10) NOT NULL AUTO_INCREMENT, `title` varchar(255) NOT NULL, `small_text` varchar(255) NOT NULL, `big_text` text NOT NULL, `date_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `is_active` tinyint(1) NOT NULL, `rating` float NOT NULL, `count_votes` int(10) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; -- Заполнение новостей INSERT INTO `news` (`id`, `title`, `small_text`, `big_text`, `date_create`, `is_active`, `rating`, `count_votes`) VALUES (1, 'Новость 1', 'короткое описание 1', 'полный текст', '2014-01-24 17:15:38', 1, 0, 0), (2, 'Новость 2', 'короткое описание 2', 'полный текст', '2014-01-24 17:15:34', 1, 0, 0), (3, 'Новость 3', 'короткое описание 3', 'полный текст', '2014-01-24 17:14:47', 1, 0, 0); -- Создание таблицы для пользователей CREATE TABLE IF NOT EXISTS `users` ( `id` int(10) NOT NULL AUTO_INCREMENT, `login` varchar(255) NOT NULL, `password` varchar(255) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; -- Создаем тестового пользователя INSERT INTO `users` (`id`, `login`, `password`) VALUES (1, 'test', 'pass'); -- Таблица для связей пользователей с голосами CREATE TABLE IF NOT EXISTS `votes_news2user` ( `id` int(10) NOT NULL AUTO_INCREMENT, `id_user` int(10) NOT NULL, `id_news` int(10) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
Теперь создадим страницу для вывода новостей и добавим на нее кнопки для голосования
<style> #num_vote{ display: block; border: 1px dotted; cursor: pointer; float: left; width: 20px; height: 10px; } #num_vote:hover{ border: 1px solid; background-color: #FF0000; } .current_vote{ background-color: #00FF00; } </style> <?php // подключение к бд include "db_connection.php"; $userId = 1; // id пользователя // достаем все новости $sql = mysql_query(" SELECT * FROM `news` ") or die(mysql_error()); $news = array(); while($r = mysql_fetch_array($sql, MYSQL_ASSOC)){ $news[] = $r; } ?> <div> <input type="hidden" id="id_user" value="<?=$userId;?>" /> <?php foreach($news as $oneNews){ ?> <div class="one_news"> <h3><?=$oneNews['title'];?></h3> <p><?=$oneNews['title'];?></p> <div id="votes"> Rating: <b><?=($oneNews['count_votes'] == 0) ? "Нет оценок" : $oneNews['rating'] . " Голосов: " . $oneNews['count_votes']; ?></b> <br/> <span <?=($oneNews['rating']>=1) ? 'class="current_vote" current="1"' : 'current="0"';?> id="num_vote" num_vote="1" ></span> <span <?=($oneNews['rating']>=2) ? 'class="current_vote" current="1"' : 'current="0"';?> id="num_vote" num_vote="2" ></span> <span <?=($oneNews['rating']>=3) ? 'class="current_vote" current="1"' : 'current="0"';?> id="num_vote" num_vote="3" ></span> <span <?=($oneNews['rating']>=4) ? 'class="current_vote" current="1"' : 'current="0"';?> id="num_vote" num_vote="4" ></span> <span <?=($oneNews['rating']>=5) ? 'class="current_vote" current="1"' : 'current="0"';?> id="num_vote" num_vote="5" ></span> <input type="hidden" id="id_news" value="<?=$oneNews['id'];?>" /> <input type="hidden" id="count_votes" value="<?=$oneNews['count_votes'];?>" /> <input type="hidden" id="rating" value="<?=$oneNews['rating'];?>" /> </div> </div> <hr/> <?php } ?> </div>
Код скрипта для подключения к базе данных храниться в файле db_connection.php. Вот его код:
define("HOST", "localhost"); define("USER", "root"); define("PASSWORD", ""); define("DB_NAME", "test_db"); $db_connect = mysql_connect(HOST, USER, PASSWORD, TRUE); mysql_selectdb(DB_NAME,$db_connect); mysql_set_charset('utf8');
Теперь составим скрипт, который будет обрабатывать аякс запросы и если нужно, то делать записи в базу данных или выводить сообщения об ошибках. Назовем его ajax_test.php:
// подключение к бд include "db_connection.php"; // контейнер для ошибок $error = false; // получение данных $userId = (int) $_POST['id_user']; $newsId = (int) $_POST['id_news']; $count = (int) $_POST['count']; // проверяем, голосовал ранее пользователь за эту новость или нет $sql = mysql_query(" SELECT count(*) FROM `votes_news2user` WHERE `id_user` = $userId AND `id_news` = $newsId ") or die(mysql_error()); $result = mysql_fetch_row($sql); // если что-то пришло из запроса, значит уже голосовал //var_dump($result);exit; if($result[0] > 0){ $error = 'Вы уже голосовали'; }else{ // если пользователь не голосовал, проголосуем // делаем запись о том, что пользователь проголосовал mysql_query(" INSERT INTO `votes_news2user` (`id_user`, `id_news`) VALUES ($userId, $newsId) ") or die(mysql_error()); // делаем запись для новости - увеличиваем количесво голосов и количество проголосовавших mysql_query(" UPDATE `news` SET `rating` = (`rating` * `count_votes` + $count) / (`count_votes` + 1), `count_votes` = `count_votes` + 1 WHERE `id` = $newsId ") or die(mysql_error()); } // делаем ответ для клиента if($error){ // если есть ошибки то отправляем ошибку и ее текст echo json_encode(array('result' => 'error', 'msg' => $error)); }else{ // если нет ошибок сообщаем об успехе echo json_encode(array('result' => 'success')); }
И наконец напишем javascript, который будет отправлять ajax запросы к скрипту ajax_test.php, а также этот скрипт будет отвечать за некоторые эффекты при наведении на кнопки голосования:
$(document).ready(function() { $('span#num_vote').click(function(){ var count = parseInt($(this).attr('num_vote')); setVote(count, $(this)); }); // Визуализация выбора рейтинга // при наведении подсвечиваем нужное количество блоков $('span#num_vote').hover( function () { var countSpan = $(this).parent().find('span#num_vote').length - 1; var num_vote = parseInt($(this).attr('num_vote')); for(i = 0; i <= countSpan; i++){ if((num_vote-1) >= i){ $(this).parent().find('span#num_vote').eq(i).addClass('current_vote'); }else{ $(this).parent().find('span#num_vote').eq(i).removeClass('current_vote'); } } }, function () { var countSpan = $(this).parent().find('span#num_vote').length - 1; for(i = 0; i <= countSpan; i++){ var element = $(this).parent().find('span#num_vote').eq(i); var current = parseInt(element.attr('current')); if(current == 1){ element.addClass('current_vote'); }else{ element.removeClass('current_vote'); } } } ); }); // count - тип голоса. Лайк или дизлайк // element - кнопка, по которой кликнули function setVote(count, element){ // получение данных из полей var id_user = $('#id_user').val(); var id_news = element.parent().find('#id_news').val(); $.ajax({ // метод отправки type: "POST", // путь до скрипта-обработчика url: "/ajax_test.php", // какие данные будут переданы data: { 'id_user': id_user, 'id_news': id_news, 'count': count }, // тип передачи данных dataType: "json", // действие, при ответе с сервера success: function(data){ // в случае, когда пришло success. Отработало без ошибок if(data.result == 'success'){ // Выводим сообщение alert('Голос засчитан'); // увеличим визуальный счетчик (текст) var count_votes = parseInt(element.parent().find('#count_votes').val()); var rating = element.parent().find('#rating').val(); var new_rating = ((rating * count_votes) + count) / (count_votes + 1); var new_html = new_rating.toFixed(5) + " Голосов: " + (count_votes + 1); element.parent().find('b').html(new_html); // увеличим визуальный счетчик (зеленые блоки) var floor_rating = Math.floor(new_rating); for(i = 0; i <= 4; i++){ var element_span = element.parent().find('span#num_vote').eq(i); if((floor_rating-1) >= i){ element_span.addClass('current_vote'); element_span.attr('current', 1); }else{ element_span.removeClass('current_vote'); element_span.attr('current', 0); } } }else{ // вывод сообщения об ошибке alert(data.msg); } } }); }
Вот и все, на этом создания рейтинга закончен. Напоследок хочу обратить внимание, что для работы с ajax я использовал библиотеку jQuery, поэтому вам тоже придется ее подключать, если хотите использовать этот код.
Архив со скриптами и дампом базы данных можете скачать тут.
Здравствуйте! Отличный сайт, много хороших скриптов. Взял Ваш скрипт и немного переделал для своего сайта, пользуюсь с удовольствием. Спасибо большое!
Всегда пожалуйста :)
Здравствуйте!
А можно как-то сделать так, чтобы на главной (например) выводились только результаты рейтинга, т.е. без возможности проголосовать? Ну а в самой статье — всё как тут сделано.
Создал базу, сделал импорт, подключил.
залил файлы из архива на сервер, но ajax и запись в базу не работает.
P.S. у вас отладке
Привет. Спасибо за скрипт. Все работает, но есть вопрос. Как на одной странице новости отобразить рейтинг только для этой конкретной страницы, не отображая рейтинг всех новостей?
Спасибо.