PHP

Слайдер для вывода последнего поста в блоге

В данном уроке мы сделаем слайдер, который показывает последний пост в любимых блогах. В ходе урока будут использоваться jQuery, PHP и XSL. Нашей целью является получение заданного RSS-фида блога и парсинг XML данных с помощью PHP. Мы будем использовать XSL, чтобы трансформировать фид в HTML и кэшировать результат для дальнейшего использования. Также мы будем использовать много свойств CSS3 для придания лоска внешнему виду слайдеpа.

По техническим причинам для данного урока демонстрационный сайт работает в оригинале без перевода.

Начнем!
Разметка

HTML будет состоять из двух основных частей: списка блогов и накладывающегося модального окна. Рассмотрим список блогов:
<div class="content">
	<h2>Latest Post Blogroll Slider</h2>

	<ul id="friendsList" class="friendsList">
		<li class="ourtuts">
			<a href="#">
				<em>Our Tuts</em>
				<span>The Easy Way to Learn Photoshop</span>

			</a>
		</li>
		<li class="devisefunction">
			<a href="#">
				<em>Devise Function</em>

				<span>Tutorials and Resources</span>
			</a>
		</li>
		...
	</ul>
</div>

Неупорядоченный список обернут в div. Для каждого элемента списка мы задаем отдельный класс, так как мы хотим добавить маленькую иконку, которая будет идентифицировать блог. Также мы добавляем span для описания блога.

Накладывающееся модальное окно будет иметь следующую структуру:
<div id="overlay" class="overlay" style="display:none;"></div>

<div id="modal" class="modal" style="display:none;">
	<a href="#" class="prev"></a>
	<a href="#" class="next"></a>

	<span class="close"></span>
	<h2 id="blog_info"></h2>
	<div id="latest_post" class="loading"></div>
</div>

Задаем для обоих элементов строчный стиль display:none, потому что в начале их нужно скрыть. Вы также можете задать эти стили в CSS, а не как строчные. В функции jQuery мы будем показывать элементы, если будет получено нажатие кнопки мыши на одном из блогов.

В div с id latest_post мы вставляем содержимое фида.

Теперь взглянем на стили..
CSS

Сначала мы производим инициализацию и определяем общий стиль:
*{
	margin:0;
	padding:0;
}
body{
	font-family:"Myriad Pro",Arial, Helvetica, sans-serif;
	background:#282828 url(../images/bg.jpg) repeat top left;
	overflow-x:hidden;
}

Нам нужно установить для body overflow-x:hidden, чтобы убрать полосу прокрутки, когда модальное окно находится за пределами экрана. Если такие установки неудобны для вас, то вы можете установить то, что нужно.

Начнем с задания стилей элементам, которые принадлежат оверлею.
Черный полупрозрачный оверлей будет иметь следующий стиль:
.overlay{
	position:fixed;
	z-index:999;
	top:0px;
	left:0px;
	width:100%;
	height:100%;
	background-color:#000;
	opacity:0.7;
}

Оверлей фиксируется и растягивается на все окно. Если пользователю нужно прокрутить окно, то оверлей останется на месте.

Модальное окно будет позиционироваться в абсолютных координатах:
.modal{
	position:absolute;
	top:25%;
	width:500px;
	height:300px;
	margin-left:-250px;
	z-index:9999;
	color:#fff;
	text-shadow:1px 1px 1px #000;
	border:1px solid #303030;
	background-color:#212121;
	-moz-box-shadow:0px 0px 10px #000;
	-webkit-box-shadow:0px 0px 10px #000;
	box-shadow:0px 0px 10px #000;
}

В нашей функции jQuery мы становим левое значение left 50% (во время вывода), для центрирования нужно установить в margin-left отрицательное значение, равное половине ширины.
Обратите внимание на z-index оверлея и модального окна: для оверлея установлено значение 999 ( для того чтобы быть сверху всего на странице), а для модального окна установлено значение 9999. Конечно, можно просто поставить 1000 и окно будет располагаться над оверлеем. Но лучше оставить некоторое пространство, потому что ниикогда не знаешь, а вдруг понадобиться вствить элемент между ними.

