为 Typecho 主题开启 Ajax 评论真正实现全站无刷
既然做了,就要做得绝。既然开了 Pjax,那就要真正实现全站无刷。
前言
在实现评论 Ajax 之前,我在网上也找了几篇教程学习了一下,大部分都是用 jQuery 实现的,但是并不是每个主题都会引入 jQuery 的,其次为了实现 Ajax 而引入 jQuery 并不值得去这么做。所以我选择用原生的方式去实现。
实现过程
首先,我们要知道表单提交的时候,浏览器发起了什么请求,请求报文有哪些。在评论时,浏览器会发起 POST 请求,请求体中的数据有评论者的信息(name, url, mail, text),注意需要判断用户是否登陆,如果登陆,就只有 text
.
可以用 dom 元素的 value
属性获取用户表单的数据,然后发起 ajax 请求。请求地址这可以从表单上的 action
属性获取。当前我们还需要将响应报文中的 dom 元素提取需要的部分,进行替换。还可以加点过度动画等等,需要注意的是别忘了重载某些方法,和阻止默认提交事件。
下面贴上完整代码
class Comment {
static comment_init() {
const commentsReply = document.querySelectorAll('span.comment_reply > a')
const replyForm = document.querySelector('.reply')
const isComment = document.querySelector('.post-form.is-comment')
for (let el of commentsReply) {
el.addEventListener('click', e => {
// 给恢复按钮绑定事件 获取parent-id
const href = e.target.getAttribute('href')
window.parentId = href.match(/replyTo=(\d+)/)[1]
// 弹出回复框
replyForm.removeAttribute('style')
if (isComment.classList.contains('active')) isComment.classList.remove('active');
setTimeout(() => {
document.getElementById('cancel-comment-reply-link').addEventListener('click', () => {
replyForm.style.display = 'none';
})
})
})
}
}
}
Comment.comment_init()
// ajax 提交评论实现方法
// 阻止默认事件
const form = document.getElementById('comment-form')
form.addEventListener('submit', function (e) {
e.preventDefault();
post_by_ajax(e, '#comment-form')
});
const reply_form = document.querySelector('.reply_form')
reply_form.addEventListener('submit', function (e) {
e.preventDefault();
post_by_ajax(e, '.reply_form', true)
});
// ajax 提交
function post_by_ajax(e, sel, reply = false) {
const isComment = document.querySelector('.post-form.is-comment')
const commentForm = document.querySelector(sel)
const post_url = e.target.getAttribute('action')
const cookie = document.cookie
const referer = window.location.href
const domParser = new DOMParser()
const dom = str => domParser.parseFromString(str, 'text/html')
// 如果是管理员登陆
if (!document.querySelector('#comment-form #author')) {
const text = commentForm.querySelector('#text').value
let data = null
if (reply) {
data = {
text, parent: window.parentId
}
} else {
data = {
text
}
}
ks.ajax({
url: post_url,
method: 'POST',
data,
success(res) {
const responseDOM = dom(res.responseText)
try {
isComment.classList.contains('active') ? isComment.classList.remove('active') : false
const needPartten = responseDOM.querySelector('.comment-list').innerHTML
needPartten === document.querySelector('.comment-list').innerHTML ? ks.notice("请等待审核哦 φ(>ω<*) ", {
color: "green",
time: 1000
}) : (document.querySelector('.comment-list').innerHTML = needPartten, ks.notice("评论成功了 (〃'▽'〃)", {
color: "green",
time: 1000
}), (reply ? false : window.scrollSmoothTo(document.body.scrollHeight || document.documentElement.scrollHeight)))
} catch (e) {
ks.notice(responseDOM.querySelector('.container').innerText, {
color: "red",
time: 1500
})
}
Comment.comment_init()
},
failed(res) {
console.log(res)
ks.notice("(;´д`)ゞ 失败了", {
color: 'red',
time: 1500
})
}
})
} else {
const author = commentForm.querySelector('#author').value
const mail = commentForm.querySelector('#mail').value
const url = commentForm.querySelector('#url').value
const text = commentForm.querySelector('#text').value
if (reply) {
data = {
author, mail, url, text, parent: window.parentId
}
} else {
data = {
author, mail, url, text,
}
}
ks.ajax({
method: "POST",
url: post_url,
data,
success(res) {
const responseDOM = dom(res.responseText)
isComment.classList.contains('active') ? isComment.classList.remove('active') : false
try {
const needPartten = responseDOM.querySelector('.comment-list').innerHTML
needPartten === document.querySelector('.comment-list').innerHTML ? ks.notice("请等待审核哦 φ(>ω<*) ", {
color: "green",
time: 1000
}) : (document.querySelector('.comment-list').innerHTML = needPartten, ks.notice("评论成功了 (〃'▽'〃)", {
color: "green",
time: 1000
}), (reply ? false : window.scrollSmoothTo(document.body.scrollHeight || document.documentElement.scrollHeight)))
Comment.comment_init()
} catch (e) {
ks.notice(responseDOM.querySelector('.container').innerText, {
color: "red",
time: 1500
})
}
}
,
failed(res) {
console.log(res)
ks.notice("(;´д`)ゞ 失败了", {
color: 'red',
time: 1500
})
}
})
}
return false
}
后续说明
在完成 Ajax 请求后,我做了两件事。
第一,判断是否评论成功,如果失败则弹出信息框,说明原因。成功则重载方法,并用平滑移动等方法跳转到新评论的地方。
第二,评论成功后,收回评论框。
由于在项目中使用了 Kico Style ,所以 Ajax 请求由 ks.ajax()
实现,原生方法亦可。
使用以上实现方法的主题:Paul