在实现隐藏弹窗或收起下拉框时,如果你还在一层层判断是否点击了某个元素之外的区域,赶紧试试使用 contains
方法来实现。
document.addEventListener('click', function (evt) {
// isClickedOutside 为 true 如果点击的元素在 ele 之外
const isClickedOutside = !ele.contains(evt.target);
});
当你想查看第三方库的主页和代码仓库时,你可以使用一下命令快速打开:
// 打开主页
npm home PACKAGE_NAME
npm home react
// 打开代码仓库
npm repo PACKAGE_NAME
npm repo react
除了在监听的事件函数中移除当前的监听外,也可以使用 once
参数。
const handler = function (e) {};
ele.addEventListener('event-name', handler, { once: true });
const formatSeconds = (s) =>
[parseInt(s / 60 / 60), parseInt((s / 60) % 60), parseInt(s % 60)]
.join(':')
.replace(/b(d)b/g, '0$1')
获取 url 参数有个热门的库 query-string,如果不想使用的话,可以通过 URLSearchParams
API 实现。
const getUrlParams = (query) =>
Array.from(new URLSearchParams(query)).reduce(
(p, [k, v]) =>
Object.assign({}, p, { [k]: p[k] ? (Array.isArray(p[k]) ? p[k] : [p[k]]).concat(v) : v }),
{}
)
// 获取 query 参数
getUrlParams(location.query)
// { a: ['1', '4'], b: '2', c: '3' }
getUrlParams('?a=1&b=2&c=3&a=4')
// 获取 hash 参数
getUrlParams(location.hash.split('?')[1])
看似平平无奇的打开页签,但是需要关注下 rel
,如果要打开外链,建议设置为 noopener noreferrer
,避免一些恶意网站通过 window.opener.location
重定向你的网站地址。window.open
方法同理。
// 高版本浏览器 rel 默认为 noopener,不过建议显示设置,兼容低版本。
<a target="_blank" rel="noopener noreferrer">...</a>
// window.open rel 默认为 opener,需要自己设置
window.open('https://baidu.com', 'baidu', 'noopener,noreferrer')
// 以下有安全漏洞,打开的新页签可以通过 window.opener.location 重定向你的网站
<a target="_blank" rel="opener">...</a>
window.opener.location = 'http://fake.website.here';
通过 fileReader
API 的 readAsDataURL
方法来显示上传图片
function readImage() {
const fileReader = new FileReader()
const file = document.getElementById('uploaded-file').files[0]
if (file) {
fileReader.readAsDataURL(file)
}
fileReader.addEventListener(
'load',
() => {
const result = fileReader.result
const resultContainer = document.getElementById('result')
const img = document.createElement('img')
img.src = result
resultContainer.append(img)
},
{ once: true }
)
}
当有大量请求需要发起时,往往需求限制并发数量保证其他请求能优先返回。
async function asyncPool(poolLimit, iterable, iteratorFn) {
// 用于保存所有异步请求
const ret = [];
// 用户保存正在进行的请求
const executing = new Set();
for (const item of iterable) {
// 构造出请求 Promise
const p = Promise.resolve().then(() => iteratorFn(item, iterable));
ret.push(p);
executing.add(p);
// 请求执行结束后从正在进行的数组中移除
const clean = () => executing.delete(p);
p.then(clean).catch(clean);
// 如果正在执行的请求数大于并发数,就使用 Promise.race 等待一个最快执行完的请求
if (executing.size >= poolLimit) {
await Promise.race(executing);
}
}
// 返回所有结果
return Promise.all(ret);
}
// 使用方法
const timeout = i => new Promise(resolve => setTimeout(() => resolve(i), i));
asyncPool(2, [1000, 5000, 3000, 2000], timeout).then(results => {
console.log(results)
})
生成 uuid 的代码片段
const uuid = (a) =>
a
? (a ^ ((Math.random() * 16) >> (a / 4))).toString(16)
: ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, uuid)