很多人喜歡Pjax 的魅力,我收集了一個(gè)博客的教程,將他們整合到一起。
這里只做備份用,很推薦去原文看看,尤其是評(píng)論區(qū),說不定會(huì)有意想不到的收獲。
此系列文章更新于2015年2月
- 原文來源:INLOJV
第一部分
教程寫給自己的,所以日后可能有補(bǔ)充。首先這個(gè)pjax的代碼有好幾部分,來自網(wǎng)絡(luò)不同作者,經(jīng)過本人封裝,教程就是按這幾個(gè)部分來進(jìn)行的。這是第一部分,我把自己理解的大致原理說一下,pjax是 pushstate + ajax,分別百度可以得到相關(guān)資料,在此就不贅述了。
Ajax
ajax直白的理解就是請(qǐng)求一個(gè)鏈接所指向的頁面的其中一部分來替換當(dāng)前頁面的一部分,比如我用的wordpress,典型的博客頁面,有頁面頭部、主體部分、側(cè)欄部分、頁面底部四個(gè)主要部分。
ajax請(qǐng)求的過程是如何的呢?比如我現(xiàn)在打開的是頁面A
,頁面A
中有一個(gè)a標(biāo)簽,正常情況下點(diǎn)擊a標(biāo)簽的鏈接會(huì)打開一個(gè)頁面B
,那么整個(gè)頁面A就會(huì)被替換成頁面B。然而,頁面A和頁面B有些結(jié)構(gòu)是完全一樣的,比如頭部,底部,甚至是側(cè)欄,其實(shí)要替換的僅僅是主體部分而已,ajax就提供了這樣一個(gè)功能,它控制你在點(diǎn)擊a標(biāo)簽的鏈接時(shí),只抓取頁面B的主體部分來替換頁面A的主體部分,而頭部、底部、側(cè)欄不用替換(也就不用刷新)。
PushState
以上是最直白的理解,而pushstate則是干嘛的?HTML5里引用了新的API,history.pushState和history.replaceState,就是通過這個(gè)接口做到無刷新改變頁面URL的。因?yàn)橛胊jax替換局部頁面時(shí),瀏覽器的地址是不會(huì)改變的,你替換為頁面B的主體,地址欄的url還是頁面A的,而且點(diǎn)擊瀏覽器的后退或前進(jìn)按鈕地址欄url也是不會(huì)改變的,pushstate的作用則用來改變地址欄url的狀態(tài)。
那么PJAX就是以上兩者的結(jié)合。
開始我們必須對(duì) 被請(qǐng)求的頁面進(jìn)行請(qǐng)求前的處理,這個(gè)處理非常重要,如果把被請(qǐng)求的頁面想象成一張圖片,那么這個(gè)處理就相當(dāng)于對(duì)圖片進(jìn)行剪裁,沒有處理之前,被請(qǐng)求的頁面B是完整的,請(qǐng)求過來就首先要預(yù)讀取一邊頁面B,而其實(shí)我們不必要將整個(gè)頁面都讀取,我們只需要讀取主體部分,所以我們可以把頭部、側(cè)欄和底部都先剪掉,只剩下主體部分,然后再請(qǐng)求過來替換頁面A中的主體部分。
這個(gè)剪裁的方法如下:
在對(duì)應(yīng)的php頁面進(jìn)行
<?php if( $_GET['ajx'] != 'container' ) { ?> //被剪裁掉的部分,比如: //<?php get_header(); ?> //<?php get_sidebar(); ?> //<?php get_footer(); ?> <?php } ?>
這個(gè)方法非常重要,包括評(píng)論分頁也需要這樣的處理,對(duì)pjax的速度是一大影響。了解了這個(gè)其實(shí)剩下的只需要把剩下的代碼超過去就可以了。當(dāng)然,你不剪裁也是可以的,那也可以替換,但那就不算是真正的ajax了。目前大多數(shù)pjax的代碼都不會(huì)有這樣的處理。下面一篇是pjax的核心代碼以及一些說明。
第二部分
原文來源: http://www.inlojv.com/4967.html
處理過程
上篇我們提到了“剪裁”,本篇我們先來實(shí)際體驗(yàn)一下被剪裁掉的頁面是如何的,這方便我們對(duì)接下來的頁面請(qǐng)求過程有一個(gè)感性的認(rèn)識(shí)。
假設(shè)我的index.php首頁是這個(gè)結(jié)構(gòu):頭部、主題、側(cè)欄、底部 四大結(jié)構(gòu)組成。
<?php get_header(); ?> <div id="container"> </div> <?php get_sidebar(); ?> <?php get_footer(); ?>
現(xiàn)在我先把頭部剪掉
<?php if( $_GET['ajx'] != 'container' ) { ?> <?php get_header(); ?> <?php } ?> <div id="container"> </div> <?php get_sidebar(); ?> <?php get_footer(); ?>
可以看到我用第一篇中所說的代碼將頭部包住了,這意味著我把頭部剪掉了。
原本首頁是?http://127.0.0.1/
?,現(xiàn)在我們以這樣的鏈接形式來訪問首頁?http://127.0.0.1/?ajx=container
打開這個(gè)鏈接你會(huì)發(fā)現(xiàn),首頁的頭部不見了,由于頭部加載了css,你首頁的樣式也會(huì)消失,這個(gè)狀態(tài)就是我們想要ajax請(qǐng)求的,我們不需要頭部,把它給剪掉了,接著我們可以用同樣的方法剪掉側(cè)欄和底部,最后就會(huì)只剩下主體部分,如下:
<?php if( $_GET['ajx'] != 'container' ) { ?> <?php get_header(); ?> <?php } ?> <div id="container"> </div> <?php if( $_GET['ajx'] != 'container' ) { ?> <?php get_sidebar(); ?> <?php } ?> <?php if( $_GET['ajx'] != 'container' ) { ?> <?php get_footer(); ?> <?php } ?>
這就是真正需要ajax請(qǐng)求的頁面了。
我們需要把http://127.0.0.1/?ajx=container?
這樣的鏈接傳遞給ajax方法進(jìn)行異步請(qǐng)求,
比如在頁面A?http://127.0.0.1/page-a
?中要請(qǐng)求頁面B,頁面A中的a標(biāo)簽中指向頁面B的鏈接就應(yīng)該是這樣的?http://127.0.0.1/page-b?ajx=container
?,
利用兩個(gè)js函數(shù)來對(duì)點(diǎn)擊的鏈接進(jìn)行處理,加上后面的?=ajx=container
參數(shù),在必要的時(shí)候后再去掉它們。
完整的PJAX代碼
var ajx_content = "#ajx_content"; function rerun() {} $(function() { rerun(); a(); }); function show_loading(e) { if ($("#loading_box").length == 0) { var div = "<div id='loading_box'></div><div id='loading'></div><div id='loading-text'></div></div>"; } if (e === true) { $("body").append(div); } else { $("#loading_box,#loading,#loading-text").fadeOut(400, function() { $(this).remove(); }); } } function body_am(id) { id = isNaN(id) ? $("#" + id).offset().top : id; $("body,html").animate({ scrollTop: id }, 600); return false; } function pluginRerun() { var plugin_scripts = $('script[src*="plugins"]'); plugin_scripts.each(function() { var url = $(this).attr("src"); $.getScript(url); }); } function addUrlPara(url, para) { var strArray = new Array(); strArray = url.split("?"); if (strArray.length == 1) { if (url.indexOf("#") != -1) { strArray = url.split("#"); return strArray[0] + "?" + para + "#" + strArray[1]; } return url + "?" + para; } else { if (url.indexOf(para) != -1) return url; return strArray[0] + "?" + para + "&" + strArray[1]; } } function removeUrlPara(url, para) { var strArray = new Array(); strArray = url.split(para); if (strArray.length == 1) { strArray = url.split("?" + para); return strArray[0]; } else { if (strArray[1].indexOf("&") != -1) { strArray = url.split(para + "&"); return strArray[0] + strArray[1]; } else { strArray = url.split("?" + para); return strArray[0] + strArray[1]; } } } function l() { history.replaceState({ url: window.document.location.href, title: window.document.title, html: $(document).find(ajx_content).html() }, window.document.title, document.location.href); } function a() { window.addEventListener("popstate", function(e) { if (e.state) { document.title = e.state.title; $(ajx_content).html(e.state.html); rerun(); } }); } function ajax(reqUrl, msg, data) { if (msg == "pagelink" || msg == "search") { show_loading(true); $(ajx_content).fadeTo("normal", 0); $("body,html").animate({ scrollTop: $("body").offset().top }, 810); var paraUrl = addUrlPara(reqUrl, "ajx=container"); } else if (msg == "comtpagenav") { to_anchor("#post-comment-list", 0); $("#comment_list").fadeTo(500, .2, function() { $("#comment_list").css("position", "relative"); }); reqUrl = removeUrlPara(reqUrl, "ajx=container"); paraUrl = addUrlPara(reqUrl, "ajx=comts"); } $.ajax({ url: paraUrl, data: data, beforeSend: function() { l(); }, success: function(data) { if (msg == "pagelink" || msg == "search") { $(ajx_content).replaceWith($(data).filter(ajx_content)); $(ajx_content).fadeTo(500, 1, function() { rerun(); }); show_loading(false); } else if (msg == "comtpagenav") { var content = $(data).find("#comment_list").html(); $("#comment_list").animate({ opacity: 0, top: 35 }, 200, function() { $("#comment_list").html(content); $("#comment_list").animate({ opacity: 1, top: 0 }, 400, function() { $("#comment_list").css("position", "inherit"); }); rerun(); }); } document.title = $(data).filter("title").text(); reqUrl = removeUrlPara(reqUrl, "ajx=comts"); var state = { url: reqUrl, title: $(data).filter("title").text(), html: $(data).filter(ajx_content).html() }; window.history.pushState(state, $(data).filter("title").text(), reqUrl); }, complete: function() {}, timeout: 5e3, error: function(request) { if (msg == msg == "pagelink" || msg == "search") { show_loading(false); location.href = reqUrl; } else if (msg == "comtpagenav") { $("#comment_list").fadeTo("normal", 1); $("#comt_svg").css("display", "none"); $("#comments_paginate").css("display", "block"); } else { location.href = reqUrl; } } }); } function check_x(url) { var url_string = new String(" , comment-page-, #respond, #comment, javascript:, oauth2, .jpg, .gif, .png"); var url_x = url_string.split(", "); for (var i in url_x) { if (url.indexOf(url_x[i]) >= 0) { return true; } } return false; } $("body").on("click", "a[target!=_blank]:not(.noajx)", function() { url = $(this).attr("href"); if (check_x(url) == true) return; ajax(url, "pagelink"); return false; }); $("body").on("submit", "#search .s-form", function() { ajax(this.action + '?=' + $(this).find("#s").val(), 'search', $(this).serialize()); return false; }); $("body").on("click", "#comments_paginate a", function() { ajax($(this).attr("href"), "comtpagenav"); return false; });
核心就是ajax(reqUrl, msg, data)函數(shù)了,還有兩個(gè)函數(shù)需要說明一下
1、check_x(url)函數(shù) —— 這是檢查a標(biāo)簽的鏈接中是否有需要排除的字符,有時(shí)候某些a標(biāo)簽是不需要ajax請(qǐng)求的,比如/wp-login.php,圖片鏈接帶有.jpg、.gif、.png 等等,都不需要ajax請(qǐng)求,我們得把它們排除掉,加入到check_x(url)內(nèi)的排除列表內(nèi)。
2、rerun()函數(shù) —— 這個(gè)函數(shù)方便我們對(duì)其他js腳本進(jìn)行重新加載,相當(dāng)于一個(gè)回調(diào)函數(shù),比如有的站用了多說評(píng)論系統(tǒng),ajax請(qǐng)求時(shí)是不會(huì)請(qǐng)求css和js的,只抓取html結(jié)構(gòu),所以ajax加載后多說需要的js就不會(huì)一起加過來,這時(shí)候就需要把多說的js放進(jìn)rerun()函數(shù)進(jìn)行重新加載。
好了,PJAX教程就介紹到這里,適合有一定js基礎(chǔ)的朋友看,如果連js都不懂,那只能靠百度了。
第三部分
原文來源: http://www.inlojv.com/5011.html
全站pjax教程一和二已經(jīng)將重點(diǎn)與核心代碼呈現(xiàn)過了,還有一些執(zhí)行上的問題在此補(bǔ)充一下
1、并不是所有的pjax代碼都相同?
網(wǎng)上有很多所謂的全站ajax代碼,其實(shí)僅僅是頁面ajax,全站還要兼顧很多東西,搜索、評(píng)論、重載回調(diào)等等,另外有一些pushstate的使用也不相同,有的pjax后退是沒有緩存的,這樣這些代碼的前進(jìn)和后退,就會(huì)重新請(qǐng)求一次push進(jìn)去的歷史鏈接,所以你會(huì)發(fā)現(xiàn)有的后退是重新執(zhí)行一遍代碼會(huì)有l(wèi)oading效果,而有的不是,是很干脆地切換回去。教程[二]提供的代碼屬于后者。
2、ajax替換頁面容器所用的函數(shù)不同
比如教程[二]中ajax執(zhí)行成功后有這么一句$(ajx_content).replaceWith($(data).filter(ajx_content));
,有一些代碼則不同,有可能是這樣的:$(ajx_content).html($(data).filter(ajx_content).html());
,還有的用的不是filter()
而是find()
?。這兩個(gè)函數(shù)是有區(qū)別的,一個(gè)是針對(duì)同級(jí)元素,一個(gè)是針對(duì)子元素;當(dāng)對(duì)請(qǐng)求頁面進(jìn)行剪裁時(shí),容器可能暴露在最外面,此時(shí)就需要用filter;當(dāng)沒有剪裁時(shí)就只能用find。
3、“剪裁”的方式
有的小伙伴可能對(duì)“剪裁”并不熟悉,只是生搬硬套,這也導(dǎo)致了后面需要做很多工作,比如:ajax請(qǐng)求后瀏覽器的頁面標(biāo)題需要通過修改頁面結(jié)構(gòu)來組合獲取。其實(shí)剪裁的時(shí)候保留title標(biāo)簽,title就可以直接用document.title = $(data).filter("title").text();
來獲取了。
4、重載回調(diào)
這個(gè)算是個(gè)很大的難題,因?yàn)榻鉀Q這樣的問題其實(shí)相當(dāng)于把jquery的基礎(chǔ)給學(xué)了一遍,我不是專業(yè)的,現(xiàn)在也還不是很明白這些代碼的執(zhí)行到底應(yīng)該怎么描述。ajax請(qǐng)求不會(huì)請(qǐng)求到容器之外的腳本文件,除非你把js寫在容器之內(nèi),比如之前我試過把百度分享代碼寫在footer.php
,但ajax始終不加載,只能把它寫在single.php
的容器里面。 還有很多插件會(huì)加載額外的js腳本,比如多說評(píng)論、某蝦米音樂插件、圖片燈箱、代碼高亮 等等,它們?cè)赼jax請(qǐng)求過來后都會(huì)失效,這時(shí)候就需要為ajax提供一個(gè)回調(diào)函數(shù),方便在ajax過程執(zhí)行完畢之后重新加載這些模塊的js腳本。
有的插件提供了執(zhí)行函數(shù),比如slimbox燈箱,會(huì)有一個(gè)slimbox()
函數(shù);Google prettify語法高亮,會(huì)有一個(gè)prettify()
函數(shù),這些都可以在ajax回調(diào)時(shí)放進(jìn)去重新加載,使得加載后這些功能不失效。
有的插件則不會(huì)提供這種函數(shù),比如多說,它只有一整個(gè)js腳本,加載方式可以看這里兩種方式執(zhí)行外部插件掛載的js腳本
下面我就以最典型的Willin Kan版的ajax評(píng)論來舉個(gè)例子,因?yàn)楹芏嘈』锇橥瓿身撁鎍jax之后,評(píng)論ajax總是失效,下面先看看這個(gè)評(píng)論ajax代碼:
var theme_dir = $('head #default-css').attr('href').split('style.css')[0]; // 主題路徑 ,以style.css分割href,第一段就是主題路徑 /** * WordPress jQuery-Ajax-Comments v1.3 by Willin Kan. * URI: http://kan.willin.org/?p=1271 */ ??? var commentform = '#comment_form', // ××× form表單id ??? comment = 'c_tarea', // ××× textarea 的id 不帶# ??? commentlist = 'comment-list',? // ××× 評(píng)論列表ul或ol的class,不帶點(diǎn) ??? respond = '#respond',? // ××× 評(píng)論插入位置,插入在這個(gè)id之前 ??? homeUrl = document.location.href.match(/http:\/\/([^\/]+)\//i)[0], // 主頁地址,用于下面的提交函數(shù) ??? txt1 = '<div id="loading" class="text-info"> 正在提交, 請(qǐng)稍候...</div>', ??? txt2 = '<div id="error">#</div>', ??? txt3 = '"><div class="text-success"> OK !', ??? edt1 = ' 刷新頁面之前您可以<a rel="nofollow" class="comment-reply-link" href="#edit" onclick=\'return addComment.moveForm("', ??? edt2 = ')\'>再次編輯評(píng)論</a></div>', ??? cancel_edit = '取消編輯', ??? edit, ??? num = 1, ??? $comments = $('#response'), // 評(píng)論數(shù) ??? $cancel = $('#cancel-comment-reply-link'), ??? cancel_text = $cancel.text(), ??? $submit = $(commentform+ '#submit'); ??? $submit.attr('disabled', false), ??? $body = (window.opera) ? (document.compatMode == "CSS1Compat" ? $('html') : $('body')) : $('html,body'), ??? comm_array = []; ??? comm_array.push(''); ??? $('#'+comment).after(txt1 + txt2); // ××× textarea的id或class ??? $('#loading').hide(); ??? $('#error').hide(); ??? // 評(píng)論提交 // $(commentform).submit(? // 非動(dòng)態(tài)綁定 $(document).on("submit", commentform, //動(dòng)態(tài)綁定 ??? function() { ??????? if (edit) $('#'+comment).after('<input type="text" name="edit_id" id="edit_id" value="' + edit + '" style="display:none;" />'); ??????? $submit.attr('disabled', true).fadeTo('slow', 0.5); ??????? $('#loading').slideDown(); ??????? $.ajax({ ??????????? url: theme_dir + '/comt-ajax.php', ??????????? data: $(this).serialize() , ??????????? type: $(this).attr('method'), ??????????? error: function(request) { ??????????????? $('#loading').slideUp(); ??????????????? $("#error").slideDown().html(request.responseText); ??????????????? setTimeout(function() { ??????????????????? $submit.attr('disabled', false).fadeTo('slow', 1); ??????????????????? $('#error').slideUp(); ??????????????? }, ??????????????? 3000); ??????????? }, ??????????? success: function(data) { ??????????????? $('#loading').hide(); ??????????????? comm_array.push($('#'+comment).val()); ??????????????? $('textarea').each(function() { ??????????????????? this.value = '' ??????????????? }); ??????????????? var t = addComment, ??????????????? cancel = t.I('cancel-comment-reply-link'), ??????????????? temp = t.I('wp-temp-form-div'), ??????????????? respond = t.I(t.respondId), ??????????????? post = t.I('comment_post_ID').value, ??????????????? parent = t.I('comment_parent').value; ?? ??? ??? ??? ?// 增加評(píng)論數(shù) ??????????????? if (!edit && $comments.length) { ??????????????????? n = parseInt($comments.text().match(/\d+/)); // 匹配數(shù)字 ??????????????????? $comments.text($comments.text().replace(n, n + 1)); ??????????????? } ?? ??? ??? ??? ?// 評(píng)論顯示 ??????????????? new_htm = '" id="new_comm_' + num + '"></'; ??????????????? new_htm = (parent == '0') ? ('\n<ol style="clear:both;" class="'+commentlist+'" ' +? new_htm + 'ol>') : ('\n<ul class="children' + new_htm + 'ul>'); ??????????????? ok_htm = '\n<div class="ajax-notice" id="success_' + num + txt3; ??????????????? div_ = (document.body.innerHTML.indexOf('div-comment-') == -1) ? '': ((document.body.innerHTML.indexOf('li-comment-') == -1) ? 'div-': ''); ??????????????? ok_htm = ok_htm.concat(edt1, div_, 'comment-', parent, '", "', parent, '", "respond", "', post, '", ', num, edt2); ??????????????? ok_htm += '</span><span></span>\n'; ??????????????? ok_htm += '</div>\n'; ?? ??? ??? ??? ?if($('#comments .comment-list').length>0){ // ××××××××××××××××××××非嵌套評(píng)論時(shí),新評(píng)論顯示插入的位置(按自己的喜好修改顯示位置) ?? ??? ??? ??? ??? ?$('#comments .comment-list').before(new_htm); ?? ??? ??? ??? ?} else{ ?? ??? ??? ??? ??? ?$('#respond').after(new_htm); ?? ??? ??? ??? ?} ??????????????? $('#new_comm_' + num).append(data); ??????????????? $('#new_comm_' + num + ' li').append(ok_htm); ??????????????? $body.animate({scrollTop: $('#new_comm_' + num).offset().top - 200},900); ??????????????? countdown(); ??????????????? num++; ??????????????? edit = ''; ??????????????? $('*').remove('#edit_id'); ??????????????? cancel.style.display = 'none'; ??????????????? cancel.onclick = null; ??????????????? t.I('comment_parent').value = '0'; ??????????????? if (temp && respond) { ??????????????????? temp.parentNode.insertBefore(respond, temp); ??????????????????? temp.parentNode.removeChild(temp) ??????????????? } ??????????? } ??????? }); ??????? return false; ??? }); ??? addComment = { ??????? moveForm: function(commId, parentId, respondId, postId, num) { ??????????? var t = this, ??????????? div, ??????????? comm = t.I(commId), ??????????? respond = t.I(respondId), ??????????? cancel = t.I('cancel-comment-reply-link'), ??????????? parent = t.I('comment_parent'), ??????????? post = t.I('comment_post_ID'); ??????????? if (edit) exit_prev_edit(); ??????????? num ? (t.I(comment).value = comm_array[num], edit = t.I('new_comm_' + num).innerHTML.match(/(comment-)(\d+)/)[2], $new_sucs = $('#success_' + num), $new_sucs.hide(), $new_comm = $('#new_comm_' + num), $new_comm.hide(), $cancel.text(cancel_edit)) : $cancel.text(cancel_text); ??????????? t.respondId = respondId; ??????????? postId = postId || false; ??????????? if (!t.I('wp-temp-form-div')) { ??????????????? div = document.createElement('div'); ??????????????? div.id = 'wp-temp-form-div'; ??????????????? div.style.display = 'none'; ??????????????? respond.parentNode.insertBefore(div, respond) ??????????? } ! comm ? (temp = t.I('wp-temp-form-div'), t.I('comment_parent').value = '0', temp.parentNode.insertBefore(respond, temp), temp.parentNode.removeChild(temp)) : comm.parentNode.insertBefore(respond, comm.nextSibling); ??????????? $body.animate({scrollTop: $('#respond').offset().top - 180},400); ??????????? if (post && postId) post.value = postId; ??????????? parent.value = parentId; ??????????? cancel.style.display = ''; ??????????? cancel.onclick = function() { ??????????????? if (edit) exit_prev_edit(); ??????????????? var t = addComment, ??????????????? temp = t.I('wp-temp-form-div'), ??????????????? respond = t.I(t.respondId); ??????????????? t.I('comment_parent').value = '0'; ??????????????? if (temp && respond) { ??????????????????? temp.parentNode.insertBefore(respond, temp); ??????????????????? temp.parentNode.removeChild(temp); ??????????????? } ??????????????? this.style.display = 'none'; ??????????????? this.onclick = null; ??????????????? return false; ??????????? }; ??????????? try { ??????????????? t.I(comment).focus(); ??????????? } ???????????? catch(e) {} ??????????? return false; ??????? }, ??????? I: function(e) { ??????????? return document.getElementById(e); ??????? } ??? }; ??? function exit_prev_edit() { ??????? $new_comm.show(); ??????? $new_sucs.show(); ??????? $('textarea').each(function() { ??????????? this.value = '' ??????? }); ??????? edit = ''; ??? } ??? var wait = 15, ??? submit_val = $submit.val(); ??? function countdown() { ??????? if (wait > 0) { ??????????? $submit.val(wait); ??????????? wait--; ??????????? setTimeout(countdown, 1000); ??????? } else { ??????????? $submit.val(submit_val).attr('disabled', false).fadeTo('slow', 1); ??????????? wait = 15; ??????? } ??? } ??? function grin(a) { ??????? var b; ??????? a = " " + a + " "; ??????? if (document.getElementById(comment) && document.getElementById(comment).type == "textarea") { ??????????? b = document.getElementById(comment) ??????? } else { ??????????? return false ??????? } ??????? if (document.selection) { ??????????? b.focus(); ??????????? sel = document.selection.createRange(); ??????????? sel.text = a; ??????????? b.focus() ??????? } else if (b.selectionStart || b.selectionStart == "0") { ??????????? var c = b.selectionStart; ??????????? var d = b.selectionEnd; ??????????? var e = d; ??????????? b.value = b.value.substring(0, c) + a + b.value.substring(d, b.value.length); ??????????? e += a.length; ??????????? b.focus(); ??????????? b.selectionStart = e; ??????????? b.selectionEnd = e ??????? } else { ??????????? b.value += a; ??????????? b.focus() ??????? } ??? }
上面的代碼有些選擇器是針對(duì)我自己的主題的,所以僅供參考,這個(gè)不重要。重點(diǎn)是當(dāng)各種變量賦值完畢后,那一句$(document).on("submit", commentform,?
,這個(gè)是關(guān)鍵,意思是這個(gè)on方法把submit事件冒泡綁定到了document上,這個(gè)時(shí)候submit事件里面的所有動(dòng)作就不會(huì)受到頁面ajax加載的影響。你可以注意到上面有一句$('#'+comment).after(txt1 + txt2);
?這個(gè)是在提交評(píng)論時(shí)顯示的loading提示文字,它沒有被包含在submit事件里面,所以它是受到頁面ajax加載影響的!也就是說:頁面ajax加載后,你點(diǎn)擊評(píng)論提交按鈕,此時(shí)不會(huì)顯示loading提示文字,但卻能進(jìn)行ajax評(píng)論提交。如果你把這段提示放進(jìn)submit里面去,那么整個(gè)評(píng)論ajax就和頁面ajax完全相互獨(dú)立了,它們可以互不影響,完全兼容。
另外,你可能注意到在$(document).on("submit", commentform,?
上一句注釋是這樣的$(commentform).submit(
,這表示你沒有用on方法將submit冒泡到document之上,此時(shí)這就和上面那個(gè)loading提示文字是一樣的,整個(gè)評(píng)論ajax就會(huì)受到頁面ajax的影響。那么如果不用on方法,應(yīng)該怎么兼容?看下面的代碼:
var theme_dir = $('head #default-css').attr('href').split('style.css')[0]; // 主題路徑 ,以style.css分割href,第一段就是主題路徑 /** ?* WordPress jQuery-Ajax-Comments v1.3 by Willin Kan. ?* URI: http://kan.willin.org/?p=1271 ?*/ $(document).ready(function() { ??? ajaxComt(); }); function ajaxComt(){ ??? var commentform = '#comment_form', // ××× form表單id ??? comment = 'c_tarea', // ××× textarea 的id 不帶# ??? commentlist = 'comment-list',? // ××× 評(píng)論列表ul或ol的class,不帶點(diǎn) ??? respond = '#respond',? // ××× 評(píng)論插入位置,插入在這個(gè)id之前 ??? homeUrl = document.location.href.match(/http:\/\/([^\/]+)\//i)[0], // 主頁地址,用于下面的提交函數(shù) ??? txt1 = '<div id="loading" class="text-info"> 正在提交, 請(qǐng)稍候...</div>', ??? txt2 = '<div id="error">#</div>', ??? txt3 = '"><div class="text-success"> OK !', ??? edt1 = ' 刷新頁面之前您可以<a rel="nofollow" class="comment-reply-link" href="#edit" onclick=\'return addComment.moveForm("', ??? edt2 = ')\'>再次編輯評(píng)論</a></div>', ??? cancel_edit = '取消編輯', ??? edit, ??? num = 1, ??? $comments = $('#response'), // 評(píng)論數(shù) ??? $cancel = $('#cancel-comment-reply-link'), ??? cancel_text = $cancel.text(), ??? $submit = $(commentform+ '#submit'); ??? $submit.attr('disabled', false), ??? $body = (window.opera) ? (document.compatMode == "CSS1Compat" ? $('html') : $('body')) : $('html,body'), ??? comm_array = []; ??? comm_array.push(''); ??? $('#'+comment).after(txt1 + txt2); // ××× textarea的id或class ??? $('#loading').hide(); ??? $('#error').hide(); ??? // 評(píng)論提交 $(commentform).submit(? // 非動(dòng)態(tài)綁定 // $(document).on("submit", commentform, // 動(dòng)態(tài)綁定 ??? function() { ??????? if (edit) $('#'+comment).after('<input type="text" name="edit_id" id="edit_id" value="' + edit + '" style="display:none;" />'); ??????? $submit.attr('disabled', true).fadeTo('slow', 0.5); ??????? $('#loading').slideDown(); ??????? $.ajax({ ??????????? url: theme_dir + '/comt-ajax.php', ??????????? data: $(this).serialize() , ??????????? type: $(this).attr('method'), ??????????? error: function(request) { ??????????????? $('#loading').slideUp(); ??????????????? $("#error").slideDown().html(request.responseText); ??????????????? setTimeout(function() { ??????????????????? $submit.attr('disabled', false).fadeTo('slow', 1); ??????????????????? $('#error').slideUp(); ??????????????? }, ??????????????? 3000); ??????????? }, ??????????? success: function(data) { ??????????????? $('#loading').hide(); ??????????????? comm_array.push($('#'+comment).val()); ??????????????? $('textarea').each(function() { ??????????????????? this.value = '' ??????????????? }); ??????????????? var t = addComment, ??????????????? cancel = t.I('cancel-comment-reply-link'), ??????????????? temp = t.I('wp-temp-form-div'), ??????????????? respond = t.I(t.respondId), ??????????????? post = t.I('comment_post_ID').value, ??????????????? parent = t.I('comment_parent').value; ?? ??? ??? ??? ?// 增加評(píng)論數(shù) ??????????????? if (!edit && $comments.length) { ??????????????????? n = parseInt($comments.text().match(/\d+/)); // 匹配數(shù)字 ??????????????????? $comments.text($comments.text().replace(n, n + 1)); ??????????????? } ?? ??? ??? ??? ?// 評(píng)論顯示 ??????????????? new_htm = '" id="new_comm_' + num + '"></'; ??????????????? new_htm = (parent == '0') ? ('\n<ol style="clear:both;" class="'+commentlist+'" ' +? new_htm + 'ol>') : ('\n<ul class="children' + new_htm + 'ul>'); ??????????????? ok_htm = '\n<div class="ajax-notice" id="success_' + num + txt3; ??????????????? div_ = (document.body.innerHTML.indexOf('div-comment-') == -1) ? '': ((document.body.innerHTML.indexOf('li-comment-') == -1) ? 'div-': ''); ??????????????? ok_htm = ok_htm.concat(edt1, div_, 'comment-', parent, '", "', parent, '", "respond", "', post, '", ', num, edt2); ??????????????? ok_htm += '</span><span></span>\n'; ??????????????? ok_htm += '</div>\n'; ?? ??? ??? ??? ?if($('#comments .comment-list').length>0){ // ××××××××××××××××××××非嵌套評(píng)論時(shí),新評(píng)論顯示插入的位置(按自己的喜好修改顯示位置) ?? ??? ??? ??? ??? ?$('#comments .comment-list').before(new_htm); ?? ??? ??? ??? ?} else{ ?? ??? ??? ??? ??? ?$('#respond').after(new_htm); ?? ??? ??? ??? ?} ??????????????? $('#new_comm_' + num).append(data); ??????????????? $('#new_comm_' + num + ' li').append(ok_htm); ??????????????? $body.animate({scrollTop: $('#new_comm_' + num).offset().top - 200},900); ??????????????? countdown(); ??????????????? num++; ??????????????? edit = ''; ??????????????? $('*').remove('#edit_id'); ??????????????? cancel.style.display = 'none'; ??????????????? cancel.onclick = null; ??????????????? t.I('comment_parent').value = '0'; ??????????????? if (temp && respond) { ??????????????????? temp.parentNode.insertBefore(respond, temp); ??????????????????? temp.parentNode.removeChild(temp) ??????????????? } ??????????? } ??????? }); ??????? return false; ??? }); ??? addComment = { ??????? moveForm: function(commId, parentId, respondId, postId, num) { ??????????? var t = this, ??????????? div, ??????????? comm = t.I(commId), ??????????? respond = t.I(respondId), ??????????? cancel = t.I('cancel-comment-reply-link'), ??????????? parent = t.I('comment_parent'), ??????????? post = t.I('comment_post_ID'); ??????????? if (edit) exit_prev_edit(); ??????????? num ? (t.I(comment).value = comm_array[num], edit = t.I('new_comm_' + num).innerHTML.match(/(comment-)(\d+)/)[2], $new_sucs = $('#success_' + num), $new_sucs.hide(), $new_comm = $('#new_comm_' + num), $new_comm.hide(), $cancel.text(cancel_edit)) : $cancel.text(cancel_text); ??????????? t.respondId = respondId; ??????????? postId = postId || false; ??????????? if (!t.I('wp-temp-form-div')) { ??????????????? div = document.createElement('div'); ??????????????? div.id = 'wp-temp-form-div'; ??????????????? div.style.display = 'none'; ??????????????? respond.parentNode.insertBefore(div, respond) ??????????? } ! comm ? (temp = t.I('wp-temp-form-div'), t.I('comment_parent').value = '0', temp.parentNode.insertBefore(respond, temp), temp.parentNode.removeChild(temp)) : comm.parentNode.insertBefore(respond, comm.nextSibling); ??????????? $body.animate({scrollTop: $('#respond').offset().top - 180},400); ??????????? if (post && postId) post.value = postId; ??????????? parent.value = parentId; ??????????? cancel.style.display = ''; ??????????? cancel.onclick = function() { ??????????????? if (edit) exit_prev_edit(); ??????????????? var t = addComment, ??????????????? temp = t.I('wp-temp-form-div'), ??????????????? respond = t.I(t.respondId); ??????????????? t.I('comment_parent').value = '0'; ??????????????? if (temp && respond) { ??????????????????? temp.parentNode.insertBefore(respond, temp); ??????????????????? temp.parentNode.removeChild(temp); ??????????????? } ??????????????? this.style.display = 'none'; ??????????????? this.onclick = null; ??????????????? return false; ??????????? }; ??????????? try { ??????????????? t.I(comment).focus(); ??????????? } ???????????? catch(e) {} ??????????? return false; ??????? }, ??????? I: function(e) { ??????????? return document.getElementById(e); ??????? } ??? }; ??? function exit_prev_edit() { ??????? $new_comm.show(); ??????? $new_sucs.show(); ??????? $('textarea').each(function() { ??????????? this.value = '' ??????? }); ??????? edit = ''; ??? } ??? var wait = 15, ??? submit_val = $submit.val(); ??? function countdown() { ??????? if (wait > 0) { ??????????? $submit.val(wait); ??????????? wait--; ??????????? setTimeout(countdown, 1000); ??????? } else { ??????????? $submit.val(submit_val).attr('disabled', false).fadeTo('slow', 1); ??????????? wait = 15; ??????? } ??? } ??? function grin(a) { ??????? var b; ??????? a = " " + a + " "; ??????? if (document.getElementById(comment) && document.getElementById(comment).type == "textarea") { ??????????? b = document.getElementById(comment) ??????? } else { ??????????? return false ??????? } ??????? if (document.selection) { ??????????? b.focus(); ??????????? sel = document.selection.createRange(); ??????????? sel.text = a; ??????????? b.focus() ??????? } else if (b.selectionStart || b.selectionStart == "0") { ??????????? var c = b.selectionStart; ??????????? var d = b.selectionEnd; ??????????? var e = d; ??????????? b.value = b.value.substring(0, c) + a + b.value.substring(d, b.value.length); ??????????? e += a.length; ??????????? b.focus(); ??????????? b.selectionStart = e; ??????????? b.selectionEnd = e ??????? } else { ??????????? b.value += a; ??????????? b.focus() ??????? } ??? } } // end Ajax評(píng)論
代碼的核心內(nèi)容和前面是一樣的,只不過我將整段評(píng)論代碼寫成了一個(gè)ajaxComt()
函數(shù),也就是將代碼用function ajaxComt(){...}
包住,可以看到,此時(shí)submit事件并非動(dòng)態(tài)綁定,只要這樣
$(document).ready(function() { ??? ajaxComt(); });
就和原來不用函數(shù)包住的時(shí)候沒什么區(qū)別了。那么這個(gè)ajaxComt()
函數(shù),就是我們放在頁面ajax回調(diào)里面重新加載的東西。ajax方法里面會(huì)有幾個(gè)執(zhí)行先后的參數(shù),beforeSend、success、complete ,我們可以把它放在complete里面:
complete: function() { // 頁面ajax完成后加載 ?? ?ajaxComt(); }
這樣就和動(dòng)態(tài)綁定沒什么區(qū)別了。說法的區(qū)別從我個(gè)人角度來看就是:前者屬于冒泡綁定,頁面ajax和評(píng)論ajax是互不影響的;后者屬于先后執(zhí)行,頁面ajax先執(zhí)行完畢再執(zhí)行一遍評(píng)論ajax 。
第四部分
原文來源: http://www.inlojv.com/5026.html
教程進(jìn)行到第四已然顯得有些羅嗦了,本篇主要是本人記錄自己遇到的一些細(xì)節(jié)問題和網(wǎng)上的各種pjax代碼版本,權(quán)當(dāng)補(bǔ)充篇來看吧。
搜索ajax表單序列化
最近想把主題換成經(jīng)典的twentytwelve
,也試著把它pjax化,其中遇到一個(gè)搜索ajax的問題,按理說其他主題能實(shí)現(xiàn),沒問題,這個(gè)也應(yīng)該可以,但我把代碼搬上去之后,發(fā)現(xiàn)搜索ajax返回沒有返回正確的頁面,這里首先要說的就是WordPress正常情況下的搜索請(qǐng)求鏈接應(yīng)該是這樣的http://127.0.0.1/?=xxx
,xxx表示你搜索的關(guān)鍵字,而由于有后端的處理(也就是教程[一]中的“剪裁”),發(fā)送給ajax的請(qǐng)求鏈接一般是類似?ajx=container
這樣的后綴(其他版本有可能是這樣?action=pjax
),那么搜索ajax的請(qǐng)求鏈接能不能這樣http://127.0.0.1/?=xxx?ajx=container
?答案是不能。只能把?號(hào)換成&號(hào),變成這樣http://127.0.0.1/?=xxx&ajx=container
,所以在搜索ajax的請(qǐng)求鏈接上要加一些判斷,如果是搜索,那么得改一改鏈接附加的參數(shù)形式。
以上只是一個(gè)細(xì)節(jié),我在修改twentytwelve時(shí)沒有返回應(yīng)有的頁面,把搜索鏈接http://127.0.0.1/?=xxx&ajx=container
直接輸入到瀏覽器打開,發(fā)現(xiàn)也不是搜索結(jié)果頁面,找了半天才發(fā)現(xiàn)是form表單序列化的問題,$.ajax()
方法有幾個(gè)參數(shù),其中我們要把序列化的表單信息放入到ajax方法的data參數(shù)內(nèi)。賦值?data = $('#searchform').serialize();
?。其中#searchform是form表單的id

以上只是一個(gè)例子,條件判斷可以按自己的思路來做改變。如此一來,搜索ajax就沒有問題了。