Hướng dẫn Sử dụng Jquery AJAX + PHP & MYSQL để phân trang

PVS

Super Moderator
Thành viên BQT
Tham gia
28/02/2015
Bài viết
16,728
Được Like
12,680
Sử dụng Jquery AJAX + PHP & MYSQL để phân trang

Bài viết này sẽ hướng dẫn các bạn cách phân trang với Jquery AJAX + PHP & MYSQL.
  • Để tiện cho việc tiếp thu bài này, các bạn nên xem lại bài Sử dụng PHP & MySQL để phân trang.
  • Do đây là bài viết nâng cao, nên bạn cần biết một số kiến thức cơ bản về PHP&MySQL để kết nối CSDL.
  • Hình ảnh, database được đính kèm trong file download.
Bước 1 – PHÂN TRANG VỚI PHP & MYSQL
Mã:
<!DOCTYPE HTML>
<html lang="en-US">
<head>
    <meta charset="UTF-8">
    <title>Pagination with Jquery AJAX + PHP</title>
    <link rel="stylesheet" type="text/css" href="css/reset.css" media="all">
    <link rel="stylesheet" type="text/css" href="css/style.css" media="all">
    <script type="text/javascript" src="js/jquery.1.7.2.min.js"></script>
    <script type="text/javascript" src="js/AJAX.js"></script>
</head>
<body>
    <div id="wrapper">
        <div id="loading"></div>
        <h1>Pagination Jquery AJAX + PHP</h1>
        <div id="data">
            <nav role="list">
                <ul>
            <?php
                
                $db = mysqli_connect('localhost','root','','pagination_ajax');
                $display = 10;
                if(isset($_GET['page']) && (int)$_GET['page']>=0) {
                   $page = $_GET['page'];
                } else {
                    $query = "SELECT COUNT(id) FROM data";
                    $result = mysqli_query($db,$query);
                    $rows = mysqli_fetch_array($result,MYSQLI_NUM);
                    $record = $rows[0];
                    if($record > $display) {
                        $page = ceil($record/$display);
                    } else {
                        $page = 1;
                    }
                }
 
                $start = (isset($_GET['start']) && (int)$_GET['start']>=0) ? $_GET['start'] : 0;
                $current = ($start/$display)+1;
                $next = $start + $display;
                $previous = $start - $display;
                $last = ($page - 1)*$display;
                if ($current >= 7) {
                    $start_page = $current - 3;
                    if ($page > $current + 3)
                        $end_page = $current + 3;
                    else if ($current <= $page && $current > $page - 6) {
                        $start_page = $page - 6;
                        $end_page = $page;
                    } else {
                        $end_page = $page;
                    }
                } else {
                    $start_page = 1;
                    if ($page > 7)
                        $end_page = 7;
                    else
                        $end_page = $page;
                }
 
 
 
                $query_data = "SELECT * FROM data
                               ORDER BY id
                               LIMIT $start, $display";
                $result_data = mysqli_query($db,$query_data);
                while($set = mysqli_fetch_array($result_data,MYSQLI_ASSOC)) {
                        $id = $set['id'];
                        $content = $set['content'];
                    echo "<li><span>$id</span> - $content</li>";
                }
            ?>
                </ul>
            </nav>
 
            <nav role="page">
                <ul>
                    <?php
                if($page > 1) {
                    if ($current > 1) {
                        echo "<li><a href='index.php?start=0&page=$page'>First</a></li>";
                        echo "<li><a href='index.php?start=$previous&page=$page'>Previous</a></li>";
                    }
 
                    for ($i = $start_page; $i <= $end_page; $i++) {
 
                        if ($current == $i)
                            echo "<li class='current'>$i</li>";
                        else
                            echo "<li><a href='index.php?start=".($display*($i-1))."&page=$page'>$i</a></li>";
                    }
 
                    if ($current < $page) {
                        echo "<li><a href='index.php?start=$next&page=$page'>Next</a></li>";
                        echo "<li><a href='index.php?start=$last'>Last</a></li>";
                    }
                }
                    ?>
                </ul>
            </nav>
        <span class='per_page'><?php echo "Trang " . $current . " => ". $page; ?></span>
 
        </div>
    </div><!-- End #wrapper -->
