个人博客 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事件取消,控制不要一直跳动
 }

总结

整个评论模块了,还不是特别完善,比如加载更多评论(翻页),回复功能,评论注水(恶意刷接口)检测等都没有开发。

posted @ 2020-08-25 22:00  王小右  阅读(204)  评论(0编辑  收藏  举报