Заголовки и параграфы будут иметь следующие стили:
.modal h2{
	font-weight:100;
	padding:5px 0px 5px 5px;
	margin:5px;
	background-color:#111;
	border:1px solid #272727;
}
.modal h2 img{
	float:left;
	width:28px;
	margin-right:10px;
	-moz-box-shadow:0px 0px 4px #000;
	-webkit-box-shadow:0px 0px 4px #000;
	box-shadow:0px 0px 4px #000;
}
.modal h3{
	text-transform:uppercase;
	font-weight:100;
	font-size:16px;
	letter-spacing:1px;
	margin:25px 25px 5px 25px;
	color:#3365AF;
}
.modal p{
	margin:15px 25px;
	line-height:24px;
	height:100px;
	overflow:hidden;
}
.modal p a{
	color:#ddd;
}
.modal p a:hover{
	color:#fff;
}

Тонкая линия под заголовком задается следующим стилем div:
.line{
	background-color:#000;
	border-bottom:1px solid #333;
	height:1px;
	margin:3px 10px 5px 10px;
}

Мы просто устанавлваем для div высоту в 1px и черный цвет. Затем добавляем границу с более светлым цветом и получается замечательный вид отражения. Вам просто нужно адаптировать цвета для используемого фона.

Кнопка полностью создается свойствами CSS3:
a.button{
	display: inline-block;
	float:right;
	padding: 4px 10px;
	background-color: #1951A5;
	color:#fff;
	margin:20px;
	font-size:12px;
	letter-spacing:1px;
	text-shadow:1px 1px 1px #011c44;
	text-transform:uppercase;
	text-decoration: none;
	border:1px solid #4c7ecb;
	outline:none;
	background-image:
		-moz-linear-gradient(
			top,
			rgba(255,255,255,0.25),
			rgba(255,255,255,0.05)
		);
	background-image:
		-webkit-gradient(
			linear,
			left top,
			left bottom,
			color-stop(0, rgba(255,255,255,0.25)),
			color-stop(1, rgba(255,255,255,0.05))
		);
	-moz-box-shadow: 1px 1px 3px #000;
	-webkit-box-shadow: 1px 1px 3px #000;
	box-shadow: 1px 1px 3px #000;
	-moz-border-radius: 5px;
	-webkit-border-radius: 5px;
	border-radius: 5px;
}
a.button:hover{
	color: #011c44;
	text-shadow: 1px 1px 1px #ccdffc;
}
a.button:active{
	margin-top:21px;
}

Мы используем прекрасный голубой градиент и эффект гладкой гравировки для свойства hover с помощью установки подходящего цвета и теней.

Стиль оборачивающего div для поста во время его загрузки:
.loading{
	background:transparent url(../images/loading.gif) no-repeat center center;
	width:100%;
	height:200px;
}

Мы добавляем и удалем данный класс в соответствии со статусом содержимого.

Навигационные ссылки будут иметь следующий общий стиль:
a.next, a.prev{
	height:50px;
	width:20px;
	background-color:#212121;
	background-repeat:no-repeat;
	background-position:center center;
	position:absolute;
	top:130px;
	cursor:pointer;
	border:1px solid #303030;
	outline:none;
}

… и персональные стили:
a.next{
	right:-21px;
	border-left:none;
	background-image:url(../images/next.png);
	-moz-border-radius:0px 5px 5px 0px;
	-webkit-border-top-right-radius:5px;
	-webkit-border-bottom-right-radius:5px;
	border-top-right-radius:5px;
	border-bottom-right-radius:5px;
	-moz-box-shadow: 1px 1px 3px #000;
	-webkit-box-shadow: 1px 1px 3px #000;
	box-shadow: 1px 1px 3px #000;
}
a.prev{
	left:-21px;
	border-right:none;
	background-image:url(../images/prev.png);
	-moz-border-radius:5px 0px 0px 5px;
	-webkit-border-top-left-radius:5x;
	-webkit-border-bottom-left-radius:5px;
	border-top-left-radius:5px;
	border-bottom-left-radius:5px;
	-moz-box-shadow: -1px 1px 3px #000;
	-webkit-box-shadow: -1px 1px 3px #000;
	box-shadow: -1px 1px 3px #000;
}