</body>
</html>

Bước 1.1 – CSS
Mã:
*{margin:0; padding:0;}
 
body {
    font-size: 62.5%;
    font-family: Arial, Helvetica, sans-serif;
}
 
#wrapper {
    width: 1000px;
    margin: 0 auto;
}
 
#data {
    position: relative;
}
 
h1 {
    font-size: 2.0em;
    text-align: center;
    margin-top: 50px;
}
 
nav[role="list"] {
    position: absolute;
    left: 230px;
    top: 20px;
    font-size: 1.7em;
}
 
nav[role="list"] ul li {
    padding-bottom: 10px;
}
 
nav[role="list"] ul li span {
    color: green;
    font-weight: bold;
}
 
nav[role="page"] {
    position: absolute;
    top: 300px;
    left: 220px;
}
 
nav[role="page"] ul li {
    float: left;
    margin-left: 10px;
    background: url(../images/pagenavi_bg.jpg) repeat-x top left;
}
 
nav[role="page"] ul li a {
    color: white;
    text-decoration: none;
    display: block;
    padding: 8px;
    font-weight: bold;
    font-size: 1.2em;
}
 
nav[role="page"] ul li a:hover {
    background: url(../images/pagenavi_bg.jpg) repeat-x bottom left;
}
 
nav[role="page"] ul li.current {
    font-weight: normal;
    font-size: 1.2em;
    padding: 8px;
    color: white;
    background: url(../images/pagenavi_bg.jpg) repeat-x bottom left
}
 
#data >  span.per_page {
    font-weight: bold;
    padding: 8px 8px 9px 8px;
    color: white;
    background: url(../images/pagenavi_bg.jpg) repeat-x top left;
    position: absolute;
    top: 300px;
    right: 150px;
    font-size: 1.2em;
    width: 88px;
    text-align: center;
}

Công việc mình cần làm ở phần này như sau :

1. Xác định bao nhiêu dòng dữ liệu hiển thị trên một trang
Mã:
$display = 10; // Mình muốn hiển thị 10 dòng trên một trang

2. Tính tổng số trang
Mã:
If(isset($_GET[‘page’]) && (int)$_GET[‘page’]>=0) {
    $page = $_GET[‘page’];
}

Đầu tiên mình sẽ kiểm tra xem nếu tổng số trang đã được tính chưa và tổng số trang của mình phải là một số nguyên >=0 thì mình lấy giá trị của nó, nếu chưa có mình sẽ đi tính tổng số trang.

Mình sử dụng hàm COUNT trong câu lệnh truy vấn MYSQL để lấy ra tổng số dòng trong CSDL. Tiếp theo mình tính số trang bằng cách lấy tổng số dòng dữ liệu chia cho tổng số dữ liệu muốn hiển thị và dùng hàm ceil để làm tròn số vì mình không muốn trang của mình có số dư như là 1.4 hay 2.2, số trang của mình phải là một số nguyên không âm.
Mã:
if($record > $display) {
    $page = ceil($record/$display);
} else {
    $page = 1;
}

Nhưng gặp trường hợp tổng số dòng dữ liệu mình lấy ra nó lại nhỏ hơn số dòng muốn hiển thị thì mình phải kiểm tra nó, nếu tổng số dữ liệu mình lớn hơn tổng số dòng hiển thị thì mình thực hiện tính và ngược lại thì tổng số trang của mình là 1.

3. Xác định dòng bắt đầu trong CSDL
Mã:
$start = (isset($_GET['start']) && (int)$_GET['start']>=0) ? $_GET['start'] : 0;

Nếu số đã có số dòng bắt đầu và nó là một số nguyên >=0 thì mình lưu nó lại, ngược lại thì dòng bắt đầu của mình là 0.

4. Tính trang hiện tại, trang sau, trang kế tiếp, trang cuối, hiển thị số trang.
Mã:
$current = ($start/$display)+1;  // Trang hiện tại = ( số dòng bắt đầu / số dòng hiển thị ) + 1
$next = $start + $display;  // Trang tiếp theo =  số dòng bắt đầu + số dòng hiển thị
$previous = $start - $display; // Trang sau = số dòng bắt đầu  - số dòng hiển thị
$last = ($page - 1)*$display; // Trang cuối = ( tổng số trang – 1 ) * số dòng hiển thị

