php整合pjax(pushstate+ajax)實現無刷新頁面

PJAX效果javascript

經過url能夠跟蹤ajax的動態加載內容。這種技術尤爲在two step view佈局的視圖中有很大的好處。無刷新加載頁面,意味着響應速度和用戶體驗獲得了極大的提高,在靜態腳本和通用模塊比較多的狀況下,最大程度上節省了重用部分的開銷。應用例子能夠參考如今的google+、facebook和新版微博,一樣是基於html5的pushState實現。g plus的表現最爲明顯,點擊導航欄地址,箭頭隨目標移動,同時加載的頁面淡入,效果很炫。php

Dirty url 和 Clean urlhtml

在pjax出現以前,要實現頁面的無刷新加載並經過url能夠追蹤,須要瀏覽器支持window.location.hash屬性。經過判斷url#錨後記錄的地址來決定須要加載的內容,具體的構建方法是寫一個hashchange的監視函數,當觸發到hash改變時便判斷加載內容。它的不足在於,對於低版本的瀏覽器例如ie6不支持hash,須要另外構建一個iframe來記錄歷史url實現前進和後退。最大的問題,即是#後生成的內容不會被搜索引擎索引到,google以前提供了解決方案,提倡使用#!把地址引導到一個?escape_fragment=url的請求地址中,我在twitter、facebook、人人、新浪微博和已經關閉了的豆瓣說中都看見曾經或正在使用這種hash bang。經過#!來實現無刷新加載的url,因爲通常的方法不容易被搜索引擎收錄(例如國內百度),稱其爲dirty url,相對而言,pjax可以使用clean url獲得一樣效果,並能很好地兼容各類瀏覽器,是如今最爲適合的方法前端

使用PHP+jQuery實現PJAXhtml5

不須要從頭編寫基於pushState的javascript插件,由於jQuery已有項目把它開源出來,並且很輕易便能實現。目前我已經在開發中的項目裏引入,並且很好地在原有的基礎上兼容,況且新版微博的推廣,我但願讓觀衆看到,我用完以後是這個樣子,大家用完以後也會是這個樣子java

開始前的準備:jquery

1. jQuery libray http://code.jquery.com/jquery-1.8.2.min.jsgit

2. 基於jQ的pjax插件(github上的開源項目)  https://github.com/defunkt/jquery-pjax github

3. PHP項目代碼(方便分享,本文使用codeigniter和yaf框架演示,實際開發中大同小異)web

一 前端實現

最最最基本須要先引入jquery庫,在頁頭中引入腳本地址 (sina的cdn)

<script src=」http://lib.sinaapp.com/js/jquery/1.8/jquery.min.js」></script>

根據第二條中的項目插件,加入jq的pjax插件地址

<script src=」BASEURL_TO_PJAX_PLUGIN」></script>

接下來,咱們來看看github上做者的說明,更直接,能夠直接打開插件看代碼。最簡單的使用方法以下

$('#main').pjax('a')

上述語句表示,點擊dom中的任何a標籤,將會發起pjax請求並將內容替換到id爲main的頁面元素內

使用實在簡單,並且jquery-pjax這個插件封裝得很好,絕對能夠按照你的喜愛來定製(例如複製g plus的效果),下面是一個整合以上步驟的基本html示例代碼

<html>
    <head>
        <script type="text/javascript" src="http://lib.sinaapp.com/js/jquery/1.8/jquery.min.js"></script>
        <script type="text/javascript" src="/js/jquery-pjax.js"></script>
    </head>
    <body>
        <script type="text/javascript">
            $(document).ready(function(){
                $("#main").pjax("a");
            });
        </script>
        <div id="nav">
            <a href="/test1">test1</a><a href="/test2">test2</a>
        </div>
        <div id="main">替換的內容</div>
     </body>
</html>

最終的目的,就是點擊地址爲/test1和/test2的a標籤時,經過ajax返回的結果將id爲main的div內的文字替換爲相應的地址內容,url自動更新,同時頁面不會從新載入。下面開始實現後端要處理的內容

二.PHP端的實現

php端須要處理的任務主要是兩件:1.實現layout視圖佈局  2.判斷pjax過來的請求

layout使每一個視圖的輸出都是在一個公用模版之上。

CI的實現:

寫一個自定義的layout library文件:

<?php
/*
*  
* --------------------------------------------------------------------
*  視圖佈局類
* --------------------------------------------------------------------
*
*  @author ekin.cen <weibo.com/2839892994>
*  
*/
class Layout{
 
    public $obj;
    public $disable_layout = FALSE; 
    protected $_layout;
    protected $_layout_dir = 'layout';
    protected $_template_dir = 'templates';
    protected $_data = array();
 