span для элемента для закрытия модального окна имеет стиль:
span.close{
	background:#000 url(../images/close.png) no-repeat center center;
	cursor:pointer;
	height:25px;
	width:25px;
	position:absolute;
	right:12px;
	top:12px;
	cursor:pointer;
	-moz-border-radius:5px;
	-webkit-border-radius:5px;
	border-radius:5px;
	opacity:0.5;
}
span.close:hover{
	opacity:1.0;
}

Свойство hover в таком виде будет работать только в современных браузерах.

Теперь взглянем на содержание списка блогов:
.content{
	width:800px;
	margin:40px auto 0 auto;
	background-color:#101010;
	height:555px;
	border:1px solid #191919;
	-moz-box-shadow:0px 0px 10px #000 inset;
	-webkit-box-shadow:0px 0px 10px #000 inset;
	box-shadow:0px 0px 10px #000 inset;
}

Цвет границы и внутренняя тень прямоугольника создают эффект реальной глубины.
.content h2{
	background-color:#222;
	color:#f0f0f0;
	text-shadow:1px 1px 1px #000;
	margin:-15px -15px 0 -15px;
	padding:20px;
	font-size:30px;
	font-weight:100;
	border:1px solid #303030;
}

Устанавливая отрицательное значение для margin, мы вытягиваем заголовок h2 из прямоугольника содержания.

Список блогов имеет следующий стиль:
ul.friendsList{
	list-style:none;
	margin:10px 0 0 0;
}
ul.friendsList li a{
	display:block;
	padding:15px 15px 15px 55px;
	text-decoration:none;
	color:#ddd;
	font-size:26px;
	text-shadow:1px 1px 1px #000;
	margin:5px 10px;
	background-color:#1f1f1f;
	border:1px solid #222;
	-moz-box-shadow:0px 0px 10px #000;
	-webkit-box-shadow:0px 0px 10px #000;
	box-shadow:0px 0px 10px #000;
	background-repeat:no-repeat;
	background-position:5px 50%;
	opacity:0.9;
	outline:none;
}
ul.friendsList li a:hover{
	color:#fff;
	border:1px solid #303030;
	background-color:#212121;
	opacity:1.0;
	text-shadow:0px 0px 1px #fff;
}

Соответствующие каждому блогу изображения определяются их собственными классами для элементов списка:
ul.friendsList li.devisefunction a{
	background-image:url(../images/devisefunction.jpg)
}
ul.friendsList li.wordrom a{
	background-image:url(../images/wordrom.jpg)
}
ul.friendsList li.fearlessflyer a{
	background-image:url(../images/fearlessflyer.jpg)
}
ul.friendsList li.bluefaqs a{
	background-image:url(../images/bluefaqs.jpg)
}
ul.friendsList li.ourtuts a{
	background-image:url(../images/ourtuts.jpg)
}
ul.friendsList li.tzine a{
	background-image:url(../images/tzine.jpg)
}
ul.friendsList li.w3avenue a{
	background-image:url(../images/w3avenue.jpg)
}

Описание блога имеет следующий стиль:
ul.friendsList li a > span{
	color:#333;
	padding-left:10px;
	font-size:22px;
}
ul.friendsList li a:hover > span{
	text-shadow:1px 1px 1px #000;
	color:#444;
}

Со стилями все закончено! Рассмотрим PHP.
PHP

