製作我們自己的 Twitter 時間線
簡介
Twitter 已經發展成為一種真正的社會現象。對於如此簡單的服務來說,這是一項了不起的成就。但如您所知,偉大的想法並不一定很複雜。
這一次,我們將創建自己的類似 Twitter 的時間線,您可以在其中查看和發布您的推文。您可以將我在此處提供的代碼用於各種目的,並確保可能性無窮無盡。所以獲取演示文件 開始學習吧!
創建數據庫
如果你想在你自己的網站上運行一個工作演示,你必須創建一個 MySQL 表來存儲你所有的推文。您可以通過 phpMyAdmin 運行以下 SQL 代碼(該代碼也可以在 table.sql 中找到 在教程文件中):
table.sql
CREATE TABLE `demo_twitter_timeline` (
`id` int(10) NOT NULL auto_increment,
`tweet` varchar(140) collate utf8_unicode_ci NOT NULL default '',
`dt` datetime NOT NULL default '0000-00-00 00:00:00',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
該表可以在任何 mysql 數據庫中。只記得更新 connect.php 中的數據 .
XHTML
感謝 CSS 和 jQuery,我們的 XHTML 代碼非常簡單。這就是您在 index.php 中看到的內容 在演示文件中。
index.php
<div id="twitter-container">
<form id="tweetForm" action="submit.php" method="post">
<span class="counter">140</span>
<label for="inputField">What are you doing?</label>
<textarea name="inputField" id="inputField" tabindex="1"rows="2" cols="40"></textarea>
<input class="submitButton inact" name="submit" type="submit" value="update" />
<span class="latest"><strong>Latest: </strong><span id="lastTweet"><?=$lastTweet?></span></span>
<div class="clear"></div>
</form>
<h3 class="timeline">Timeline</h3>
<ul class="statuses"><?=$timeline?></ul>
</div>
我們的整個時間線位於一個 id 為 twitter-container 的 div 容器中 .它在下面的 CSS 文件中附加了一些有趣的樣式。
接下來我們有一個 id 為 tweetForm 的表單 .這個表單是通過 AJAX 提交的,所以 action 是什麼並不重要 並提交 屬性設置為。
在表單內部,我們有一個特殊的 span 元素。它充當計數器,顯示當前填充在框中的字符數。和 twitter 一樣,這裡的限制設置為 140 個字符。
後來我們有了 textarea 的標籤,textarea 本身和提交按鈕,它是 disabled 默認情況下(這是通過 jQuery 和一個特殊的 CSS 類 - inact 完成的 , 稍後你會看到)。
之後,我們有我們最新的推文和一個清除 div。通過該 div,我們解決了 CSS 的一個有趣的缺點,稍後您將看到。
最後是時間線本身,包含我們最新的推文。
第 9 行和第 16 行被突出顯示,以顯示我們正在顯示 PHP 變量。我們稍後會解釋它們並生成列表。

CSS
我們已經提到,通過使用 CSS,我們能夠大大減少我們編寫的 XHTML 代碼的數量。另一個好處是,隨時更改我們項目的外觀真的很容易,只需更改樣式表即可。
現在讓我們看看我們的 demo.css 中有什麼 文件。
demo.css
/* Page styles */
body,h1,h2,h3,p,td,quote,small,form,input,ul,li,ol,label{
margin:0px;
padding:0px;
}
body{
margin-top:20px;
color:#51555C;
}
/* Form & timeline styles */
#twitter-container{
-moz-border-radius:12px;
-khtml-border-radius: 12px;
-webkit-border-radius: 12px;
border-radius:12px;
border:6px solid #f5f5f5;
padding:10px;
width:600px;
font-size:11px;
font-family:'Lucida Grande',sans-serif;
color:#333333;
}
label{
font-size:20px;
display:block;
}
.counter{
color:#CCCCCC;
float:right;
font-family:Georgia,serif;
font-size:32px;
font-weight:bold;
height:40px;
overflow:hidden;
}
textarea{
width:594px;
height:38px;
margin:5px 0 10px 0;
border:1px solid #AAAAAA;
padding: 4px 2px;
font-family:'Lucida Grande',sans-serif;
overflow:auto;
font-size:14px;
}
.clear{
clear:both;
}
.submitButton{
color:#666666;
font-size:14px;
height:32px;
width:115px;
-moz-border-radius:6px;
-khtml-border-radius: 6px;
-webkit-border-radius: 6px;
border-radius:6px;
border:1px solid #cccccc;
background:url(img/button_bg.gif) repeat-x #f5f5f5;
cursor:pointer;
float:right;
}
.submitButton:hover{
background-position:bottom;
border-color:#dddddd;
color:#333333;
}
.inact,.inact:hover{
background:#f5f5f5;
border:1px solid #eeeeee;
color:#aaaaaa;
cursor:auto;
}
.latest{
color: #666666;
}
ul.statuses{
margin:10px 0;
}
ul.statuses li {
position:relative;
border-bottom:1px dashed #D2DADA;
padding:15px 15px 15px 10px;
list-style:none;
font-size:14px;
}
ul.statuses li:first-child{
border-top:1px dashed #D2DADA;
}
ul.statuses li:hover {
background-color:#F7F7F7;
}
h3.timeline{
margin-top:20px;
color:#999999;
font-size:20px;
font-weight:normal;
}
div.tweetTxt{
float:left;
width:498px;
overflow:hidden;
}
ul.statuses a img.avatar{
float:left;
margin-right:10px;
border:1px solid #446600;
}
div.date{
line-height:18px;
font-size:12px;
color:#999999;
}
li a, li a:visited {
color:#007bc4;
text-decoration:none;
outline:none;
}
li a:hover{
text-decoration:underline;
}
我們從定義頁面樣式開始。首先我們重置我們的頁面(取消一些頁面元素的邊距和填充,默認情況下在不同的瀏覽器上有所不同)。之後在第 8 行,我們為正文設置了上邊距,並為頁面上的所有文本設置了字體顏色。
第 16 到 19 行是我們圍繞 div 的地方,包含我們的表單和時間線。直到最近,您才不得不手動創建圓角圖形並為每個角插入額外的 div 元素。但最新版本的 Firefox 和 Safari 可以使用純 CSS 實現。
不幸的是,其他瀏覽器不支持此方法。該技術的另一個小缺點是您必須使用特定於瀏覽器的 CSS 屬性來定位每個瀏覽器 - 例如 -moz-border-radius ,因為圓角不是當前 CSS 規範的一部分。但是如果它包含在未來的規範中,我們會包含應該直接支持的屬性 - border-radius ,從而產生了前面提到的 4 行代碼。
CSS 在第 59 行之前非常簡單。這是我之前提到的一個重要的 CSS hack(稱為 clearfix)。當 div 包含浮動元素時,它的高度不會放大到其子元素的高度。為此目的,插入了另一個具有 CSS 屬性 clear:both 的 div .這會迫使它在浮動元素下方換行,從而擴大其父元素的高度。
第 63 行 是我們設置提交按鈕的地方。在這裡,我們再次使用圓角邊框屬性,如您所見,它也適用於按鈕。另一個需要注意的重要事情是我們為按鈕定義了背景圖形。它正好是按鈕高度的兩倍。在其正常狀態下,圖像的頂部用作背景,懸停時 - 底部。這就是我們在第 82 行所做的。
第 87 行是 inact 班級。此類僅在按鈕被禁用時(在初始頁面加載時,或文本區域為空時)分配給按鈕,以防止用戶提交它。它也有一個定義的法線和 :hover 狀態,但它們是完全一樣的。這樣做是為了停止另一個 :hover 動作,該動作在第 81 行定義,影響按鈕。換句話說,我們設置了一個新的 :hover 類覆蓋前一個。
第 102 到 116 行定義了時間線元素的樣式。時間線只不過是一個無序列表。這裡要注意的有趣的事情是我們如何只使用 :first-child 處理第一個 li 元素 選擇器並給它一個上邊框。
jQuery 代碼
我再次選擇了 jQuery,因為它敏捷而簡單的方法可以用更少的代碼行完成更多的工作。
script.js
$(document).ready(function(){
$('#inputField').bind("blur focus keydown keypress keyup", function(){recount();});
$('input.submitButton').attr('disabled','disabled');
$('#tweetForm').submit(function(e){
tweet();
e.preventDefault();
});
});
function recount()
{
var maxlen=140;
var current = maxlen-$('#inputField').val().length;
$('.counter').html(current);
if(current<0 || current==maxlen)
{
$('.counter').css('color','#D40D12');
$('input.submitButton').attr('disabled','disabled').addClass('inact');
}
else
$('input.submitButton').removeAttr('disabled').removeClass('inact');
if(current<10)
$('.counter').css('color','#D40D12');
else if(current<20)
$('.counter').css('color','#5C0002');
else
$('.counter').css('color','#cccccc');
}
function tweet()
{
var submitData = $('#tweetForm').serialize();
$('.counter').html('<img style="padding:12px" src="img/ajax_load.gif" alt="loading" width="16" height="16" />');
$.ajax({
type: "POST",
url: "submit.php",
data: submitData,
dataType: "html",
success: function(msg){
if(parseInt(msg)!=0)
{
$('ul.statuses li:first-child').before(msg);
$("ul.statuses:empty").append(msg);
$('#lastTweet').html($('#inputField').val());
$('#inputField').val('');
recount();
}
}
});
}
我們可以把這段代碼分成三個重要的路徑。在頁面加載後執行的那個(第 1 行)。 recount() 函數,它用剩下的字符數填充我們的計數器範圍,以及 tweet() 處理 AJAX 通信和後續頁面更新以將新推文包含在時間線中的函數。
在第一部分,在第 3 行,您看到我們將 recount() 函數綁定到文本區域中可能發生的許多事件。這是因為這些事件中的任何一個本身都無法保證計數器的更新速度足夠快。
在下一行,我們禁用提交按鈕 - 我們不需要用戶能夠提交空表單。
稍後我們綁定 onsubmit 將表單事件發送到 tweet() 函數,防止在第 9 行提交實際表單。
在重新計票 功能有很多東西值得一提。在第 17-19 行,我們計算剩餘的字符,在第 21-36 行,根據我們與最大數量的接近程度,設置計數器的顏色。
我們還決定是否應該禁用按鈕(如果文本區域中沒有文本,或者超出限制),否則啟用它。通過設置屬性 disabled 來禁用/啟用按鈕 並分配我們的自定義 CSS 類 - inact ,這會移除手形光標並將其顏色更改為淺灰色。
推文 函數是魔法發生的地方。我們在 submitData 中序列化表單 變量並將計數器替換為旋轉的 gif 動畫。
在此之後,數據被發送到 submit.php 並根據返回值,將收到的推文插入到時間線的第 55 行和第 56 行。
這兩行代碼實際上是做什麼的?第 55 行使用相同的 :first-child 選擇器就像我們上面的樣式表一樣。這意味著它將在第一個元素之前插入它收到的格式化推文。那為什麼我們需要第二行呢?好吧,如果我們沒有發布任何推文, :first-child 將找不到任何元素。這就是我們使用 :empty 的原因 選擇器。這兩條線中只有一條可以同時插入元素,從而無需手動檢查時間軸中是否有元素。
插入新創建的推文後,我們清空文本區域並重新計算剩餘字符。
PHP
我們的 PHP 代碼管理 MySQL 數據庫中的數據插入以及我們的推文和時間線的格式。
提交.php
define('INCLUDE_CHECK',1);
require "functions.php";
require "connect.php";
if(ini_get('magic_quotes_gpc'))
$_POST['inputField']=stripslashes($_POST['inputField']);
$_POST['inputField'] = mysql_real_escape_string(strip_tags($_POST['inputField']),$link);
if(mb_strlen($_POST['inputField']) < 1 || mb_strlen($_POST['inputField'])>140)
die("0");
mysql_query("INSERT INTO demo_twitter_timeline SET tweet='".$_POST['inputField']."',dt=NOW()");
if(mysql_affected_rows($link)!=1)
die("0");
echo formatTweet($_POST['inputField'],time());
首先我們檢查是否 magic_quotes_gpc 已設置。這在某些主機上啟用,它的作用是自動轉義傳入的數據,這被認為是一種不好的做法。這就是為什麼如果它打開,我們會刪除轉義的代碼並可以正常繼續我們的腳本。
我們轉義數據,檢查 $_POST['inputField'] 的長度 並在我們的數據庫中插入該行。我們使用 formatTweet 回顯格式化的推文(稍後會詳細介紹),該推文返回到 tweet() jQuery函數作為變量msg .
functions.php
if(!defined('INCLUDE_CHECK')) die('You are not allowed to execute this file directly');
function relativeTime($dt,$precision=2)
{
$times=array( 365*24*60*60 => "year",
30*24*60*60 => "month",
7*24*60*60 => "week",
24*60*60 => "day",
60*60 => "hour",
60 => "minute",
1 => "second");
$passed=time()-$dt;
if($passed<5)
{
$output='less than 5 seconds ago';
}
else
{
$output=array();
$exit=0;
foreach($times as $period=>$name)
{
if($exit>=$precision || ($exit>0 && $period<60)) break;
$result = floor($passed/$period);
if($result>0)
{
$output[]=$result.' '.$name.($result==1?'':'s');
$passed-=$result*$period;
$exit++;
}
else if($exit>0) $exit++;
}
$output=implode(' and ',$output).' ago';
}
return $output;
}
function formatTweet($tweet,$dt)
{
if(is_string($dt)) $dt=strtotime($dt);
$tweet=htmlspecialchars(stripslashes($tweet));
return'
<li><a href="#"><img class="avatar" src="img/avatar.jpg" width="48" height="48" alt="avatar" /></a>
<div class="tweetTxt">
<strong><a href="#">demo</a></strong> '. preg_replace('/((?:http|https|ftp):\/\/(?:[A-Z0-9][A-Z0-9_-]*(?:\.[A-Z0-9][A-Z0-9_-]*)+):?(\d+)?\/?[^\s\"\']+)/i','<a href="$1" rel="nofollow" target="blank">$1</a>',$tweet).'
<div class="date">'.relativeTime($dt).'</div>
</div>
<div class="clear"></div>
</li>';
}
在這裡您可以看到 2 個功能。第一個 - relativeTime() 是我不久前做的一個函數,它顯示了自給定時間以來經過的相對時間段(它同時支持 unix 時間戳和 mysql 日期字符串作為參數)。
另一個是專門為本教程製作的。它僅使用推文文本和時間變量格式化並返回推文。如果您打算對示例進行更改,請從這裡開始。
格式推文 函數沒什麼特別的——首先我們決定是否應該將給定的時間參數從 mysql 數據字符串轉換為時間戳。在此之後,我們使用 htmlspecialchars 防止可能的漏洞 ,然後返回格式化的推文。這裡需要注意的一件有趣的事情是第 53 行。使用 preg_replace 函數我們將推文中包含的鏈接轉換為真正的超鏈接,並帶有 target 和 nofollow 屬性。

現在讓我們看看我們的時間線是如何實際生成的。
index.php
define('INCLUDE_CHECK',1);
require "functions.php";
require "connect.php";
// remove tweets older than 1 hour to prevent spam
mysql_query("DELETE FROM demo_twitter_timeline WHERE id>1 AND dt<SUBTIME(NOW(),'0 1:0:0')");
//fetch the timeline
$q = mysql_query("SELECT * FROM demo_twitter_timeline ORDER BY ID DESC");
$timeline='';
while($row=mysql_fetch_assoc($q))
{
$timeline.=formatTweet($row['tweet'],$row['dt']);
}
// fetch the latest tweet
$lastTweet = '';
list($lastTweet) = mysql_fetch_array(mysql_query("SELECT tweet FROM demo_twitter_timeline ORDER BY id DESC LIMIT 1"));
if(!$lastTweet) $lastTweet = "You don't have any tweets yet!";
此代碼位於頁面上任何 XHTML 代碼之前。出於演示的目的,我將推文設置為在一小時後自動刪除。您可以刪除此行以無限期保留推文。
這段代碼的主要目的是生成 $timeline 和 $lastTweet 變量,它們包含在本教程開頭的 XHTML 代碼中。
這樣我們自己的推特時間線就完成了。
結論
今天我們使用 PHP、MySQL、jQuery、CSS 和 XHTML 來創建我們自己的類似 twitter 的時間線。可能性是無窮無盡的——您可以將此示例變成留言簿、您網站上的社區推文、留言箱甚至下一個推特。