介绍25种很实用的ES6方法,来解决实际开发中的问题

原创 @泽泽vlog 昨天

主要是介绍25种ES6方法,这些方法都挺实用的,用本本记好要考的,嘿嘿嘿。时不时翻出来看看

1. 如何隐藏所有指定的元素

const hide = (el)=>
[...el].forEach(e=>e.style.display = 'none')
hide(document.querySelectorAll('img'))

2. 如何检查元素是否具有指定的类

在页面DOM里的每个节点上都有一个classList对象,程序员可以使用里面的方法新增、删除、修改节点上的CSS类。使用classList,程序员还可以用它来判断某个节点是否被赋予了某个CSS类

const hasClass = (el,className)=>el.classList.contains(className)

//示例
hasClass(document.querySelector('div.s_form_wrapper '),'soutu-env-nomac')

3. 如何切换一个元素的类

const toggleClass =(el,className)=>el.classList.toggle(className)

//示例 移除div具有`s_form_wrapper`的类
toggleClass( document.querySelector('div.s_form_wrapper '),'s_form_wrapper')

4. 如何获取当前页面的滚动位置

const getScrollPosition =(el=window)=>({
x:el.pageXOffset !==undefined ? el.pageXOffset:el.scrollLeft,
y:el.pageYOffset !==undefined ? el.pageYOffset:el.scrollTop
})

//示例
getScrollPosition() //{x: 0, y: 600}

5. 如何平滑滚动到页面顶部

const scrollToTop=()=>{
const c = document.documentElement.scrollTop || document.body.scrollTop
if(c > 0){
window.requestAnimationFrame(scrollToTop)
window.scrollTo(0,c-c/8)
}
}
//示例
scrollToTop()

requestAnimationFrame()不需要设置时间间隔,是由系统的时间间隔定义的。大多数浏览器的刷新频率是60Hz(每秒钟反复绘制60次),循环间隔是1000/60,约等于16.7ms。大多数浏览器会对反复挥着这个操作加以限制,不能超过60HZ,即使人为设置超过了该值,效果也不会改善。requestAnimationFrame()保证了最佳的绘制效率。
当页面被隐藏或者最小化时,setInterval()仍在后台继续执行,这种动画刷新是完全没有意义的,对cpu也是极大的浪费;
当页面被隐藏或者最小化时,requestAnimationFramel()中页面的渲染会被系统暂停,当页面再次激活后,继续从上次停止地方继续绘制;

6. 如何检查指定的元素在视口中是否可见

const elmentIsVisibleInViewport = (el,partiallyVisible=false)=>{
const {top,left,bottom,right } = el.getBoundingClientRect();
const { innerHeight ,innerWidth } = window;
return partiallyVisible
?((top > 0 && top < innerHeight ) ||( bottom > 0 && bottom < innerHeight )) &&
((left > 0 && left < innerWidth ) || (right > 0 && right < innerWidth ))
: top >= 0 && left >=0 && bottom <= innerHeight && right <= innerWidth;
}

//示例
elmentIsVisibleInViewport(el);//需要左右可见
elmentIsVisibleInViewport(el,true);//需要全屏(上下左右)可见

7. 如何检查父元素是否包含子元素

const elementContains =(parent,child)=>parent !== child && parent.contains(child);