Наш класс PHP будет получать RSS-фид и кэшировать его после трансформации. Папка, названная “cache” будет создаваться на диске и наш PHP класс будет читать из этех файлов (если они созданы) до тех пор пока не будет исчерпан определенный лимит времени (cache_lifetime).
class RSS{
	/**
	* кэш директория, в которой будет храниться вывод фида
	*/
	private $cache_dir		= 'cache';
	/**
	* время в секундах, в течении которого кэшируется фид
	*/
	private $cache_lifetime	= 300;
	/**
	* переменные, передаваемые с AJAX, 
	* которые содержат имя блога, из которого будет осуществляться выборка RSS
	*/
	private $source;
	/**
	* таблица стилей xsl, которая
	* трансформирует rss-фид в html
	*/
	private $xsl_file 		= 'rss2html.xsl';
	
	public function __construct($source){
		$this->source = $source;
	}
	
	/**
	* получаем последний пост соответствующего блога
	*/
	public function getLatest(){
		switch($this->source){
			case 'wordrom':
				$xml 		= 'http://feeds.feedburner.com/Wordrom?format=xml';
				break;
			case 'w3avenue':
				$xml 		= 'http://feeds.feedburner.com/w3avenue?format=xml';
				break;
			case 'fearlessflyer':
				$xml 		= 'http://feeds.feedburner.com/fearlessflyer?format=xml';
				break;	
			case 'tzine':
				$xml 		= 'http://feeds.feedburner.com/Tutorialzine?format=xml';
				break;	
			case 'bluefaqs':
				$xml 		= 'http://feeds.feedburner.com/Bluefaqscom?format=xml';
				break;	
			case 'devisefunction':
				$xml 		= 'http://feeds.feedburner.com/devisefunction?format=xml';
				break;	
			case 'ourtuts':
				$xml 		= 'http://feeds.feedburner.com/ourtutsfeed?format=xml';
				break;					
		}
		/**
		* если в кэше сожержится вывод, то мы уже получили его
		* иначе загружаем и сохраняем его в кэше
		*/
		if($this->isCached($this->source . '.xml')){
			echo $this->getCache($this->source . '.xml');
		}
		else{
			$doc = new DOMDocument();
			$xsl = new XSLTProcessor();

			$doc->load($this->xsl_file);
			$xsl->importStyleSheet($doc);

			$doc->load($xml);
			$output = html_entity_decode($xsl->transformToXML($doc));
			
			$this->addCache($output , $this->source . '.xml');
			echo $output;
		}
	}
	
	/**
	* следующий механизм кэша был взят с сайта
	* http://www.phpro.org/classes/Template-Class.html
	*/
	private function addCache($content, $file){
		/** 
		* имя файла кэша
		*/
		$filename  = $this->cache_dir . '/' . basename($file);
		/**
		* имя директории файла кэша
		*/
		$directory = $this->cache_dir;
		/** 
		* создаем директорию кэша
		*/
		@mkdir($directory, 0775);
		/** 
		* записываем в кэш
		*/
		if(file_put_contents($filename, $content) == FALSE){
			throw new Exception("Unable to write to cache");
		}
	}
	
	/**
	* получаем содержимое кэш файла
	*/
	private function getCache($file){
		$filename 	= $this->cache_dir . '/' . basename($file);
		/** 
		* читаем кэш файл в переменную
		*/
		$content	= file_get_contents($filename);
		return isset($content) ? $content : false;
	}
	
	/**
	* проверяем, кэширован ли файл, основываясь на времени 
	* заданном в cache_lifetime
	*/
	public function isCached($file){
		$filename = $this->cache_dir . '/' . basename($file);
		if (is_file($filename)){
			clearstatcache();
			if (filemtime($filename) > (time() - $this->cache_lifetime)){
				$isCached = true;
			}
		}
		return isset($isCached) ? true : false;
	}
}

XSL

Определим XSL, который будет использоваться для трансформации XML в HTML:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
	<xsl:output method="html" encoding="iso-8859-1" indent="no"/>

	<xsl:template match="channel">
		<xsl:apply-templates select="item[1]" />

	</xsl:template>

	<xsl:template match="item">
		<h3>
			<xsl:value-of select="title"/>
		</h3>
		<div class="line"></div>

		<p>
			<xsl:value-of select="description"/>
		</p>
		<a class="button" target="_blank">
			<xsl:attribute name="href">
				<xsl:value-of select="link"/>

			</xsl:attribute>
			Read more
		</a>
	</xsl:template>
