前言
今天讲解的主题是在vue中正确使用防抖和节流,先和大家再解释下什么是防抖什么是节流。防抖好比生活中乘坐升降电梯时,你进去了,门需要等两秒才会关门,过去了一秒多的时候,又有人进来了,此时又重新计时两秒,等两秒内没人进来时,才会关门。节流好比玩《王者荣耀》游戏时,攻击速度并不会随着你平A的速度变快而更快,而是按正常该英雄的攻击速度来攻击。这就是即使你手速很快,但是他也只是按正常的攻速攻击,这就是节流。
更通俗的讲就是:
1.防抖犹如 英雄回城,被打断了就得重新花时间回城。
2.节流犹如 技能冷却,得冷却时间到了,才能重新释放技能。
代码
防抖及节流相关代码可查阅 js中防抖与节流的封装
主测试代码如下:
<template>
<div ref="container" class="app-container">
<van-sticky class="search-wrap">
<van-search
:round="false"
input-align="left"
v-model="params.unitName"
placeholder="请输入搜索关键词"
@input="handleSearch"
>
</van-search>
</van-sticky>
<van-pull-refresh
:class="['content-wrap', refreshing ? 'refreshing' : '']"
v-model="refreshing"
@refresh="onRefresh"
>
<van-list
v-model="loading"
:finished="finished"
:finished-text="list.length === 0 ? '' : '没有更多了'"
@load="onLoad"
>
<div
class="news-item"
@click="handleSelectItem(item)"
v-for="(item, index) in list"
:key="index"
>
<p class="news-title xz-ellipsis">{{ item.unitName }}</p>
<p class="time-box flex-c-b">
<span class="danwei">{{ item.index }}</span>
<span class="time">{{ item.time }}</span>
</p>
</div>
<van-empty
class="no-result"
description="未查询到相关信息,下拉可重新查询"
v-show="list.length === 0 && !refreshing && !loading"
/>
</van-list>
</van-pull-refresh>
</div>
</template>
<script>
import {debounce} from "@/utils/common"
export default {
data() {
return {
handleSearch: debounce(this.onRefresh, 1000),
showSearch: false,
params: {
unitName: "", // 搜索关键字
page: 0, //页数
size: 20 //每行页数
},
list: [],
loading: false,
finished: false,
refreshing: false,
baseForm: {
unitName: "" // 微信公众号
}
}
},
methods: {
handleSelectItem(item) {
this.baseForm.unitName = item.unitName
this.showSearch = false
},
onLoad() {
this.params.page++
this.getListApi(this.params).then((data) => {
if (this.refreshing || this.isSearch) {
this.list = []
this.refreshing = false
this.isSearch = false
}
this.list = this.list.concat(data.list)
this.loading = false
if (this.list.length >= data.total) {
this.finished = true
}
})
},
onRefresh() {
this.$refs.container.scrollTop = 0
this.isSearch = true
// 清空列表数据
this.finished = false
// 重新加载数据
// 将 loading 设置为 true,表示处于加载状态
this.loading = true
this.params.page = 0
this.onLoad()
},
//模拟接口
getListApi(params) {
console.log("调用了查询接口,查询页码为:")
console.log(params.page)
return new Promise((resolve, reject) => {
setTimeout(() => {
const data = []
const total = 50
for (let i = 0; i < params.size; i++) {
if ((params.page - 1) * params.size + i < total) {
data.push({
index: i + (params.page - 1) * params.size,
url: "/consultation-detail",
unitName: "关注微信公众号【爆米花小布】,提升前端开发效率",
time: "2022-09-16 20:00:00"
})
} else {
continue
}
}
resolve({
list: data,
total: total
})
}, 500)
})
}
}
}
</script>
<style lang="less" scoped>
.app-container {
position: relative;
height: 100vh; // 关键
overflow: auto; // 关键
padding: 0;
// 搜索容器
.search-wrap {
width: 100%;
background-color: #fff;
z-index: 9999;
position: relative;
border-bottom: 1px solid #eee;
// 堆代码 duidaima.com
// 优化条件搜索样式
/deep/ .van-dropdown-menu__bar {
height: 40px;
box-shadow: none;
.van-dropdown-menu__title {
color: #212121;
font-size: 14px;
}
}
.main-text {
color: #4077f4;
}
}
// 内容列表容器
.content-wrap {
padding: 16px;
min-height: calc(100vh - 45px);
&.refreshing {
// 解决下拉刷新时双加载动画问题
/deep/ .van-list__loading {
display: none;
}
}
/deep/ .van-empty__description {
padding: 0;
}
.news-item {
margin-top: 0 16px;
border-bottom: 1px solid #f9faf9;
&:last-child {
border: none;
}
.news-title {
font-size: 16px;
color: #333333;
line-height: 22px;
}
.time-box {
font-size: 14px;
color: #999999;
padding: 8px 0;
}
}
}
}
</style>
vue项目中使用防抖和节流
第一种:
模板中添加方法
<van-search
:round="false"
input-align="left"
v-model="params.unitName"
placeholder="请输入搜索关键词"
@input="handleSearch"
>
</van-search>
在data中定义该方法
data() {
return {
handleSearch: debounce(this.onRefresh, 1000)
}
},
onRefresh为防抖的逻辑方法
第二种:
模板中添加方法
<van-search
:round="false"
input-align="left"
v-model="params.unitName"
placeholder="请输入搜索关键词"
@input="handleSearch"
>
</van-search>
在methods中添加如下代码
methods: {
handleSearch: debounce(function() {
this.onRefresh()
}, 1000),
}
一定要使用function() 不可使用箭头函数,onRefresh得加() 否则没调用到,不触发。
第三种:
在mixin中添加全局防抖方法
created() {
this.$debounce = debounce
},
模板中添加方法
<van-search
:round="false"
input-align="left"
v-model="params.unitName"
placeholder="请输入搜索关键词"
@input="handleSearch">
</van-search>
在页面中添加如下代码
created() {
this.handleSearch = this.$debounce(this.onRefresh, 1000)
},
节流同理。
防抖效果如下:
/**
*
* @param {*} func 防抖函数
* @param {*} wait 等待时长(毫秒)
* @param {*} immediate 是否先立即触发一次
* @returns
*/
function debounce(func, wait = 300, immediate = false) {
let timer = null
return function(...arg) {
if (timer !== null) {
clearTimeout(timer)
} else if (immediate) {
func.apply(this, arg)
}
timer = setTimeout(() => {
func.apply(this, arg)
timer = null
}, wait)
}
}
节流效果如下
/**
*
* @param {*} func 节流函数
* @param {*} wait 等待时长(毫秒)
* @param {*} immediate 是否先立即触发一次
* @returns
*/
function throttle(func, wait = 300, immediate = false){
let last, timer
return function(...arg) {
const now = +new Date()
// 堆代码 duidaima.com
if (last && now < last + wait) {
clearTimeout(timer)
timer = setTimeout(function() {
func.apply(this, arg)
}, wait) //停止触发 后wait毫秒立即执行
} else {
if (!immediate) {
if (last) {
func.apply(this, arg)
}
} else {
func.apply(this, arg)
}
last = now
}
}
}
此节流方法超过了传统定义的节流,因为在wait秒后没触发事项时也会最后再执行一下回调函数。
总结
这就是防抖和节流在vue项目中的使用方式,并附上了防抖和节流封装好的方法,有兴趣的自取。