    public function __construct()
    {
        $this->obj = &get_instance();
    }
 
    public function set_layout($layout)
    {
 
        $this->_layout = $layout;
        return $this;
    }
 
    public function set_layout_dir($dirname)
    {
        $this->_layout_dir = $dirname;
        return $this;
    }
 
    public function set_template_dir($dirname)
    {
        $this->_template_dir = $dirname;
        return $this;
    }
 
    public function view($view, $data = NULL, $return = FALSE)
    {
        $view = $this->_template_dir . DIRECTORY_SEPARATOR . $view;
        $this->_layout = $this->_layout_dir . DIRECTORY_SEPARATOR . $this->_layout;
 
        if ($this->_data)
        {
            $data = $data ? array_merge($this->_data, $data) : $this->_data;
        }
        if ($this->disable_layout)
        {
            echo $this->obj->load->view($view, $data, TRUE);
        }
        else
        {
            $data = array('TEMPLATE_CONTENT' => $this->obj->load->view($view, $data, TRUE));
            $this->obj->load->view($this->_layout,$data,$return);
        }
    }
 
    public function assign($key, $value = null)
    {
        $data = is_array($key) ? $key : array($key => $value);
        $this->_data = array_merge($data, $this->_data);
        return $this;
    }
}
/* End of file */

將以上文件命名未Layout.php放在application/libraries文件夾中,並在autoload文件中加入:

$autoload['libraries'] = array('layout');

調用時,在通常的controller中輸出視圖的方法

$this->load->view(TEMPLATE_PATH,$data);

變成:

$this->layout->view(TEMPLATE_PATH,$data);

 以上Layout文件中視圖模版的輸出路徑默認在 /view/templates/,layout模版對應的位置爲/view/layout/ ,在/view/layout中新建一個模版文件(layout_test.php), 代碼以下:

<html>
    <head>
        <script type="text/javascript" src="http://lib.sinaapp.com/js/jquery/1.8/jquery.min.js"></script>
        <script type="text/javascript" src="/js/jquery-pjax.js"></script>
    </head>
    <body>
        <script type="text/javascript">
            $(document).ready(function(){
                $("#main").pjax("a");
            });
        </script>
        <div id="nav">
            <a href="/test1">test1</a><a href="/test2">test2</a>
        </div>
        <div id="main"><?=$LAYOUT_CONTENT;?></div>
     </body>
</html>

上面只是將html模版中要替換的內容變成了咱們控制器須要輸出的視圖模版內容($LAYOUT_CONTENT)。

到目前爲止已經能夠在CI中使用layout,剩下的就是在前端控制器中判斷請求類型,若是存在$_SERVER['HTTP_X_PJAX']類型,就不輸出layout,直接返回組件的渲染內容。 

使用自定義的控制器,在application/core文件夾中新建文件 MY_Controller(默認的前綴根據配置定義),添加以下代碼:

<?php
/*
 * 
 * @author ekin.cen<weibo.com/2839892994>
 * 
 */

class MY_Controller extends CI_Controller
{
    //默認的layout模版
    protected $_layout = 'layout_test';


    public function __construct()
    {
        parent::__construct();
        $this->_initialize();
    }

    protected function _initialize()
    {
        //如設置了autoload文件,則此步省略
        $this->_set_layout(); 
        // check if is pjax request
        if (array_key_exists('HTTP_X_PJAX', $_SERVER) && $_SERVER['HTTP_X_PJAX'])
        {
            $this->layout->disable_layout = true;
        }
    }

    protected function _set_layout()
    {
        $this->load->library('layout');
        $this->layout->set_layout($this->_layout);
    }
}

/* End of file MY_Controller.php */

 到此爲止,已經準備好並能測試效果了 :)

編寫兩個測試控制器test1和test2, 經過layout方法輸出視圖

class Test1 extends MY_Controller{

    public function index(){
        $this->layout->view('test1');
    }
}

打開瀏覽器查看網絡請求狀態

上圖是點擊地址爲「/test」的a標籤後獲得的pjax請求,說明整合成功

--------------------------------------

jquery-pjax使用中須要注意的事項:

1.返回的模版內容不能爲純文本,須要用html標籤包裹

2.插件的使用方法,詳情參考github的項目說明,更新後使用方法或有不一樣

3.對於不支持pushstate的低版本瀏覽器,pjax插件會自動判斷並使用傳統的頁面加載模式

4.當一個頁面的pjax請求時間超過設定時間時,會使用刷新來加載,須要調整插件內的相關參數

目前整理了適用於CI和yaf的demo,CI論壇的傳送門地址包含下載 http://codeigniter.org.cn/forums/thread-14433-1-1.html

相關文章
相關標籤/搜索