个人博客 Django 评论模块开发总结【四】JavaScript逻辑,请求渲染校验数据
JavaScript逻辑,请求渲染校验数据
个人网站开通评论了 https://www.charmcode.cn/article/2020-07-09_Comment
欢迎评论交流
思路分析
首先得理清楚,需要做那些功能
- 确定是否登录(通过cookie 存储的用户信息判断)
- 用户输入内容校验,以及提示用户输入字数,涉及到防抖函数
- 请求评论数据,然后渲染数据列表(目前不考虑做分页)
- 添加评论数据,添加前先过滤数据,提交按钮防抖,提交后清空输入框并且给出接口回调提示,评论成功或者失败。
工具类函数
思路分析中用到的几个点,需要封装以下工具类函数
- 1 获取cookie值
/**
* 获取cookie工具函数
* */
function getCookie(c_name) {
if (document.cookie.length > 0) {
let c_start = document.cookie.indexOf(c_name + "=");
if (c_start !== -1) {
c_start = c_start + c_name.length + 1;
let c_end = document.cookie.indexOf(";", c_start);
if (c_end === -1) c_end = document.cookie.length;
return unescape(document.cookie.substring(c_start, c_end));
}
}
return "";
}
- 2 输入框,提交按钮, 防抖函数
/**
* 防抖工具函数
* */
function debounce(fun, delay) {
return function (args) {
let that = this;
let _args = args;
clearTimeout(fun.id);
fun.id = setTimeout(function () {
fun.call(that, _args)
}, delay)
}
}
- 3 过滤输入评论数据的函数(当然后端也有一次过滤)
/**
* 过滤输入数据工具函数
* author:CharmCode.cn
* */
function clearValue(v) {
v = v.trim();
// 去掉特殊字符
v = v.replace(/[\'\"\\\/\b\f\n\r\t]/g, '');
v = v.replace(/[\#\$\%\^\&\*\{\}\:\"\L\<\>\?]/g, '');
// 多个空格|换行 替换成一个
v = v.replace(/[\s\n]{2,}/g, " ");
// 截取前100个字符
v = v.slice(0, 100);
return v
}
- 4 封装的http请求库
返回一个promise对象:可以参考我上一篇文章
/**
* fetch函数封装
* @author:CharmCode.cn
* @return: promise object
* */
function requests(path, method = "GET", data = {}, headers = {'content-type': 'application/json'}) {
method = method.toUpperCase();
// 默认请求头
let requestHeader = {
headers,
method
};
// 如果是get请求
if (method === "GET") {
// 转换拼接get参数
let esc = encodeURIComponent;
let queryParams = Object.keys(data)
.map(k => `${esc(k)}=${esc(data[k])}`)
.join('&');
if (queryParams) path += `?${queryParams}`;
} else {
// 其他请求 放入body里面
requestHeader.body = JSON.stringify(data)
}
// 可以在这封装一个回调函数,请求拦截
// 发送请求并返回 promise 对象 注意 fetch不会拦截其他异常请求️
return fetch(`${window.location.origin}${path}`, requestHeader).then(
// 可在这里封装 响应拦截函数
response => response.json()
)
}
js逻辑实现
获取用户信息
页面一加载,js就会获取用户信息,如果获取到了,就把登录按钮给去掉,替换成用户的信息,然后去掉输入框的只读属性。
function checkLogin() {
let username = getCookie("github_username");
let avatar = getCookie("github_avatar");
if (username && avatar) {
// 获取到 说明已经登录
let github_info = document.getElementById("github-info");
github_info.innerHTML = `<img class="github-image"
src=${avatar}>
<span class="github-name">${username}</span>`;
// 已经登录 移除输入框只读属性
let input = document.getElementById("veditor");
input.removeAttribute("readonly")
}
}
加载评论
这一步和上面从cookie中获取用户信息,是异步进行的。
演示了使用fetch发送请求的便捷性, 当然可以封装一个响应拦截器,统一拦截状态码不为200的响应。
// 获取评论
function loadCommit() {
let article_url = window.location.pathname.split("/").pop();
requests(
"/article/comment/",
"GET",
{
article_url: article_url
}
).then((data) => {
if (data.code === 200) {
// 获取到评论框对象
let commit = document.getElementById("show-commit");
// 每次加载评论前先置为空
commit.innerHTML = "";
let strTemp = "";
for (let i of data.data) {
// 处理GitHub头像加载失败
let onerrorImg = i.userInfo.avatar.replace(/avatars\d/, 'avatars3');
strTemp += `<div class="comments-item">
<div class="comment-user-head">
<img src="${i.userInfo.avatar}" onerror="imgerrorfun("${onerrorImg}");">
</div>
<div class="comment-content">
<div class="comment-body">
${i.content}
</div>
<div class="comment-time">
<a href="${i.userInfo.github_add}" target="_blank">${i.userInfo.username}</a>
${i.time}
<span id="reply" style="padding: 3px;color: #00a8c6">
回复
</span>
</div>
</div>
</div>`
}
commit.innerHTML = strTemp;
}
})
}
检测输入 防抖
首先我是有检测,用户输入评论的字数的,当然不是实时监控检测,有5毫秒的延迟检测。
// 检测输入
function inputTextChange() {
let input = document.getElementById("veditor");
// 防抖监听输入事件
input.addEventListener("input", debounce(() => {
let inputLen = input.value.length;
let surplus = 100 - inputLen;
let valueTip = document.getElementById("valueLen");
if (surplus >= 1) {
valueTip.innerHTML = `还能输入 ${surplus} 字`
} else {
valueTip.innerHTML = `已经超过100字,将截取前100字`
}
}, 500), false)
}
提交评论
提交评论这块我也做了防抖处理,然后提交前验证数据,还有就是提交后消息回调,提示是否回调成功。
// 提交评论数据
function commitReply() {
let username = getCookie("github_username");
let avatar = getCookie("github_avatar");
let commit_btn = document.getElementById("commit");
commit_btn.addEventListener("click", debounce(() => {
if (username && avatar) {
// 获取textarea对象
let inputValue = document.getElementById("veditor");
// 过滤数据
inputValue = clearValue(inputValue.value);
if (inputValue.length >= 2) {
// 发送post请求
submitCommit(username, inputValue, replayTip);
// 将textarea 值置为空
document.getElementById("veditor").value = "";
// 重新加载评论
loadCommit()
}
} else {
alert("请登录后在输入")
}
}, 500), false);
}
回调提示
这是一个提交评论的回调提示,然后最后面的定时器,设置提示信息停留时间
// 回调后的提示信息
function replayTip(code) {
// replyTipSpan
let tip = document.getElementById("replyTipSpan");
if (code === 200) {
tip.innerHTML = `<span style='color:#67C23A'>评论成功</span>`
} else {
tip.innerHTML = `<span style='color:#F56C6C'>评论失败</span>`
}
// 清理提示
setTimeout(() => {
tip.innerHTML = ""
}, 8000)
}
头像加载错误处理
由于我使用的是Github第三方登录, github cdn很多,所以我了图片的onerror="imgerrorfun("${onerrorImg}")
这个加载错误处理事件。以免加载不出来头像等资源时,像Stack Overflow一样一直卡在哪里加载
// 图片加载失败后处理函数
function imgerrorfun(onerrorImg) {
let img = event.srcElement;
img.src = onerrorImg;
img.onerror = null; // 把传递的onerror事件取消,控制不要一直跳动
}
总结
整个评论模块了,还不是特别完善,比如加载更多评论(翻页),回复功能,评论注水(恶意刷接口)检测等都没有开发。