</xsl:stylesheet>

Концепция оцень проста. Мы предполагаем, что в RSS XML будет следующая структура:
<channel>

	...
	<item>
		<title> </title>
		<link> </link>
		...
	</item>

</channel>

Сначала мы выделяем узел, который называется channel, и выделяем из него первый элемент item. Затем мы используем шаблон для узла элемента. Таким образом получается структура с заголовком, описанием и ссылкой на оригинал статьи.
JavaScript

При нажатии на ссылку блога в списке, мы получаем нужную инфрмацию через запрос AJAX к классу PHP и размещаем ее в нашем модальном окне. Определяем функции showModal() и hideModal(), которые выполняют вывод модального окна на экран и скрывают модально окно за границами экрана.
Мы выполняем анимацию модального окна из-за пределов экрана слева (негативное значение) в центр страницы. Помните, мы определяли в CSS margin-left как -250px. Если мы переместим модальное окно в положение left:50%, то оно появится с горизонтальным центрированием на странице с отрицательным полем. Для того, чтобы скрыть модальное окно, мы сдвигаем его вправо устанавливая left в значение 150%.
Функции, для получения следующих и предыдущих постов блога используют переменную current, которая отслеживает, на каком пункте списка мы сейчас находимся.
$(function() {
	/**
	* решаем проблему кэша IE AJAX
	*/
	$.ajaxSetup({cache: false});
    
	/**
	* индекс текущего выбранного элемента / блога
	* и общее количество элементов / блоговblogs
	*/
	var current = -1;
	var total	= $('#friendsList').children().length;
	
	/**
	* когда мы нажимаем на сслыке на блог,
	* мы получаем самый последний пост с помощью запроса AJAX
	*/
	$('#friendsList a').bind('click',function(e){
		var $this = $(this);
		show();
		var $elem	= $this.parent();
		current 	= $elem.index() + 1;
		var source 	= $elem.attr('class');
		/**
		* добавлем заголовок и изображение к блогу
		*/
		$('#blog_info').empty()
					   .html('' + $this.find('em').html());	
		    $.get('rss.class.php', {source:source} , function(data) {
			$('#latest_post').removeClass('loading').html(data);
		});
		e.preventDefault();
	});
	
	/**
	* показываем диалоговое окно с постом
	*/
	function show(){
		$('#overlay').show();
		if(!$('#modal').is(':visible'))
		$('#modal').css('left','-260px')
				   .show()
				   .stop()
					   .animate({'left':'50%'}, 500);
	}
	
	/**
	* скрываем диалоговое окно
	*/
	function hide(){
		$('#modal').stop()
				   .animate({'left':'150%'}, 500, function(){
						$(this).hide();
						$('#overlay').hide();
						$('#latest_post').empty();
				   });
	}
	
	/**
	* нажимаем на крестик, чтобы скрыть окно
	*/
	$('#modal .close').bind('click',function(){
		hide();
	});
	
	/**
	* нажимаем кнопку мыши на 'следующий' в окне диалога
	*/
	$('#modal .next').bind('click',function(e){
		if(current == total){ 
			e.preventDefault();
			return;
		}	
		$('#latest_post').empty().addClass('loading');
		$('#friendsList li:nth-child('+ parseInt(current+1) +')').find('a').trigger('click');
		e.preventDefault();
	});
	
	/**
	* нажимаем кнопку мыши на 'предыдуший' в окне диалога
	*/
	$('#modal .prev').bind('click',function(e){										
		if(current == 1){ 
			e.preventDefault();
			return;
		}	
		$('#latest_post').empty().addClass('loading');
		$('#friendsList li:nth-child('+ parseInt(current-1) +')').find('a').trigger('click');
		e.preventDefault();
	});
});

Вот и все!
Добавлено: 21 Августа 2013 02:23:13 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...