Hiển thị số link của trang
Mã:
if ($cur_page >= 7) {
    $start_page = $cur_page - 3;
if ($page > $cur_page + 3)
    $end_page = $cur_page + 3;
else if ($cur_page <= $page && $cur_page > $page - 6) {
    $start_page = $page - 6;
    $end_page = $page;
} else {
    $end_page = $page;
}
} else {
    $start_page = 1;
if ($page > 7)
    $end_page = 7;
else
    $end_page = $page;
}

Mình muốn số link hiển thị là 7 để khi CSDL nó lên đến hàng ngàn dòng thì số link sẽ không hiển thị ra quá nhiều. Nếu trang hiện tại >=7 thì trang bắt đầu bằng trang hiện tại trừ đi 3. Mình muốn ở sau trang hiện tại của mình là 3 trang và phía trước của nó là 3 trang thì mình kiểm tra thêm một lần nữa là nếu tổng số trang lớn hơn trang hiện tại + 3 thì trang kết thúc của mình là trang hiện tại + 3. Ngược lại nếu trang hiện tại mình nhỏ hơn hoặc bằng tổng số trang và trang hiện tại nhỏ hơn tổng số trang – 6 thì trang bắt đầu của mình là tổng số trang – 6 và trang kết thúc của mình là bằng chính tổng số trang. Nếu trường hợp trên không xảy ra thì mình gán trang kết thúc bằng tổng số trang.

Ngược lại của trường hợp trang hiện tại >= 7 thì trang bắt đầu sẽ là 1. Nếu tổng số trang lớn hơn 7 thì trang kết thúc của mình sẽ là 7 và ngược lại thì trang kết thúc bằng tổng số trang. Đoạn hiển thị số link của trang có vẽ hơi khó hiểu, bạn nên xem kỹ nhé.

5. Truy vấn CSDL

Sau khi đã có hai biến $display & $start thì mình bắt đầu SELECT CSDL, LIMIT ở đây được gọi là giới hạn, khi người dùng truy cập vào lần đầu tiên thì biến $start của mình sẽ không set được có nghĩa là nó là = 0 và biến $display mình đã khai báo trên kia là 10 thì nó sẽ xuất ra cho mình 10 dòng dữ liệu đầu tiên.

6. Hiển thị phân trang

Sau khi mình đã tính toán các bước cần thiết ở trên, bây giờ mình sẽ cho nó hiển thị ra ngoài. Nếu tổng số trang của mình > 1 thì mình sẽ phân trang cho nó còn nhỏ hơn 1 thì chỉ có 1 trang nên mình không cần phân trang làm gì.

