記錄一些本身寫代碼過程當中遇到的問題,google來的一些技巧和方法。css
能夠經過設置背景爲none,在設置border達到效果。git
input{ background: none; border-bottom: 1px solid #dbdbdb; border-top: 0px; border-left: 0px; border-right: 0px; }
一個比較精簡的寫法。json
const res = new Map(); return arr.filter((a) => !res.has(a. attr) && res.set(a. attr, 1))
JSON.parse(JSON.stringify(object))
img標籤設置的width和height,若是src爲空則會出現佔位框。數組
img[src=""],img:not([src]) { opacity: 0; }
React中router跳轉時,舊組件的componentWillUnmount和新組件的constructor並非按順序執行的。舉個栗子,即舊組件銷燬window.onresize會把新組件constructor添加的window.onresize監聽銷燬掉。但若是是在新組件componentDidMount中經過window.addEventListener則不會受到影響。緩存
同源能夠經過a標籤的download屬性下載,非同源則以下:app
/** * 獲取 blob * @param {String} url 目標文件地址 * @return {Promise} */ function getBlob(url) { return new Promise(resolve => { const xhr = new XMLHttpRequest(); xhr.open('GET', url, true); xhr.responseType = 'blob'; xhr.onload = () => { if (xhr.status === 200) { resolve(xhr.response); } }; xhr.send(); }); } /** * 保存 * @param {Blob} blob * @param {String} filename 想要保存的文件名稱 */ function saveAs(blob, filename) { if (window.navigator.msSaveOrOpenBlob) { navigator.msSaveBlob(blob, filename); } else { const link = document.createElement('a'); const body = document.querySelector('body'); link.href = window.URL.createObjectURL(blob); link.download = filename; // fix Firefox link.style.display = 'none'; body.appendChild(link); link.click(); body.removeChild(link); window.URL.revokeObjectURL(link.href); } } /** * 下載 最後直接調用download便可 * @param {String} url 目標文件地址 * @param {String} filename 想要保存的文件名稱 */ export function download(url, filename) { getBlob(url).then(blob => { saveAs(blob, filename); }); }
防抖動是將屢次執行變爲最後一次執行。函數
/** * 防抖函數,返回函數連續調用時,空閒時間必須大於或等於 wait,func 纔會執行 * * @param {function} func 回調函數 * @param {number} wait 表示時間窗口的間隔 * @param {boolean} immediate 設置爲ture時,是否當即調用函數 * @return {function} 返回客戶調用函數 */ export function debounce(func, wait = 200, immediate = false) { let timer, context, args // 延遲執行函數 const later = () => setTimeout(() => { // 延遲函數執行完畢,清空緩存的定時器序號 timer = null // 延遲執行的狀況下,函數會在延遲函數中執行 // 使用到以前緩存的參數和上下文 if (!immediate) { func.apply(context, args) context = args = null } }, wait) // 這裏返回的函數是每次實際調用的函數 return function (...params) { // 若是沒有建立延遲執行函數(later),就建立一個 if (!timer) { timer = later() // 若是是當即執行,調用函數 // 不然緩存參數和調用上下文 if (immediate) { func.apply(this, params) } else { context = this args = params } // 若是已有延遲執行函數(later),調用的時候清除原來的並從新設定一個 // 這樣作延遲函數會從新計時 } else { clearTimeout(timer) timer = later() context = this args = params } } }
節流是將屢次執行變成每隔一段時間執行。grunt
/** * underscore 節流函數,返回函數連續調用時,func 執行頻率限定爲 次 / wait * * @param {function} func 回調函數 * @param {number} wait 表示時間窗口的間隔 * @param {object} options 若是想忽略開始函數的的調用,傳入{leading: false}。 * 若是想忽略結尾函數的調用,傳入{trailing: false} * 二者不能共存,不然函數不能執行 * @return {function} 返回客戶調用函數 */ _.throttle = function(func, wait, options) { var context, args, result; var timeout = null; // 以前的時間戳 var previous = 0; // 若是 options 沒傳則設爲空對象 if (!options) options = {}; // 定時器回調函數 var later = function() { // 若是設置了 leading,就將 previous 設爲 0 // 用於下面函數的第一個 if 判斷 previous = options.leading === false ? 0 : _.now(); // 置空一是爲了防止內存泄漏,二是爲了下面的定時器判斷 timeout = null; result = func.apply(context, args); if (!timeout) context = args = null; }; return function() { // 得到當前時間戳 var now = _.now(); // 首次進入前者確定爲 true // 若是須要第一次不執行函數 // 就將上次時間戳設爲當前的 // 這樣在接下來計算 remaining 的值時會大於0 if (!previous && options.leading === false) previous = now; // 計算剩餘時間 var remaining = wait - (now - previous); context = this; args = arguments; // 若是當前調用已經大於上次調用時間 + wait // 或者用戶手動調了時間 // 若是設置了 trailing,只會進入這個條件 // 若是沒有設置 leading,那麼第一次會進入這個條件 // 還有一點,你可能會以爲開啓了定時器那麼應該不會進入這個 if 條件了 // 其實仍是會進入的,由於定時器的延時 // 並非準確的時間,極可能你設置了2秒 // 可是他須要2.2秒才觸發,這時候就會進入這個條件 if (remaining <= 0 || remaining > wait) { // 若是存在定時器就清理掉不然會調用二次回調 if (timeout) { clearTimeout(timeout); timeout = null; } previous = now; result = func.apply(context, args); if (!timeout) context = args = null; } else if (!timeout && options.trailing !== false) { // 判斷是否設置了定時器和 trailing // 沒有的話就開啓一個定時器 // 而且不能不能同時設置 leading 和 trailing timeout = setTimeout(later, remaining); } return result; }; };
建立 .git-commit-template.txt
寫入(頭部建議空一行,行尾序列爲LF(vscode能夠更改)):post
# <類型>: (類型的值見下面描述) <主題> (最多50個字) # 解釋爲何要作這些改動 # |<---- 請限制每行最多72個字 ---->| # 提供相關文章和其它資源的連接和關鍵字 # 例如: Github issue #23 # --- 提交 結束 --- # 類型值包含 # feat (新特性) # fix (bug修復) # docs (文檔改動) # style (格式化, 缺失分號等; 不包括生產代碼變更) # refactor (重構代碼) # test (添加缺失的測試, 重構測試, 不包括生產代碼變更) # chore (更新grunt任務等; 不包括生產代碼變更) # -------------------- # 注意 # 主題和內容以一個空行分隔 # 主題限制爲最大50個字 # 主題行大寫 # 主題行結束不用標點 # 主題行使用祈使名 # 內容每行72個字 # 內容用於解釋爲何和是什麼,而不是怎麼作 # 內容多行時以'-'分隔 # --------------------
而後把該文件丟到你喜歡的位置。測試
//這個命令只能設置當前分支的提交模板 git config commit.template [模板文件位置] //這個命令能設置全局的提交模板 git config --global commit.template [模板文件位置]
完成!
更強烈的規範約束能夠看這個優雅的提交你的 Git Commit Message。