共计 4413 个字符,预计需要花费 12 分钟才能阅读完成。
介绍
记录一些自己写代码过程中遇到的问题,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。
正文完
发表至: javascript
2019-05-03