1. 程式人生 > 實用技巧 >個人部落格 Django 評論模組開發總結【四】JavaScript邏輯,請求渲染校驗資料

個人部落格 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事件取消,控制不要一直跳動
 }

總結

整個評論模組了,還不是特別完善,比如載入更多評論(翻頁),回覆功能,評論注水(惡意刷介面)檢測等都沒有開發。