js之实用事件


监听滚动的结束事件

思想:把结束 handler 放在 scroll 事件中不断延时处理,scroll 事件停了之后就会触发。

1
2
3
4
5
6
7
8
9
10
var scrollTimer   //定时器
const timeout = 400 //时间
function handler () { //结束时触发时间
// ...
}
document.addEventListener('scroll', () => {
...
clearTimeout(scrollTimer) //打破上一个定时器
scrollTimer = setTimeout(handler, timeout) //定义新的定时器,这样就会在最后一次滚动的时候触发事件
})
判断移动设备类型
1
2
3
4
5
6
7
8
9
10
11
12
export const getOsFrom = (callback) => {
var u=navigator.userAgent;
var isAndroid=u.indexOf('Android') > -1 || u.indexOf('Adr') > -1; //android终端
var isiOS=!!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端
if ( isAndroid ) { // 返回1是android
return 'a';
}
if (isiOS) { // 返回2是ios
return 'i';
}
return 0;
}
获取当前页面的URL 对其带的参数进行处理
1
2
3
4
5
6
7
8
9
export const getUrlParams = () => {
let result = {}
let paramArr = location.search.substring(1).split('&')
paramArr.forEach(item => {
let arr = item.split('=')
arr.length === 2 && (result[arr[0]] = window.decodeURIComponent(arr[1]))
})
return result
}
颜色16进制转rgb
1
2
3
4
5
6
7
8
9
10
11
12
export const colorToRgb = (color, opacity) => {
let reg = /^[0-9a-fA-f]{6}$/
let sColor = color.toLowerCase().replace('#', '')
if (sColor && reg.test(sColor)) {
let sColorChange = []
for (let i = 0; i < 6; i += 2) {
sColorChange.push(parseInt('0x' + sColor.slice(i, i + 2)))
}
if (opacity) sColorChange.push(opacity)
return sColorChange
}
}
桌面推送消息
1
2
3
4
5
6
7
8
9
10
11
Notification.requestPermission(function (permission) {  
if (permission == "granted") {
var notification = new Notification("您有一条新的消息",{
dir: "auto",
lang: "zh-CN",
tag: "testNotice",
icon:'ant.png',
body: '你好啊!我是蚂蚁,我在测试桌面推送'
});
}
})
js执行字符串函数
1
2
// eval() 函数会将传入的字符串当做 JavaScript 代码进行执行,尽量不要使用
eval('alert(5)')
懒加载

首先将页面上的图片的 src 属性设为空字符串,而图片的真实路径则设置在data-original属性中,
当页面滚动的时候需要去监听scroll事件,在scroll事件的回调中,判断我们的懒加载的图片是否进入可视区域,如果图片在可视区内将图片的 src 属性设置为data-original 的值,这样就可以实现延迟加载。预加载和懒加载的区别是一个是提前加载,一个是迟缓甚至不加载。懒加载对服务器前端有一定的缓解压力作用,预加载则会增加服务器前端压力。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<head>
<meta charset="UTF-8">
<title>Lazyload</title>
<style>
.image-item {
display: block;
margin-bottom: 50px;
height: 200px;//一定记得设置图片高度
}
</style>
</head>
<body>
<img src="" class="image-item" lazyload="true" data-original="images/1.png"/>
<img src="" class="image-item" lazyload="true" data-original="images/2.png"/>
<img src="" class="image-item" lazyload="true" data-original="images/3.png"/>
<img src="" class="image-item" lazyload="true" data-original="images/4.png"/>
<img src="" class="image-item" lazyload="true" data-original="images/5.png"/>
<img src="" class="image-item" lazyload="true" data-original="images/6.png"/>
<img src="" class="image-item" lazyload="true" data-original="images/7.png"/>
<img src="" class="image-item" lazyload="true" data-original="images/8.png"/>
<img src="" class="image-item" lazyload="true" data-original="images/9.png"/>
<img src="" class="image-item" lazyload="true" data-original="images/10.png"/>
<img src="" class="image-item" lazyload="true" data-original="images/11.png"/>
<img src="" class="image-item" lazyload="true" data-original="images/12.png"/>
<script>
var viewHeight =document.documentElement.clientHeight//获取可视区高度
function lazyload(){
var eles=document.querySelectorAll('img[data-original][lazyload]')
Array.prototype.forEach.call(eles,function(item,index){
var rect
if(item.dataset.original==="")
return
rect=item.getBoundingClientRect()// 用于获得页面中某个元素的左,上,右和下分别相对浏览器视窗的位置
if(rect.bottom>=0 && rect.top < viewHeight){
!function(){
var img=new Image()
img.src=item.dataset.original
img.onload=function(){
item.src=img.src
}
item.removeAttribute("data-original")//移除属性,下次不再遍历
item.removeAttribute("lazyload")
}()
}
})
}
lazyload()//刚开始还没滚动屏幕时,要先触发一次函数,初始化首页的页面图片
document.addEventListener("scroll",lazyload)
</script>
预加载