Hiển thị trang đầu ( First page ) và trang sau ( Previous page )
Mã:
if ($current > 1) {
    echo "<li><a href='index.php?start=0&page=$page'>First</a></li>";
if ($current > 1) {
    echo "<li><a href='index.php?start=$previous&page=$page'>Previous</a></li>";
}

Nếu trang hiện tại của mình > 1 thì nó mới xuất hiện, trang đầu của mình thì tham số start của mình chắc chắn nó sẽ = 0 thì mình sẽ gán trực tiếp giá trị vào luôn.

Hiển thị số link của trang ( Link page )
Mã:
for ($i = $start_page; $i <= $end_page; $i++) {
    if ($current == $i)
    echo "<li class='current'>$i</li>";
else
echo "<li><a href='index.php?start=".($display*($i-1))."&page=$page'>$i</a></li>"; }

Ở phần trên mình đã tính được trang bắt đầu và trang cuối của mình thì bây giờ mình sẽ dùng vòng lặp For để lấy nó ra. Khi người dùng truy cập lần đầu tiên thì trang bắt đầu của mình luôn luôn sẽ là 1 và trang kết thúc của mình sẽ là 7. Khi người dùng di chuyển sang trang 7 thì bước nhảy của mình sẽ được tính như ở trên có nghĩa là trang hiện tại của mình là 7 thì phía sau nó sẽ có 3 trang là 6 5 4 và phía trước của nó sẽ có 3 trang nữa là 8 9 10 và nó sẽ tiếp tục tăng dần cho đến trang cuối cùng.

Hiển thị trang tiếp theo (Next page) và trang cuối (Last page)
Mã:
if ($current < $page) {
    echo "<li><a href='index.php?start=$next&page=$page'>Next</a></li>";
}
if ($current < $page) {
    echo "<li><a href='index.php?start=$last'>Last</a></li>";
}

Nếu trang hiện tại của mình vẫn nhỏ hơn tổng số trang thì mình cho hiển thị nó ra, các tham số mình đã tính ở trên thì bây giờ chỉ việc thay biến đó vào thôi ^^.

Bước 2 – ÁP DỤNG JQUERY AJAX
Mã:
<?php
 
if($_POST['page']) {
$page = $_POST['page'];
$current_page = $page;
$page -= 1;
$display = 10;
$start = $page * $display;
$db = mysqli_connect('localhost','root','','pagination_ajax');
 
$data = "";
 
$query = "SELECT * FROM data
          ORDER BY id
          LIMIT $start, $display";
$result = mysqli_query($db,$query);
while($rows = mysqli_fetch_array($result,MYSQLI_ASSOC)) {
    $id = $rows['id'];
    $content = $rows['content'];
    $data .= "<li><span>$id</span> - $content</li>";
}
 
$data = "<nav role='list'>
            <ul>".$data."</ul>
        </nav>";
 
$query_page = "SELECT COUNT(*) AS count FROM data";
$result_page = mysqli_query($db,$query_page);
$row = mysqli_fetch_array($result_page);
$count = $row['count'];
$pages = ceil($count / $display);
 
if ($current_page >= 7) {
    $start_page = $current_page - 3;
        if ($pages > $current_page + 3)
            $end_page = $current_page + 3;
        else if ($current_page <= $pages && $current_page > $pages - 6) {
            $start_page = $pages - 6;
            $end_page = $pages;
        } else {
            $end_page = $pages;
        }
} else {
    $start_page = 1;
if ($pages > 7)
    $end_page = 7;
else
    $end_page = $pages;
}
 
$data .= "<nav role='page'><ul>";
 
if ($current_page > 1) {
    $data .= "<li page='1'>First</li>";
    $previous = $current_page - 1;
    $data .= "<li page='$previous'>Previous</li>";
}
 
for ($i = $start_page; $i <= $end_page; $i++) {
    if ($current_page == $i)
        $data .= "<li page='$i' class='current'>{$i}</li>";
    else
        $data .= "<li page='$i'>{$i}</li>";
}
 
if ($current_page < $pages) {
    $next = $current_page + 1;
    $data .= "<li page='$next'>Next</li>";
    $data .= "<li page='$pages'>Last</li>";
}
 
$total_page = "<span class='per_page'>Trang ". $current_page ." => $pages </span>";
 
$data = $data . "</ul></nav>".$total_page;
 
echo $data;
 
}
?>

Khi mình bắt đầu chuyển nó sang dạng phân trang với Jquery AJAX thì cấu trúc của nó sẽ có một số thay đổi để phù hợp nên phần này là quan trọng các bạn hãy chú ý thật kỹ nhé.

Khi mình sử dụng Jquery AJAX để load dữ liệu thì mình phải kiểm tra xem nếu có trang nào thì mới thực hiện load dữ liệu và ngược lại sẽ không load gì cả.

Nếu có thì mình sẽ lưu giá trị nó vào một biến $page và biến $page của mình khi được load lần đầu tiên thì nó luôn luôn là trang 1 và nó cũng chính là trang hiện tại.

Các bạn thấy biến $page -= 1 nó có nghĩa là khi truy cập lần đầu tiên thì biến $page của mình là trang 1 thì -=1 là chính nó trừ đi 1 thì lúc này $page của mình sẽ là 0. Sau đó mình có biến $display =10 thì lúc này $page của mình = 0 và $display = 10 thì mình sẽ có $start = 0 vì 0 x 10 thì = 0 chứ nhỉ ^^ .

Trong cuộc gọi AJAX thì dữ liệu của mình trả về là một chuỗi hay một mảng giá trị lưu giữ toàn bộ giá trị đó thì lúc này mình sẽ khởi tạo một biến $data = ” “, có nghĩa là chuỗi này ban đầu sẽ chưa có gì cả. Sau đó mình mới truy vấn CSDL và lấy dữ liệu của nó ra và lưu vào biến này.

Trong đó biến $data .= này có nghĩa là khi vòng lặp while của mình nó lấy dữ liệu từ dòng thứ 1 cho đến dòng cuối cùng thì nó sẽ nối tiếp lại với nhau. Trong PHP muốn nối một chuỗi thì mình dùng dấu “ . “ nhưng ở đây mình muốn nối tiếp nhiều chuỗi vào cùng trong một biến thì mình dùng thêm “ = “ vậy là mình đã nối chúng lại với nhau thành một chuỗi lớn.

Và cuối cùng mình cũng thực hiện các bước phân trang như ở phần 1 và mình sẽ không xuất nó ra mà lưu nó tiếp vào biến $data vì để khi mình echo $data ra thì dữ liệu của mình sẽ trả về toàn bộ.

Nhưng một đặc điểm đáng lưu lý ở đây là các bạn sẽ thấy mình sẽ không còn dùng thẻ a với link là index.php?start=??&page=?? nữa vì bây giờ mình chỉ cần lấy số trang và dùng AJAX để load trang đó nên mình chỉ cần thẻ li là đủ, trong này mình sẽ truyền tham số cho thẻ li qua một chổ tạm là page và khi mình load trang thì chỉ cần sử dụng hàm attr trong Jquery để lấy tham số này và truyền vào để AJAX xử lý thôi.

Bước cuối cùng cũng là bước quan trọng nhất khi dữ liệu mình đã có thì mình dùng AJAX để gọi nó ra.
Mã:
function pagination(page){
    $('#loading').html("<img src='images/loading.gif'/>").fadeIn('fast');                 
    $.ajax ({
        type: "POST",
        url: "pagination.php",
        data: "page="+page,
        success: function(data_page) {
            $('#loading').fadeOut('fast');
            $("#data").html(data_page); 
        }
    });
}

Mình sẽ viết một hàm pagination có tham số là page có nghĩa là tham số mình truyền vào chính là số trang. Mình vẫn sử dụng phương thức là POST và dữ liệu của mình là từ file pagination.php, data của mình là số trang hiển thị, thì page của mình sẽ = tham số page, nhắc lại một xíu là dấu ” + ” có nghĩa là nối chuỗi trong Jquery nhé. Lúc này trong thẻ
Mã:
<div id="data">

của mình sẽ là rỗng, chưa có gì cả và bây giờ mình dùng AJAX để đổ dữ liệu vào đó.
Mã:
   pagination(1); 
   $("nav[role='page'] > ul li").live('click',function(){
    var page = $(this).attr('page');
    pagination(page);
});

Sau khi viết xong hàm pagination để gọi trang thì lúc đầu mình muốn khi người dùng truy cập lần đầu tiên nó sẽ gọi trang 1 thì mình chạy hàm pagination với tham số page=1. Sau đó mình sử dụng Jquery để xử lý khi họ chuyển trang, khi thẻ li được click thì mình sẽ lấy tham số của thẻ li mà mình đã truyền trong file pagination.php đó lưu vào biến page và gọi hàm pagination với tham số là page để gọi trang mà họ di chuyển tới.

Một điểm nữa là khi mình sử dụng sự kiện live() thì sự kiện này sẽ được sử dụng trong suốt quá trình chạy website và khi mình dùng AJAX kết quả trả về là success thì dữ liệu sẽ được append vào document. Những element (thẻ li) sau sẽ không nhận được các sự kiện click hay submit nữa, khi đó mình phải sử dụng sự kiện live() để di chuyển sang trang khác.

Chúc các bạn thành công.


Nguồn: izwebz.com​
 

Hướng dẫn sử dụng

XenForo 1 XenForo 2
Translate by PVS

Dịch vụ XenForo của VNXF

Mr. Tuấn

Mobile/Zalo: 0988 488 096

Telegram: bluekpro

Email: [email protected]

Nhà Tài Trợ

Mút Xốp Không Gian
pallet Thịnh Phát
Top Bottom