Adesso creeremo uno slider che visualizzare una news per volta automaticamente ricavando le stesse da un RSS feed
Prima di tutto scriviamo un po' di HTML:
<div id="sidebar">
<h3>Recent News</h3>
<div id="news-feed">
<a href=news/index.html>News Releases</a>
</div>
</div>
E' stato previsto un link alla pagina delle news, nel caso Javascript non sia abilatato.
Quindi ci serve del CSS:
#news-feed {
position: relative;
height: 200px;
width: 17em;
overflow: hidden;
}
.headline {
position: absolute;
height: 200px;
top: 210px;
overflow: hidden;
}
Cose importanti del CSS:
Javascript code:
$(document).ready(function() {
$('#news-feed').each(function() {
$(this).empty();
});
});
Al caricamento della pagina, svuoto il contenitore delle news dal link presente nel caso javascript sia abilitato
Ecco il mio bellissimo contenitore vuoto: News RSS feed widget step 1
Adesso carichiamo l'xml con una chiamata ad un feed RSS:
Javascript code:
$(document).ready(function() {
$('#news-feed').each(function() {
$(this).empty();
$.get('news/feed.xml', function(data) {
$(data).find('item').each(function() {//$('/rss//item', data)
var title = $('title', this).text();
//alert(title);
var linkText = $('link', this).text();
var $link = $('<a></a>')
.attr('href', linkText)
.text(title);
$link = $('<h3></h3>').html($link);
var pubDate = new Date($('pubDate', this).text());
var pubMonth = pubDate.getMonth() + 1;
var pubDay = pubDate.getDate();
var pubYear = pubDate.getFullYear();
var $pubDiv = $('<div></div>')
.addClass('publication-date')
.text(pubMonth + '/' + pubDay + '/' + pubYear);
var summaryText = $('description', this).text();
var $summary = $('<div></div>')
.addClass('summary')
.html(summaryText);
$('<div></div>')
.addClass('headline')
.append($link)
.append($pubDiv)
.append($summary)
.appendTo('#news-feed');
});
});
});
});
Analizziamo il codice:
$.get('news/feed.xml', function(data) {
carico l'xml ed imposto la callback
$(data).find('item').each(function() {
ciclo su ciascun nodeo item all'interno del feed RSS
Ecco il risultato: News RSS feed widget step 2
Come vedete ancora pagina bianca, ma in realtà se controllate il codice generato (Web developer toolbar > view source > view generated source), trovate tutto il nostro HTML generato, che non si vede a causa del CSS di cui sopra (provate a cambiare il valore top della classe .headline!
Ora facciamo apparire la prima news: per fare questo, al caricamento della pagina dovrò cambiare la proprietà CSS top della prima notizia:
Javascript code:
$(document).ready(function() {
$('#news-feed').each(function() {
var currentHeadline = 0;
var oldHeadline = 0;
var hiddenPosition = $('#news-feed').height() + 10;
$(this).empty();
$.get('news/feed.xml', function(data) {
$(data).find('item').each(function() {//$('/rss//item', data)
var title = $('title', this).text();
//alert(title);
var linkText = $('link', this).text();
var $link = $('<a></a>')
.attr('href', linkText)
.text(title);
$link = $('<h3></h3>').html($link);
var pubDate = new Date($('pubDate', this).text());
var pubMonth = pubDate.getMonth() + 1;
var pubDay = pubDate.getDate();
var pubYear = pubDate.getFullYear();
var $pubDiv = $('<div></div>')
.addClass('publication-date')
.text(pubMonth + '/' + pubDay + '/' + pubYear);
var summaryText = $('description', this).text();
var $summary = $('<div></div>')
.addClass('summary')
.html(summaryText);
$('<div></div>')
.addClass('headline')
.append($link)
.append($pubDiv)
.append($summary)
.appendTo('#news-feed');
});
var headlineCount = $('div.headline').length;
var headlineTimeout;
$('div.headline:eq(' + currentHeadline + ')').css('top','0');
});
});
});
Analizziamo quello che abbiamo aggiunto:
var currentHeadline = 0;
var oldHeadline = 0;
var hiddenPosition = $('#news-feed').height() + 10;
nell'ordine: una variabile che tiene l'indice della news visibile, una che tiene l'indice della precedente, un'altra che tiene in memoria la posizione delle news nascoste
var headlineCount = $('div.headline').length;
var headlineTimeout;
$('div.headline:eq(' + currentHeadline + ')').css('top','0');
nell'ordine: una variabile con il numero di news, una variabile che tiene il valore del timeout cioè il tempo che deve passare prima che la news cambi; ed infine l'istruzione che rende la prima news visibile
Ecco il risultato: News RSS feed widget step 3
Adesso facciamole muovere:
Javascript code:
$('div.headline:eq(' + currentHeadline + ')').css('top','0');
var headlineRotate = function() {
currentHeadline = (oldHeadline + 1) % headlineCount;
$('div.headline:eq(' + oldHeadline + ')')
.animate({top: -hiddenPosition}, 'slow', function() {
$(this).css('top',hiddenPosition);
});
$('div.headline:eq(' + currentHeadline + ')')
.animate({top: 0},'slow', function() {
headlineTimeout = setTimeout(headlineRotate, 5000);
});
oldHeadline = currentHeadline;
};
headlineTimeout = setTimeout(headlineRotate,5000);
Quindi: abbiamo scritto una funzione headlineRotate che incrementa l'indice della news corrente e calcola a che indice siamo, poi muovo i relativi elementi:
currentHeadline = (oldHeadline + 1) % headlineCount;
Incrementiamo la variabile ad ogni slide. Il modulo serve a resettare la variabile a zero nel caso si arrivi all'ultima news.
$('div.headline:eq(' + oldHeadline + ')')
.animate({top: -hiddenPosition}, 'slow', function() {
$(this).css('top',hiddenPosition);
});
sposto la vecchia news sopra il contenitore e la resetto sotto
$('div.headline:eq(' + currentHeadline + ')')
.animate({top: 0},'slow', function() {
headlineTimeout = setTimeout(headlineRotate, 5000);
});
faccio apparire la successiva
Ecco il risultato: News RSS feed widget step 4
Aggiungiamo un po' d'interattività: quando un utente va con il mouse su una delle news, l'effetto di rotazione si deve fermare mentre sul mouseover deve ripartire (la funzione .hover() di JQuery accetta i due parametri)
Javascript code:
$('#news-feed').hover(function() {
clearTimeout(headlineTimeout);
}, function() {
headlineTimeout = setTimeout(headlineRotate, 250);
});
Ecco il risultato: News RSS feed widget step 5
Stiamo caricando un file esterno che sta sul nostro server. Ma in uno scenario reale? Ajax non consente chiamate crossdomain, per problemi di sicurezza. Però possiamo passare da un file php che apra i contenuti di un feed:
PHP code:
<?php
header('Content-Type: text/xml');
print $feed = file_get_contents('http://jquery.com/blog/feed');
?>
Adesso mi basta sostituire il file php al file xml nella chiamata $.get()
Aggiungiamo inoltre, poichè adesso ci sarà un minimo di tempo di caricamento, un loader:
Javascript code:
$(document).ready(function() {
$('#news-feed').each(function() {
var currentHeadline = 0;
var oldHeadline = 0;
var hiddenPosition = $('#news-feed').height() + 10;
$(this).empty();
var $newsLoading = $('<img/>')
.attr({
'src': 'news/loading.gif',
'alt': 'loading. please wait'
})
.addClass('news-wait');
$(this).ajaxStart(function() {
$(this).append($newsLoading);
})
.ajaxStop(function() {
$newsLoading.remove();
});
$.get('news/feed.php', function(data) {
[...]
Ecco il risultato: News RSS feed widget step 6
Tocco finale: aggiungiamo un effetto di fade
Javascript code:
var $this = $(this);
var totalheight = $this.height();
var fadeHeight = totalheight / 4;
for (var i = 0; i < fadeHeight; i+=2) {
$('<div></div>')
.css({
opacity: i / fadeHeight,
top: totalheight - fadeHeight + i
})
.addClass('fade-slice')
.appendTo($this);
}
In pratica creiamo 25 div alti 2px e li posizionamo uno dietro l'altro infondo al box delle news con un valore di opacità sempre crescente
Ed ecoo il nostro widget: News RSS feed widget step 7