预加载简单来说就是将所有所需的资源提前请求加载到本地,这样后面在需要用到时就直接从缓存取资源。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// 1、使用HTML标签预加载
<img src="http://pic26.nipic.com/20121213/6168183 0044449030002.jpg" style="display:none"/>
// 虽然display:none; 这时候已经请求了图片资源

// 2、使用Image对象
<script src="./myPreload.js"></script>
//myPreload.js文件
var image= new Image()
image.src="http://pic26.nipic.com/20121213/6168183 004444903000 2.jpg"

// 3、使用XMLHttpRequest对象
var xmlhttprequest=new XMLHttpRequest();
xmlhttprequest.onreadystatechange=callback;
xmlhttprequest.onprogress=progressCallback;
xmlhttprequest.open("GET","http://image.baidu.com/mouse,jpg",true);
xmlhttprequest.send();
function callback(){
if(xmlhttprequest.readyState==4&& xmlhttprequest.status==200){
var responseText=xmlhttprequest.responseText;
}else{
console.log("Request was unsuccessful:"+xmlhttprequest.status);
}
}
function progressCallback(e){
e=e || event;
if(e.lengthComputable){
console.log("Received"+e.loaded+"of"+e.total+"bytes")
}
}

// 4、使用PreloadJS库
PreloadJS提供了一种预加载内容的一致方式,以便在HTML应用程序中使用。预加载可以使用HTML标签以及XHR来完成。默认情况下,PreloadJS会尝试使用XHR加载内容,因为它提供了对进度和完成事件的更好支持,但是由于跨域问题,使用基于标记的加载可能更好。

var queue=new createjs.LoadQueue();//默认是xhr对象,如果是new createjs.LoadQueue(false)是指使用HTML标签,可以跨域
queue.on("complete",handleComplete,this);
queue.loadManifest([
{id:"myImage",src:"http://pic26.nipic.com/20121213/6168183 0044449030002.jpg"},
{id:"myImage2",src:"http://pic9.nipic.com/20100814/2839526 1931471581702.jpg"}
]);
function handleComplete(){
var image=queue.getResuLt("myImage");
document.body.appendChild(image);
}
函数节流

在规定时间内只触发一次

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function throttle(fn, delay) {
// 记录上一次函数触发的时间
var lastTime = Date.now();
return function() {
// 记录当前函数触发的时间
var nowTime = Date.now();
if (nowTime - lastTime > delay) {
// 修正this指向问题
fn.call(this);
// 同步时间
lastTime = nowTime;
}
}
}
document.onscroll = throttle(function() { console.log('scroll事件被触发了' + Date.now()) }, 200)
函数防抖

一个需要频繁触发的函数,在规定时间内,只让最后一次生效,前面的不生效。其原理就第一次调用函数,创建一个定时器,在指定的时间间隔之后运行代码。当第二次调用该函数时,它会清除前一次的定时器并设置另一个。如果前一个定时器已经执行过了,这个操作就没有任何意义。然而,如果前一个定时器尚未执行,其实就是将其替换为一个新的定时器,然后延迟一定时间再执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<button id='btn'>按钮</button>
<script type="text/javascript">
function debounce(fn, delay, immediate = true) {
// 记录上一次的延时器
var timer = null;
return function() {
if (immediate) {
fn.apply(this, [...arguments])
immediate = false
} else {
// 清除上一次延时器
clearTimeout(timer)
timer = setTimeout(function() {
fn.apply(this, [...arguments])
}, delay)
}
}
}
document.getElementById('btn').onclick = debounce(function() {
console.log('点击事件被触发' + Date.now())
}, 1000)
</script>
数组降维

思路: 递归

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
let arr = [[1,[2,3, [4,5]]]]

function fn (arr, callback) {
let result = []
(function fn1 (arr) {
arr.forEach(item => {
if (Array.isArray(item)) {
fn1(item)
} else {
result.push(callback(item))
}
})
})(arr)
return result
}
let res = fn(arr, function (item) {return item + 1})
对象父子级分解

将对象的父子级进行分解成数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let obj = { id: 1, name: '一级1', children: [{ id: 2, name: '一级1-1' }, { id: 3, name: '一级1-2', children: [{ id: 4, name: '一级1-1-1' }, { id: 5, name: '一级1-1-2' }] }] }

function fn (obj, callback) {
let result = [];
(function fn1 (obj) {
result.push(obj)
if (obj.children) {
obj.children.forEach(item => {
fn1(item)
})
}
})(obj)
return result
}
let res = fn(obj)