介紹
記錄一些自己寫代碼過程中遇到的問題,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。