雜記(一)
介紹
記錄一些自己寫程式碼過程中遇到的問題,google來的一些技巧和方法。
Iconfont的symbol引入
- Iconfont的symbol引入,最好連結前加https:頭 ,防止受到package.json裡homepage的影響(如果設定了的話)。
- 除非是雙色圖示,否則不要線上修改其顏色,並批量去色,然後直接通過程式碼修改到自己需要的顏色。線上修改會寫死fill屬性,css改顏色就不能單純的通過color來修改了。
Input 只顯示下劃線
可以通過設定背景為none,在設定border達到效果。
input{ background: none; border-bottom: 1px solid #dbdbdb; border-top: 0px; border-left: 0px; border-right: 0px; }
物件陣列根據某屬性去重
一個比較精簡的寫法。
const res = new Map(); return arr.filter((a) => !res.has(a. attr) && res.set(a. attr, 1))
深拷貝
JSON.parse(JSON.stringify(object))
img標籤隱藏佔位邊框
img標籤設定的width和height,如果src為空則會出現佔位框。
img[src=""],img:not([src]) { opacity: 0; }
React中router問題
React中router跳轉時,舊元件的componentWillUnmount和新元件的constructor並不是按順序執行的。舉個栗子,即舊元件銷燬window.onresize會把新元件constructor新增的window.onresize監聽銷燬掉。但如果是在新元件componentDidMount中通過window.addEventListener則不會受到影響。
非同原始檔下載
同源可以通過a標籤的download屬性下載,非同源則如下:
/** * 獲取 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 } } }
節流函式
節流是將多次執行變成每隔一段時間執行。
/** * 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 模板
建立 .git-commit-template.txt
寫入(頭部建議空一行,行尾序列為LF(vscode可以更改)):
# <型別>: (型別的值見下面描述) <主題> (最多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 。