记录一些本身写代码过程当中遇到的问题,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。