Như bạn biết thường thì khi ta làm việc với ajax sẽ bị hạn chế với Search Engine, nhưng với công nghệ hiện nay thì có một kỹ thuật nho nhỏ giúp ta sử dụng ajax mà vẫn chạy được cho SEO, và đây cũng là lý do tôi mở ra bài này.
Trong bài nay tôi sẽ làm một ví dụ nhỏ nhỏ về phân trang ajax có thay đổi URL, trong bài tôi có sử dụng thư viện phân trang của bài "Thuật toán phân trang" nên nếu bạn chưa biết thuật toán phân trang thì quay lại và đọc bài đó nhé.
Trong bài nay tôi sẽ làm một ví dụ nhỏ nhỏ về phân trang ajax có thay đổi URL, trong bài tôi có sử dụng thư viện phân trang của bài "Thuật toán phân trang" nên nếu bạn chưa biết thuật toán phân trang thì quay lại và đọc bài đó nhé.
1. Tạo cơ sở dữ liệu
Bạn tạo một database mới tên là 
test và chạy đoạn code câu truy vấn sau:| 
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 | CREATETABLEIF NOTEXISTS `member` (  `id` int(11) unsigned NOTNULLAUTO_INCREMENT,  `username` varchar(30) DEFAULTNULL,  `email` varchar(255) DEFAULTNULL,  `fullname` varchar(255) DEFAULTNULL,  `phone` varchar(30) DEFAULTNULL,  PRIMARYKEY(`id`)) ENGINE=InnoDB  DEFAULTCHARSET=latin1 AUTO_INCREMENT=10 ;---- Contenu de la table `member`--INSERTINTO`member` (`id`, `username`, `email`, `fullname`, `phone`) VALUES(1, 'thehalfheart', 'thehalfheart@gmail.com', 'Nguyen B', '1234567890'),(2, 'freetuts', 'freetuts.net@gmail.com', 'Nguyen A', '5245234534'),(3, 'kingston', 'kingston@gmail.com', 'Nguyen C', '4234234343'),(4, 'cafeviet', 'cafeviet@gmail.com', 'Nguyen D', '4234324344'),(5, 'emailer', 'emailer@gmail.com', 'Nguyen E', '4354354656'),(6, 'domain', 'domain@gmail.com', 'Nguyen F', '4324234343'),(7, 'root', 'root@gmail.com', 'Nguyen G', '4343253543'),(8, 'admin', 'admin@gmail.com', 'Nguyen H', '5465465767'),(9, 'supper', 'supper@gmail.com', 'Nguyen I', '3442342323'); | 
2. Viết thư viện phân trang
Bạn tạo một trang 
pagination.php với nội dung như sau:| 
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 
40 
41 
42 
43 
44 
45 
46 
47 
48 
49 
50 
51 
52 
53 
54 
55 
56 
57 
58 
59 
60 
61 
62 
63 
64 
65 
66 
67 
68 
69 
70 
71 
72 
73 
74 
75 
76 
77 
78 
79 
80 
81 
82 
83 
84 
85 
86 
87 
88 
89 
90 
91 
92 
93 
94 
95 
96 
97 
98 
99 
100 
101 
102 
103 
104 
105 
106 
107 
108 
109 
110 
111 
112 
113 
114 
115 
116 
117 
118 
119 
120 
121 
122 
123 
124 
125 
126 
127 
128 
129 
130 
131 
132 
133 
134 
135 
136 
137 
138 
139 
140 
141 
142 
143 
144 
145 
146 
147 
148 
149 
150 
151 
152 
153 
154 
155 
156 
157 
158 
159 
160 
161 
162 
163 
164 
165 
166 
167 
168 
169 
170 
171 
172 
173 
174 
175 
176 
177 
178 
179 
180 
181 
182 
183 
184 
185 
186 
187 
188 | classPagination    protected$_config= array(        'current_page'=> 1, // Trang hiện tại        'total_record'=> 1, // Tổng số record        'total_page'=> 1, // Tổng số trang        'limit'=> 10,// limit        'start'=> 0, // start        'link_full'=> '',// Link full có dạng như sau: domain/com/page/page        'link_first'=> '',// Link trang đầu tiên        'range'=> 9, // Số button trang bạn muốn hiển thị        'min'=> 0, // Tham số min        'max'=> 0  // tham số max, min và max là 2 tham số private    );        functionget_config($key)        return$this->_config[$key];            /*     * Hàm khởi tạo ban đầu để sử dụng phân trang     */    functioninit($config= array())            /*         * Lặp qua từng phần tử config truyền vào và gán vào config của đối tượng         * trước khi gán vào thì phải kiểm tra thông số config truyền vào có nằm         * trong hệ thống config không, nếu có thì mới gán         */        foreach($configas$key=> $val)            if(isset($this->_config[$key]))                $this->_config[$key] = $val;                                    /*         * Kiểm tra thông số limit truyền vào có nhỏ hơn 0 hay không?         * Nếu nhỏ hơn thì gán cho limit = 0, vì trong mysql không cho limit bé hơn 0         */        if($this->_config['limit'] < 0)            $this->_config['limit'] = 0;                        /*         * Tính total page, công tức tính tổng số trang như sau:         * total_page = ciel(total_record/limit).         * Tại sao lại như vậy? Đây là công thức tính trung bình thôi, ví         * dụ tôi có 1000 record và tôi muốn mỗi trang là 100 record thì         * đương nhiên sẽ lấy 1000/100 = 10 trang đúng không nào :D         */        $this->_config['total_page'] = ceil($this->_config['total_record'] / $this->_config['limit']);                /*         * Sau khi có tổng số trang ta kiểm tra xem nó có nhỏ hơn 0 hay không         * nếu nhỏ hơn 0 thì gán nó băng 1 ngay. Vì mặc định tổng số trang luôn bằng 1         */        if(!$this->_config['total_page'])            $this->_config['total_page'] = 1;                        /*         * Trang hiện tại sẽ rơi vào một trong các trường hợp sau:         *  - Nếu người dùng truyền vào số trang nhỏ hơn 1 thì ta sẽ gán nó = 1         *  - Nếu trang hiện tại người dùng truyền vào lớn hơn tổng số trang         *    thì ta gán nó bằng tổng số trang         * Đây là vấn đề giúp web chạy trơn tru hơn, vì đôi khi người dùng cố ý         * thay đổi tham số trên url nhằm kiểm tra lỗi web của chúng ta         */        if($this->_config['current_page'] < 1)            $this->_config['current_page'] = 1;                        if($this->_config['current_page'] > $this->_config['total_page'])            $this->_config['current_page'] = $this->_config['total_page'];                        /*         * Tính start, Như bạn biết trong mysql truy vấn sẽ có limit và start         * Muốn tính start ta phải dựa vào số trang hiện tại và số limit trên mỗi trang         * và áp dụng công tức start = (current_page - 1)*limit        */        $this->_config['start'] = ($this->_config['current_page'] - 1) * $this->_config['limit'];                /*         * Bây giờ ta tính số trang ta show ra trang web         * Như bạn biết với những website có data lớn thì số trang có thể         * lên tới hàng trăm trang, chẵng nhẽ ta show hết cả 100 trang?         * Nên trong bài này tôi hướng dẫn bạn show trong một khoảng nào đó (range)         * giống website freetuts.net vậy        */                // Trước tiên tính middle, đây chính là số nằm giữa trong khoảng tổng số trang        // mà bạn muốn hiển thị ra màn hình        $middle= ceil($this->_config['range'] / 2);        // Ta sẽ lâm vào các trường hợp như bên dưới        // Trong trường hợp này thì nếu tổng số trang mà bé hơn range        // thì ta show hết luôn, không cần tính toán làm gì        // tức là gán min = 1 và max = tổng số trang luôn        if($this->_config['total_page'] < $this->_config['range'])            $this->_config['min'] = 1;            $this->_config['max'] = $this->_config['total_page'];                // Trường hợp tổng số trang mà lớn hơn range        else                    // Ta sẽ gán min = current_page - (middle + 1)            $this->_config['min'] = $this->_config['current_page'] - $middle+ 1;                        // Ta sẽ gán max = current_page + (middle - 1)            $this->_config['max'] = $this->_config['current_page'] + $middle- 1;                        // Sau khi tính min và max ta sẽ kiểm tra            // nếu min < 1 thì ta sẽ gán min = 1  và max bằng luôn range            if($this->_config['min'] < 1)                $this->_config['min'] = 1;                $this->_config['max'] = $this->_config['range'];                                    // Ngược lại nếu min > tổng số trang            // ta gán max = tổng số trang và min = (tổng số trang - range) + 1            elseif($this->_config['max'] > $this->_config['total_page'])                            $this->_config['max'] = $this->_config['total_page'];                $this->_config['min'] = $this->_config['total_page'] - $this->_config['range'] + 1;                                /*     * Hàm lấy link theo trang     */    privatefunction__link($page)            // Nếu trang < 1 thì ta sẽ lấy link first        if($page<= 1 && $this->_config['link_first'])            return$this->_config['link_first'];                // Ngược lại ta lấy link_full        // Như tôi comment ở trên, link full có dạng domain.com/page/page.        // Trong đó page là nơi bạn muốn số trang sẽ thay thế vào        returnstr_replace('page', $page, $this->_config['link_full']);            /*     * Hàm lấy mã html     * Hàm này ban tạo giống theo giao diện của bạn     * tôi không có config nhiều vì rất rối     * Bạn thay đổi theo giao diện của bạn nhé     */    functionhtml()              $p= '';        if($this->_config['total_record'] > $this->_config['limit'])                    $p= '<ul>';                        // Nút prev và first            if($this->_config['current_page'] > 1)                            $p.= '<li><a href="'.$this->__link('1').'">First</a></li>';                $p.= '<li><a href="'.$this->__link($this->_config['current_page']-1).'">Prev</a></li>';                                    // lặp trong khoảng cách giữa min và max để hiển thị các nút            for($i= $this->_config['min']; $i<= $this->_config['max']; $i++)                            // Trang hiện tại                if($this->_config['current_page'] == $i)                    $p.= '<li><span>'.$i.'</span></li>';                                else                    $p.= '<li><a href="'.$this->__link($i).'">'.$i.'</a></li>';                                        // Nút last và next            if($this->_config['current_page'] < $this->_config['total_page'])                            $p.= '<li><a href="'.$this->__link($this->_config['current_page'] + 1).'">Next</a></li>';                $p.= '<li><a href="'.$this->__link($this->_config['total_page']).'">Last</a></li>';                                    $p.= '</ul>';                return$p;     | 
Đây là thư viện mà tôi đã đề cập ở trên nên bạn hãy quay lại và xem bài đó để rõ hơn nhé.
3. Viết thư viện xử lý database
Trong phần này tôi sẽ viết một thư viện xử lý danh sách thành viên gồm 4 hàm chính, đó là hàm kết nối, ngắt kết nối, hàm lấy danh sách, hàm lấy tổng số record.
Bạn tạo file 
database.php với nọi dung như sau:| 
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 
40 
41 
42 
43 
44 
45 
46 
47 | // Khai báo biến toàn cục kết nốiglobal$conn;// Hàm kết nối databasefunctionconnect()    global$conn;    $conn= mysqli_connect('localhost', 'root', 'vertrigo', 'test') ordie('error:"bad_request"');// Hàm đóng kết nốifunctiondisconnect()    global$conn;    if($conn)        mysqli_close($conn);    // Hàm đếm tổng số thành viênfunctioncount_all_member()    global$conn;    $query= mysqli_query($conn, 'select count(*) as total from member');    if($query)        $row= mysqli_fetch_array($query, MYSQLI_ASSOC);        return$row['total'];        return0;// Lấy danh sách thành viênfunctionget_all_member($limit, $start)    global$conn;    $sql= 'select * from member limit '.(int)$start. ','.(int)$limit;    $query= mysqli_query($conn, $sql);        $result= array();        if($query)            while($row= mysqli_fetch_array($query, MYSQLI_ASSOC))            $result[] = $row;                    return$result; | 
4. Xây dựng trang hiển thị danh sách phân trang
Đây là phân quan trọng nhất của ứng dụng này. Trước tiên bạn tạo file 
index.php và copy nội dung như sau:| 
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 
40 
41 
42 
43 
44 
45 
46 
47 
48 
49 
50 
51 
52 
53 
54 
55 
56 
57 
58 
59 
60 
61 
62 
63 
64 
65 
66 
67 
68 
69 
70 
71 
72 
73 
74 
75 
76 
77 
78 
79 
80 
81 
82 
83 
84 
85 
86 
87 
88 
89 
90 
91 
92 
93 
94 
95 
96 
97 
98 
99 
100 
101 
102 
103 
104 
105 
106 
107 
108 
109 
110 
111 
112 
113 
114 
115 
116 
117 
118 
119 
120 
121 
122 
123 
124 
125 
126 
127 | <?php// Import thư viện data vàorequire_once'database.php';// Load thư viện phân tranginclude_once'pagination.php';// Connect DBconnect();// Phân trang$config= array(    'current_page'=> isset($_GET['page']) ? $_GET['page'] : 1,    'total_record'=> count_all_member(), // tổng số thành viên    'limit'=> 3,    'link_full'=> 'index.php?page=page',    'link_first'=> 'index.php',    'range'=> 9);$paging= newPagination();$paging->init($config);// Lấy limit, start$limit= $paging->get_config('limit');$start= $paging->get_config('start');// Lấy danh sách thành viên$member= get_all_member($limit, $start);// Kiểm tra nếu là ajax request thì trả kết quảif(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest')    die(json_encode(array(        'member'=> $member,        'paging'=> $paging->html()    )));// Disconnect DBdisconnect();?><!DOCTYPE html><html>    <head>        <title></title>        <meta http-equiv="Content-Type"content="text/html; charset=UTF-8">        <style>            lifloat:left; margin: 3px; border: solid 1px gray; list-style: none            apadding: 5px;            spandisplay:inline-block; padding: 0px 3px; background: blue; color:white        </style>         <script language="javascript"src="http://code.jquery.com/jquery-2.0.0.min.js"></script>    </head>    <body>        <div id="content">            <div id="list">                <table border="1"cellspacing="0"cellpadding="5">                    <?php foreach($memberas$item) ?>                    <tr>                        <td>                           <?php echo$item['id']; ?>                         </td>                        <td>                           <?php echo$item['username']; ?>                        </td>                        <td>                           <?php echo$item['email']; ?>                         </td>                        <td>                           <?php echo$item['fullname']; ?>                         </td>                        <td>                           <?php echo$item['phone']; ?>                         </td>                    </tr>                    <?php ?>                </table>            </div>            <div id="paging">                <?php echo$paging->html(); ?>            </div>        </div>         <script language="javascript">             $('#content').on('click','#paging a', function()                              varurl = $(this).attr('href');                                  $.ajax(                     url : url,                     type : 'get',                     dataType : 'json',                     success : function(result)                                              //  kiểm tra kết quả đúng định dạng không                         if(result.hasOwnProperty('member') && result.hasOwnProperty('paging'))                                                      varhtml = '<table border="1" cellspacing="0" cellpadding="5">';                             // lặp qua danh sách thành viên và tạo html                             $.each(result['member'], function(key, item)                                html += '<tr>';                                html += '<td>'+item['id']+'</td>';                                html += '<td>'+item['username']+'</td>';                                html += '<td>'+item['email']+'</td>';                                html += '<td>'+item['fullname']+'</td>';                                html += '<td>'+item['phone']+'</td>';                                html += '</tr>';                             );                                                          html += '</table>';                                                          // Thay đổi nội dung danh sách thành viên                             $('#list').html(html);                                                          // Thay đổi nội dung phân trang                             $('#paging').html(result['paging']);                                                          // Thay đổi URL trên website                             window.history.pushState(path:url,'',url);                                                               );                 returnfalse;             );         </script>    </body></html> | 
Ở file này thì đoạn code php sau có nhiệm vụ là lấy danh sách thành viên và phân trang
| 
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 | // Import thư viện data vàorequire_once'database.php';// Load thư viện phân tranginclude_once'pagination.php';// Connect DBconnect();// Phân trang$config= array(    'current_page'=> isset($_GET['page']) ? $_GET['page'] : 1,    'total_record'=> count_all_member(), // tổng số thành viên    'limit'=> 3,    'link_full'=> 'index.php?page=page',    'link_first'=> 'index.php',    'range'=> 9);$paging= newPagination();$paging->init($config);// Lấy limit, start$limit= $paging->get_config('limit');$start= $paging->get_config('start');// Lấy danh sách thành viên$member= get_all_member($limit, $start);// Kiểm tra nếu là ajax request thì trả kết quảif(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest')    die(json_encode(array(        'member'=> $member,        'paging'=> $paging->html()    )));// Disconnect DBdisconnect(); | 
Nhưng có một điểm bạn cần chú ý đó là dòng:
| 
1 
2 
3 
4 
5 
6 
7 | // Kiểm tra nếu là ajax request thì trả kết quảif(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest')    die(json_encode(array(        'member'=> $member,        'paging'=> $paging->html()    ))); | 
Dòng này rất quan trọng, nó có nhiệm vụ kiểm tra nếu như là request là ajax thì nó sẽ trả về một chuỗi json gồm danh sách thành viên và mã html phân trang, còn không phải thì nó bỏ qua và đoạn mã html bên dưới sẽ hoạt động bình thường. Điều này sẽ giúp cho việc khi ta sử dụng ajax để phân trang và nhấn F5 thì nó vẫn lấy đúng dữ liệu
Đoạn code thứ hai bạn cần chú ý là đoạn xử lý ajax dưới đây:
| 
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 
40 | $('#content').on('click','#paging a', function()    varurl = $(this).attr('href');    $.ajax(        url : url,        type : 'get',        dataType : 'json',        success : function(result)                    //  kiểm tra kết quả đúng định dạng không            if(result.hasOwnProperty('member') && result.hasOwnProperty('paging'))                            varhtml = '<table border="1" cellspacing="0" cellpadding="5">';                // lặp qua danh sách thành viên và tạo html                $.each(result['member'], function(key, item)                   html += '<tr>';                   html += '<td>'+item['id']+'</td>';                   html += '<td>'+item['username']+'</td>';                   html += '<td>'+item['email']+'</td>';                   html += '<td>'+item['fullname']+'</td>';                   html += '<td>'+item['phone']+'</td>';                   html += '</tr>';                );                html += '</table>';                // Thay đổi nội dung danh sách thành viên                $('#list').html(html);                // Thay đổi nội dung phân trang                $('#paging').html(result['paging']);                // Thay đổi URL trên website                window.history.pushState(path:url,'',url);                        );    returnfalse;); | 
Trong đoạn code này tôi đã gắn sự kiện ON cho thẻ a ở dạng global, tức là dù thẻ 
a được thêm sau khi load trang thì đoạn code vẫn hoạt động. Nếu như ban không dùng sự kiện ON này thì đoạn mã phân trang sau khi bạn đổi bằng ajax sẽ không có tác dụng.
Nội dung bên trong file quá rõ ràng rồi nên tôi không giải thích gì thêm
Hình ảnh tham khảo:

5. Lời kết
Như vậy là ta đã làm xong được chức năng phân trang bằng Ajax, đây là một module được sử dụng rất nhiều khi bạn làm các ứng dụng website vì Ajax sẽ giúp cho người dùng cảm thấy website hoạt động mượt mà hơn.
Đây cũng là bài thứ 9 rồi nên tôi hy vọng bạn đã có đủ kiến thúc để tự mình làm ra những ứng dụng khác, tuy nhiên bạn đừng lo vì trong serie mình vẫn còn đề cập đến nhiều kỹ thuật Ajax khác nữa.
Theo code.freetuts.net
 
0 nhận xét: