一、定时器的练习
setInterval:定时调用
可以将一个函数,每隔一段时间执行一次;
参数1:回调函数,该函数会每隔一段时间被调用一次;
参数2:每次调用间隔的时间,单位:毫秒
返回值:返回一个Number类型的数据,这个数据用来作为定时器的唯一标识;
var num = 1;
var timer = setInterval(function() {
count.innerHTML = num++
if(num == 21) {
clearInterval(timer)
}
}, 200)
切换图片的练习:
var img = document.getElementsByTagName('img')[0]
var arr = ['./1.jpg', './2.jpg', './3.jpg',
'./4.jpg', './5.jpg']
var i = 0;
setInterval(function() {
i++;
if (i >= arr.length) {i = 0} // 或者使用下面一行的写法
i = i % arr.length
img.src = arr[i]
}, 500)
如果设置一个按钮,点击按钮,执行定时器;会有一个问题,如果连续点击按钮,则会开启很多个定时器,所以切换速度会越来越快,而且timer是赋值给最新的定时器,所以关闭定时器只能关闭最后一个定时器(导致无法关闭所有的定时器)
解决办法:开启一个定时器时,先关闭上一个定时器
定时器的应用:
<div><button id="btn">点击图片,进行移动</button></div>
<div id="box"></div>
function getStyle(obj, name) {
return getComputedStyle(obj, null)[name]
}
var box = document.getElementById("box")
var btn = document.getElementById("btn")
var timer;
btn.onclick = function() {
clearInterval(timer)
timer = setInterval(() => {
var oldValue = parseInt(getStyle(box, 'left'))
var newValue = oldValue + 4
if (newValue >= 600) {
newValue = 600
}
box.style.left = newValue + "px"
if (newValue == 600) {
clearInterval(timer)
}
}, 30);
}
二、延时调用
定时调用会执行多次,而延时调用只会执行一次
var num = 0;
// 隔一段时间再执行,而且只会执行一次
var timer = setTimeout(function() {
console.log(++num) // 先自增,后执行num表达式,打印1
console.log(num++) // 先执行num表达式,后自增,打印0
}, 1000)
// 关闭延时调用
clearTimeout(timer)
三、防抖
事件被触发n秒后再执行回调函数,如果在这n秒内又被触发,则重新计时;应用场景:
- 用户在输入框中连续输入一串字符后,只会在输入完后去执行最后一次的查询ajax请求,这样可以有效减少请求次数,节约请求资源;
- window的resize、scroll事件,不断地调整浏览器的窗口大小,或者滚动时会触发对应事件,防抖让其只触发一次;
- 搜索框搜索输入,手机号、邮箱验证输入
<body>
<div>
<input type="text">
<input type="submit" id="input">
</div>
<script type="text/javascript">
const btn = document.getElementById("input")
btn.addEventListener("click", debounce(submit), false)
function debounce(fn, timer) {
let t = null
return function() {
let firstClick = !t
if (t) { clearTimeout(t) }
if(firstClick) { fn() }
t = setTimeout(() => {
t = null
}, timer)
}
}
function submit() {
console.log(1)
}
</script>
</body>
Vue中的防抖
<template>
<div id="app">
<input type="text" placeholder="请输入手机号码"
v-model="val" @keyup="check"/>
<div class="box" v-show="statu==true">
您输入的手机号码格式正确</div>
</div>
</template>
<script>
import {debouce} from 'common/utils'
export default {
methods: {
// check是我们绑定的输入框的@keyup事件,注意这里不能是函数,
// 不然不会触发,必须要是对象
check: debounce(function(){
this.handle()
}),
handle() {
let reg = /^1[3|4|5|7|8][0-9]{9}$/;
if(reg.test(this.val)){
this.statu=true;
}
}
}
}
</script>
export function debounce(fn, delay = 100) { //默认100毫秒
let timer;
return function() {
if(timer) { clearTimeout(timer) }
timer = setTimeout(() => {
// 定时器必须要更改this指向,可以用apply、bind、
// 或者上面用变量转换等方式来进行更改this指向
fn.apply(this); // this 指向vue
}, delay);
};
}
四、节流
规定一个单位时间,在这个单位时间内,只能有一次触发事件的回调函数执行,如果在同一个单位时间内某事件被触发多次,只能有一次能生效。(一个函数可以在短时间内被调用的次数);应用场景:
- 鼠标连续不断地触发某事件(如点击),在单位时间内只触发一次;
- 在页面的无限加载场景下,需要用户在滚动页面时,每隔一段时间发一次ajax请求,而不是在用户听下滚动页面操作时,才去请求数据;
- 监听滚动时间,比如是否滑到底自动加载更多
const btn = document.getElementById("input")
btn.addEventListener("click", throttle(submit, 1000), false)
function throttle(fn, delay) {
let begin = 0
return function() {
let cur = new Date().getTime()
if (cur - begin > delay) {
fn(arguments)
begin = cur
}
}
}
function submit(e) {
console.log(e)
}