既然做了,就要做得绝。既然开了 Pjax,那就要真正实现全站无刷。

前言

在实现评论 Ajax 之前,我在网上也找了几篇教程学习了一下,大部分都是用 jQuery 实现的,但是并不是每个主题都会引入 jQuery 的,其次为了实现 Ajax 而引入 jQuery 并不值得去这么做。所以我选择用原生的方式去实现。

实现过程

首先,我们要知道表单提交的时候,浏览器发起了什么请求,请求报文有哪些。在评论时,浏览器会发起 POST 请求,请求体中的数据有评论者的信息(name, url, mail, text),注意需要判断用户是否登陆,如果登陆,就只有 text.
可以用 dom 元素的 value 属性获取用户表单的数据,然后发起 ajax 请求。请求地址这可以从表单上的 action 属性获取。当前我们还需要将响应报文中的 dom 元素提取需要的部分,进行替换。还可以加点过度动画等等,需要注意的是别忘了重载某些方法,和阻止默认提交事件。
下面贴上完整代码
1class Comment {
2
3    static comment_init() {
4      const commentsReply = document.querySelectorAll('span.comment_reply > a')
5      const replyForm = document.querySelector('.reply')
6      const isComment = document.querySelector('.post-form.is-comment')
7      for (let el of commentsReply) {
8        el.addEventListener('click', e => {
9          // 给恢复按钮绑定事件 获取parent-id
10          const href = e.target.getAttribute('href')
11          window.parentId = href.match(/replyTo=(\d+)/)[1]
12          // 弹出回复框
13          replyForm.removeAttribute('style')
14          if (isComment.classList.contains('active')) isComment.classList.remove('active');
15          setTimeout(() => {
16            document.getElementById('cancel-comment-reply-link').addEventListener('click', () => {
17              replyForm.style.display = 'none';
18            })
19          })
20        })
21      }
22    }
23  }
24
25  Comment.comment_init()
26
27  // ajax 提交评论实现方法
28
29  // 阻止默认事件
30  const form = document.getElementById('comment-form')
31  form.addEventListener('submit', function (e) {
32    e.preventDefault();
33    post_by_ajax(e, '#comment-form')
34  });
35
36  const reply_form = document.querySelector('.reply_form')
37  reply_form.addEventListener('submit', function (e) {
38    e.preventDefault();
39    post_by_ajax(e, '.reply_form', true)
40  });
41
42
43  // ajax 提交
44  function post_by_ajax(e, sel, reply = false) {
45    const isComment = document.querySelector('.post-form.is-comment')
46    const commentForm = document.querySelector(sel)
47    const post_url = e.target.getAttribute('action')
48    const cookie = document.cookie
49    const referer = window.location.href
50    const domParser = new DOMParser()
51    const dom = str => domParser.parseFromString(str, 'text/html')
52
53    // 如果是管理员登陆
54    if (!document.querySelector('#comment-form #author')) {
55      const text = commentForm.querySelector('#text').value
56      let data = null
57
58      if (reply) {
59        data = {
60          text, parent: window.parentId
61        }
62      } else {
63        data = {
64          text
65        }
66      }
67      ks.ajax({
68        url: post_url,
69        method: 'POST',
70        data,
71        success(res) {
72          const responseDOM = dom(res.responseText)
73
74          try {
75            isComment.classList.contains('active') ? isComment.classList.remove('active') : false
76            const needPartten = responseDOM.querySelector('.comment-list').innerHTML
77            needPartten === document.querySelector('.comment-list').innerHTML ? ks.notice("请等待审核哦 φ(>ω<*) ", {
78              color: "green",
79              time: 1000
80            }) : (document.querySelector('.comment-list').innerHTML = needPartten, ks.notice("评论成功了 (〃'▽'〃)", {
81              color: "green",
82              time: 1000
83            }), (reply ? false : window.scrollSmoothTo(document.body.scrollHeight || document.documentElement.scrollHeight)))
84
85          } catch (e) {
86            ks.notice(responseDOM.querySelector('.container').innerText, {
87              color: "red",
88              time: 1500
89            })
90          }
91          Comment.comment_init()
92        },
93        failed(res) {
94          console.log(res)
95          ks.notice("(;´д`)ゞ 失败了", {
96            color: 'red',
97            time: 1500
98          })
99        }
100      })
101    } else {
102      const author = commentForm.querySelector('#author').value
103      const mail = commentForm.querySelector('#mail').value
104      const url = commentForm.querySelector('#url').value
105      const text = commentForm.querySelector('#text').value
106
107      if (reply) {
108        data = {
109          author, mail, url, text, parent: window.parentId
110        }
111      } else {
112        data = {
113          author, mail, url, text,
114        }
115      }
116
117      ks.ajax({
118        method: "POST",
119        url: post_url,
120        data,
121        success(res) {
122          const responseDOM = dom(res.responseText)
123          isComment.classList.contains('active') ? isComment.classList.remove('active') : false
124          try {
125            const needPartten = responseDOM.querySelector('.comment-list').innerHTML
126            needPartten === document.querySelector('.comment-list').innerHTML ? ks.notice("请等待审核哦 φ(>ω<*) ", {
127              color: "green",
128              time: 1000
129            }) : (document.querySelector('.comment-list').innerHTML = needPartten, ks.notice("评论成功了 (〃'▽'〃)", {
130              color: "green",
131              time: 1000
132            }), (reply ? false : window.scrollSmoothTo(document.body.scrollHeight || document.documentElement.scrollHeight)))
133            Comment.comment_init()
134          } catch (e) {
135            ks.notice(responseDOM.querySelector('.container').innerText, {
136              color: "red",
137              time: 1500
138            })
139          }
140
141        }
142        ,
143        failed(res) {
144          console.log(res)
145          ks.notice("(;´д`)ゞ 失败了", {
146            color: 'red',
147            time: 1500
148          })
149        }
150      })
151
152    }
153    return false
154  }
Copy

后续说明

在完成 Ajax 请求后,我做了两件事。
第一,判断是否评论成功,如果失败则弹出信息框,说明原因。成功则重载方法,并用平滑移动等方法跳转到新评论的地方。
第二,评论成功后,收回评论框。
由于在项目中使用了 Kico Style ,所以 Ajax 请求由 ks.ajax() 实现,原生方法亦可。
使用以上实现方法的主题:

亲亲留个评论再走呗

正在加载评论区...