//示例
elementContains(document.querySelector('head'),document.querySelector('title')
//true
elementContains(document.querySelector('body'),document.querySelector('body')
//false

8. 如何获取元素中的所有图像?

const getImages = (el,includeDuplicates = false)=>{
const images = [...el.getElementByTagName('img')].map(img => img.getAttribute('src'));
return includeDuplicates?images:[...new Set(images)];
}

//示例 includeDuplicates 为 true 表示需要重复元素
getImages(document,true)
getImages(document,false)

9. 如何确定设备是移动设备还是台式机/笔记本电脑

const detectDeviceType = () => {
return /Android|webOS|iPhone|iPad|BlackBerry|IEMobile|Opera Mini/i
.test(navigator.userAgent)?'Mobile':'Desktop';
}

//示例
detectDeviceType();

10. 获取当前url

const currentURL =() =>{window.location.href}

//示例
currentURL();//www.zeze.info

11. 验证url的格式合法性

const isURL=(str_url)=> {
let reg = /(?:(https?|ftp|file):)?\/\/[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]/;
let re = new RegExp(reg);
return re.test(str_url);
}
isURL('http://www.zeze.info')

12. 如何创建一个包含当前URL参数的对象

const getURLParameters = url =>(url.match(/([^?=&]+)(=([^&]*))/g) || []).reduce(
(accumulator,currentValue) => ((accumulator[currentValue.slice(0,v.indexOf('='))] = currentValue.slice(currentValue.indexOf('=')+1)),accumulator)
,{}
);
//示例
getURLParameters('http://www.zeze.info/index?a=1&b=2') //{a:1,b:2}
getURLParameters('http://www.zeze.info') //{}

13. 如何将一组表单元素转化为对象

const formToObject = form =>{
Array.from(new FormData(form)).reduce(
(acc,[key,value])=>({
...acc,
[key]:value
}),
{}
)
}
//示例
formToObject(document.querySelector('#from'))
//{email:'test@email.com',name:'www.zeze.info'}

14. 如何从对象检索给定选择器指示的一组属性

const get =(from,...selectos)=>
[...selectos].map(s=>
s
.replace(/\[([^\[\]]*)\]/g,'.$1.')
.split('.')
.filter(t=> t !=='')
.reduce((prev,cur)=>prev && prev[cur],from)
);

const obj = { selector:{to:{val:'val to select' } }, target:[1,2,{a:'test'}] };

//示例
get(obj,'selector.to.val','target[0]','target[2].a')
// ["val to select", 1, "test"]

15. 如何在等待指定时间后调用提供的函数

const delay =(fn,wait,...args)=>setTimeout(fn,wait,...args)

delay(
(test)=>console.info(test),
1000,
'later'
)

16. 如何在给定元素上触发特定事件且能选择地传递自定义数据

/* 创建一个事件对象,名字为newEvent,类型为build */
var newEvent = new Event('build', { bubbles:true,cancelable:true,composed:true });

/* 给这个事件对象创建一个属性并赋值 */
newEvent.name = "新的事件!";

/* 将自定义事件绑定在document对象上,这里绑定的事件要和我们创建的事件类型相同,不然无法触发 */
document.addEventListener("build",function(){
alert("你触发了自定义事件!" + newEvent.name);
},false)

/* 触发自定义事件 */
document.dispatchEvent(newEvent);

启动文档的时候因为”document.dispatchEvent(newEvent)”的关系,会先触发一次事件:

事件对象

之后你每执行一次”document.dispatchEvent(newEvent)”都会触发这个事件:

事件对象

接下来我们看看Event()这个方法的语法

event = new Event(typeArg, eventInit);

typeArg:指定事件类型,传递一个字符串。这里的事件类型指的是像点击事件(click)、提交事件(submit)、加载事件(load)等等。
eventInit:可选,传递EventInit类型的字典。实际上这个EventInit类型的字典也就是我们使用InitEvent()时需要传递的参数,以键值对的形式传递,不过它可以多选一个参数:
bubbles:事件是否支持冒泡,传递一个boolean类型的参数,默认值为false。
cancelable:是否可取消事件的默认行为,传递一个boolean类型的参数,默认值为false。
composed:事件是否会触发shadow DOM(阴影DOM)根节点之外的事件监听器,传递一个boolean类型的参数,默认值为false。(关于shadow DOM可以去看ChokCoco前辈的这篇文章,这里就不详说了,可能我会根据自己的理解也写一个关于shadow DOM的笔记)这个参数是InitEvent()中没有的新参数。

我们先通过下面的例子了解一下如何使用CustomEvent()去创建一个事件对象(这里先不使用事件相关值detail);

 /* 创建一个事件对象,名字为newEvent,类型为build */
var newEvent = new CustomEvent('build', { bubbles:true,cancelable:true,composed:true });

/* 给这个事件对象创建一个属性并赋值,这里绑定的事件要和我们创建的事件类型相同,不然无法触发 */
newEvent.name = "新的事件!";

/* 将自定义事件绑定在document对象上 */
document.addEventListener("build",function(){
alert("你触发了使用CustomEvent创建的自定义事件!" + newEvent.name);
},false)

/* 触发自定义事件 */
document.dispatchEvent(newEvent);
然后我们来看CustomEvent()的语法:
event = new CustomEvent(typeArg, customEventInit);
typeArg:指定事件类型,传递一个字符串。这里的事件类型指的是像点击事件(click)、提交事件(submit)、加载事件(load)等等。 customEventInit:可选。传递一个CustomEventInit字典。实际上这个字典就是我们使用initCustomEvent()时需要的参数,这个参数就是事件相关值(detail): detail:可选,默认值为null,类型为any(也就是说可以传递任意类型的参数)。这个值就是和事件相关联的值。 在展示使用detail作为第二个参数的例子前,要先注意一件事:CustomEventInit字典也可以接受EventInit字典的参数,就像一开始的例子一样,我传递了EventInit字典的bubbles、cancelable、composed。
下面将展示使用detail参数的例子,使用到detail的部分我会加粗处理(为了看着方便,这回就不传递EventInit字典中的参数了):
 /* 创建一个事件对象,名字为newEvent,类型为build */
var newEvent = new CustomEvent('build',{
detail: {
dog:"wo",cat:"mio"
}
});

/* 将自定义事件绑定在document对象上 */
document.addEventListener("build",function(){
alert(" event.detail.dog:" + event.detail.dog
+ "\n event.detail.cat:" + event.detail.cat );
},false)

/* 触发自定义事件 */
document.dispatchEvent(newEvent);

17. 如何从元素中移除事件监听器

const  off =
(el,evt,fn,opts=false) => el.removeEventListener(evt,fn,opts);

const fn =() => console.log('!')
document.body.addEventListener('click',fn)
off(document.body,'click',fn)

18. 如何获得给定毫秒数的可读格式

const  formatDuration = ms =>{
if(ms<0) ms = -ms;
const time ={
day: Math.floor(ms/86400000),
hour:Math.floor(ms/3600000) % 24,
minute: Math.floor(ms/60000) % 60,
second: Math.floor(ms/1000) % 60,
millisecond: Math.floor(ms) % 1000,
};
return Object.entries(time)
.filter(val => val[1] !== 0)
.map(([key,val])=>`${val} ${key}${val !== 1 ? 's':''}`)
.join(',');
}
//示例
formatDuration(1001);
//"1 second,1 millisecond"
formatDuration(3432505574);
//"39 days,17 hours,28 minutes,25 seconds,574 milliseconds"

19. 如何获得两个日期之间的差异(以天为单位)

const getDaysDiffBetweenDates = (dateInitial,dateFinal)=>
(dateFinal - dateInitial) / (1000 * 3600 *24)

//示例
getDaysDiffBetweenDates(new Date('2020-03-01'),new Date('2020-03-03'))

20. 如何向传递的URL发出GET请求

const httpGet = (url,callback,err = console.error) =>{
const request = new XMLHttpRequest();
request.open('GET',url,true);
request.onload = () =>callback(request.responseText);
request.onerror = () => err(request);
request.send();
}
httpGet(
'https://jsonplaceholder.typicode.com/posts/1',
console.log
)
/*
{
"userId": 1,
"id": 1,
"title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
"body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
}
*/

21. 如何对传递的URL发出POST请求

const httpPost = (url,data,callback,err = console.error) =>{
const request = new XMLHttpRequest();
request.open('POST',url,true);
request.setRequestHeader('Content-type','application/json; charset=utf-8');
request.onload = () =>callback(request.responseText);
request.onerror = () => err(request);
request.send(data);
}
const postData={
userId:1,
title:'Foo'
}
const data =JSON.stringify(postData)
httpPost(
'https://jsonplaceholder.typicode.com/posts',
data,
console.log
)

22. 如何为指定选择器创建具有指定范围,步长和持续时间的计数器

const counter = (selector,start,end,step=1,duration)=>{
let current = start;
_step = (end-start) * step < 0?-step : step
timer = setInterval(() => {
current += _step;
document.querySelector(selector).innerHTML = current;
if (current >= end) {
document.querySelector(selector).innerHTML = end ;
clearInterval(timer);
}
},Math.abs(Math.floor(duration/(end-start))));
}
//示例
counter('#myId',1,1000,5,20000);

23. 如何将字符串复制到剪贴板

const copyToClipboard = str =>{
const el = document.createElement('textarea');
el.value = str;
el.setAttribute('readonly','');
el.style.position='absolute';
el.style.left = '-9999px';
document.body.appendChild(el);
const selected =document.getSelection().rangeCount >0?document.getSelection().getRangeAt(0):false;
el.select();
document.execCommand('copy');
document.body.removeChild(el)
if(selected){
document.getSelection().removeAllRanges();
document.getSelection().addRange(selected);
}
}
copyToClipboard('www.zeze.info')

24. 如何确定页面的浏览器选项卡是否聚焦

const isBrowserTabFocused= ()=> !document.hidden; 
isBrowserTabFocused();

25. 如何创建目录(如果不存在)

const fs =require('fs')
const createDirIfNotExists = dir =>(!fs.existsSync(dir)?fs.mkdirSync(dir):undefined);
createDirIfNotExists('test');

这里面的方法大都挺实用,可以解决很多开发过程问题,大家就好好利用起来吧。

博主主页

可以加博主微信一起交流:twobixiaoxin