全站pjax教程一和二已经将重点与核心代码呈现过了,还有一些执行上的问题在此补充一下

1、并不是所有的pjax代码都相同?

网上有很多所谓的全站ajax代码,其实仅仅是页面ajax,全站还要兼顾很多东西,搜索、评论、重载回调等等,另外有一些pushstate的使用也不相同,有的pjax后退是没有缓存的,这样这些代码的前进和后退,就会重新请求一次push进去的历史链接,所以你会发现有的后退是重新执行一遍代码会有loading效果,而有的不是,是很干脆地切换回去。教程[二]提供的代码属于后者。

2、ajax替换页面容器所用的函数不同

比如教程[二]中ajax执行成功后有这么一句$(ajx_content).replaceWith($(data).filter(ajx_content));,有一些代码则不同,有可能是这样的:$(ajx_content).html($(data).filter(ajx_content).html());,还有的用的不是filter()而是find() 。这两个函数是有区别的,一个是针对同级元素,一个是针对子元素;当对请求页面进行剪裁时,容器可能暴露在最外面,此时就需要用filter;当没有剪裁时就只能用find。

3、“剪裁”的方式

有的小伙伴可能对“剪裁”并不熟悉,只是生搬硬套,这也导致了后面需要做很多工作,比如:ajax请求后浏览器的页面标题需要通过修改页面结构来组合获取。其实剪裁的时候保留title标签,title就可以直接用document.title = $(data).filter("title").text();来获取了。

4、重载回调

这个算是个很大的难题,因为解决这样的问题其实相当于把jquery的基础给学了一遍,我不是专业的,现在也还不是很明白这些代码的执行到底应该怎么描述。ajax请求不会请求到容器之外的脚本文件,除非你把js写在容器之内,比如之前我试过把百度分享代码写在footer.php,但ajax始终不加载,只能把它写在single.php的容器里面。 还有很多插件会加载额外的js脚本,比如多说评论、某虾米音乐插件、图片灯箱、代码高亮 等等,它们在ajax请求过来后都会失效,这时候就需要为ajax提供一个回调函数,方便在ajax过程执行完毕之后重新加载这些模块的js脚本。


有的插件提供了执行函数,比如slimbox灯箱,会有一个slimbox()函数;Google prettify语法高亮,会有一个prettify()函数,这些都可以在ajax回调时放进去重新加载,使得加载后这些功能不失效。
有的插件则不会提供这种函数,比如多说,它只有一整个js脚本,加载方式可以看这里两种方式执行外部插件挂载的js脚本


下面我就以最典型的Willin Kan版的ajax评论来举个例子,因为很多小伙伴完成页面ajax之后,评论ajax总是失效,下面先看看这个评论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',  // ××× 评论列表ul或ol的class,不带点
    respond = '#respond',  // ××× 评论插入位置,插入在这个id之前
    homeUrl = document.location.href.match(/http:\/\/([^\/]+)\//i)[0], // 主页地址,用于下面的提交函数
    txt1 = '<div id="loading" class="text-info"> 正在提交, 请稍候...</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 = ')\'>再次编辑评论</a></div>',
    cancel_edit = '取消编辑',
    edit,
    num = 1,
    $comments = $('#response'), // 评论数
    $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();
    // 评论提交
// $(commentform).submit(  // 非动态绑定
$(document).on("submit", commentform, //动态绑定
    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;
                // 增加评论数
                if (!edit && $comments.length) { 
                    n = parseInt($comments.text().match(/\d+/)); // 匹配数字
                    $comments.text($comments.text().replace(n, n + 1));
                }
                // 评论显示
                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){ // ××××××××××××××××××××非嵌套评论时,新评论显示插入的位置(按自己的喜好修改显示位置)
                    $('#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()
        }
    }

上面的代码有些选择器是针对我自己的主题的,所以仅供参考,这个不重要。重点是当各种变量赋值完毕后,那一句$(document).on("submit", commentform, ,这个是关键,意思是这个on方法把submit事件冒泡绑定到了document上,这个时候submit事件里面的所有动作就不会受到页面ajax加载的影响。你可以注意到上面有一句$('#'+comment).after(txt1 + txt2); 这个是在提交评论时显示的loading提示文字,它没有被包含在submit事件里面,所以它是受到页面ajax加载影响的!也就是说:页面ajax加载后,你点击评论提交按钮,此时不会显示loading提示文字,但却能进行ajax评论提交。如果你把这段提示放进submit里面去,那么整个评论ajax就和页面ajax完全相互独立了,它们可以互不影响,完全兼容。


另外,你可能注意到在$(document).on("submit", commentform, 上一句注释是这样的$(commentform).submit(,这表示你没有用on方法将submit冒泡到document之上,此时这就和上面那个loading提示文字是一样的,整个评论ajax就会受到页面ajax的影响。那么如果不用on方法,应该怎么兼容?看下面的代码:

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',  // ××× 评论列表ul或ol的class,不带点
    respond = '#respond',  // ××× 评论插入位置,插入在这个id之前
    homeUrl = document.location.href.match(/http:\/\/([^\/]+)\//i)[0], // 主页地址,用于下面的提交函数
    txt1 = '<div id="loading" class="text-info"> 正在提交, 请稍候...</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 = ')\'>再次编辑评论</a></div>',
    cancel_edit = '取消编辑',
    edit,
    num = 1,
    $comments = $('#response'), // 评论数
    $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();
    // 评论提交
$(commentform).submit(  // 非动态绑定
// $(document).on("submit", commentform, // 动态绑定
    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;
                // 增加评论数
                if (!edit && $comments.length) { 
                    n = parseInt($comments.text().match(/\d+/)); // 匹配数字
                    $comments.text($comments.text().replace(n, n + 1));
                }
                // 评论显示
                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){ // ××××××××××××××××××××非嵌套评论时,新评论显示插入的位置(按自己的喜好修改显示位置)
                    $('#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评论

代码的核心内容和前面是一样的,只不过我将整段评论代码写成了一个ajaxComt()函数,也就是将代码用function ajaxComt(){...}包住,可以看到,此时submit事件并非动态绑定,只要这样

$(document).ready(function() {
    ajaxComt();
});

就和原来不用函数包住的时候没什么区别了。那么这个ajaxComt()函数,就是我们放在页面ajax回调里面重新加载的东西。ajax方法里面会有几个执行先后的参数,beforeSend、success、complete ,我们可以把它放在complete里面:

complete: function() { // 页面ajax完成后加载
    ajaxComt();
}

这样就和动态绑定没什么区别了。说法的区别从我个人角度来看就是:前者属于冒泡绑定,页面ajax和评论ajax是互不影响的;后者属于先后执行,页面ajax先执行完毕再执行一遍评论ajax 。


好了,教程[三]就到此结束。