el-select下拉框懒加载以及搜索联合处理+搜索防抖处理

前言

本文采主要用了自定义指令结合绑定滚动条事件的方式

问题描述

现有一个页面,充斥着大量表单元素,首先要知道的是vue对于视图上的更新机制,在一个组件内若有元素发生变动,那么整个组件就会刷新渲染,所以将大量的表单元素放在一个组件内是会造成页面卡顿的现象。如果有下拉框一次性加载大量数据的情况,这个现象会格外的明显。虽然说将表单分割成多个组件会有帮助,但是效果不会很大,必须要解决下拉框一次性加载了大量元素这个根源问题。由于element自身没有对于下拉框(el-select)做懒加载的处理(也可以和element-ui的InfiniteScroll(无限滚动)联合处理),所以就需要我们自己手动实现。

需求

  1. 默认展示20条
  2. 滚动到底部再加载20条或剩余数据
  3. 同时支持搜索,(符合搜索条件的数据也要支持滚动加载)
  4. 无论是滚动加载还是搜索出的数据只加载一次,不做重复加载
  5. 搜索需要做防抖处理,来尽量避免不必要的搜索操作
一、自定义指令完成滚动加载的功能

1.第一步:在自定义指令中绑定滚动事件触发执行加载数据方法

directives: {
    "el-select-loadmmore": {
      bind (el, binding) {
        // 因为el-select最终会渲染成ul  li  ,所以我们要找到对应的ul元素节点,因为最底层的滚动条就是这个ul的
        const SELECTDOM = el.querySelector('.el-select-dropdown .el-select-dropdown__wrap')
        // 为对应的ul绑定滚动条滚动事件
        SELECTDOM.addEventListener('scroll', function () {
          const condition = this.scrollHeight - this.scrollTop == this.clientHeight
          // 判断滚动到底部
          if (condition) {
          // binding.value 为自定义指令绑定的值,因为绑定的是个方法,所以这里是方法调用,触发指令后执行加载数据
            binding.value()
          }
        })

      }
    }
  },

利用自定义指令就可以针对性的对使用了指令的el-select组件处理懒加载。
2.第二步:加载数据的方法

props: {
    seleteOptions: {
      type: Array,
      default: function () {
        return []
      }
    }
  },
data () {
    return {
      seVal: '',
      
      initOption:[], // 满足筛选条件的val集合
      filterVal: '', // 搜索条件
      filterArray:[],  // 所有可展示的数据 (符合搜索条件 && newData没有的数据)
      newData: [],  // 正在展示的数据或展示过的数据
    }
},
mounted () {
    this.filterArray = [...this.seleteOptions]
    // 初始时加载一次
    this.loadmore()
},
methods: {
    // 滚动加载
    loadmore () {
      const oldArray = this.filterArray  // 可展示预备数据
      const newArray = this.newData        // 展示的数据
      let pushArray = []                 // 新增的数据

      // 当加载完毕时 直接退出方法
      if (newArray.length === oldArray.length) return

      // 当剩余要加载的不足20个时  则加载全部的
      if (newArray.length + 20 > oldArray.length) {
        pushArray = oldArray.slice(0)
        this.filterArray.splice(0)
      } else {
        pushArray = oldArray.slice(0,20)
        this.filterArray.splice(0,20)
      }
      // 搜索后展示的数据
      this.newData = [...newArray, ...pushArray]
    },
}

loadmore方法每次执行都会从预备数据中拿取20条或者剩余数据
3.第三步:自定义搜索方法

filterMethod (params) {
      // 记录下搜索条件
      this.filterVal = params

      // 搜索方法
      let vals = []
      let filterArray = []
      this.seleteOptions.forEach((item, i) => {
        // 有搜索条件时  查找符合条件的
        if (params && item.label.includes(params)) {
          // 添加所有符合搜索条件的val值
          vals.push(item.value)
          // 寻找符合搜索条件且newData中没有出现过的数据
          if(!this.newData.find(fin=>fin.value === item.value)){
           filterArray.push(item)
          }
        }else if(!params){  // 无搜索条件时  获取所有剩余newData中没有出现过的数据
          if(!this.newData.find(fin=>fin.value === item.value)){
           filterArray.push(item)
          }
        }
      })
      
      this.initOption = [...vals]
      this.filterArray = [...filterArray]

      this.loadmore()
      
    }

因为要搜索和懒加载结合使用,所以就需要自定义搜索方法结合到懒加载的数据使用,做一些逻辑处理。

4.第四步 搜索的防抖处理

computed: {
    // 防抖
    filterMethodThrottle(){
      var time = null
      return (param)=>{
        if(time){
          clearTimeout(time)
        }
        time = setTimeout(()=>{
          // 搜索方法
            this.filterMethod(param)
            clearTimeout(time)
        },2000)
      }
    }
  }

组件使用

<el-select v-model="seVal"
               filterable
               placeholder="请选择"
               v-el-select-loadmmore="loadmore"
               :filter-method="filterMethodThrottle">
      <el-option v-for="(item, i) in newData"
                 :label="item.label"
                 :value="item.value"
                 v-show="!filterVal || initOption.includes(item.value)"
                 :key="i + 'region2'">
      </el-option>
    </el-select>

测试数据
将测试数据传给props中的

[
	{
		label:'第一项',
		value:'1'
	},...
]

至此element的懒加载联合搜索就结束了

问题

一、使用v-infinite-scroll(无限滚动)

v-infinite-scroll是element的一个滚动加载数据的一个自定义指令,但是需要注意的是,这个指令是需要直接作用在可滚动的父元素上的,就像官方的例子

 <ul class="infinite-list" v-infinite-scroll="load" style="overflow:auto">
    <li v-for="i in count" class="infinite-list-item">{{ i }}</li>
  </ul>

这里的ul是一个内部有滚动条可滚动的元素,但是我们如果想给el-select使用的话会发生什么事情,废话不多说,上示例
1.首先给el-select一个类名

在这里插入图片描述
2.我们来看渲染的dom节点
在这里插入图片描述
但是值得注意的是,像emement-ui都会在组件内部有插槽的设置,这里利用默认插槽也是可以解决这个问题的

二、防抖与节流

首先我们只需要了解防抖和节流主要是解决什么问题的,它们采取的手段虽然不同,

防抖可以简单理解为在频繁的操作中,我只触发间隔达到规定的那一次

节流可以简单理解为不管你多频繁的操作,我就按照我规定的间隔去触发

归根结底两者都是在对控制触发频率这块做文章,只要理解这个思想,就不难实现。

首先给大家看一段简单的防抖代码:

其实事件每触发一次,用于防抖处理的方法也是都要执行一次的,只不过是将逻辑代码封装进了handle函数中,然后控制handle函数的触发频率。那么由此看来,如果能做到控制逻辑代码块的执行频率是不是也算是变相的防抖处理?
1.滚动事件的处理
在这里插入图片描述
2.搜索事件的处理
搜索事件因为无法利用代码限制判断出应该在哪一瞬间执行事件函数,所以就需要做防抖处理,做个2秒的防抖,这样如果用户是一个字一个字的输入,就不会频繁的在每一次输入字符都要执行一次函数,若超过2秒,则认为用户输入完毕,执行事件函数

结束语

如有理解的不对的地方,还望多多包涵,本意只在记录问题。

防抖是一种常用的前端技术,它可以有效地降低函数的执行频率,从而提升页面的性能和体验。在 Vue 中实现搜索按钮防抖,常用的方式是使用 debounce 函数。debounce 函数会延迟一段时间执行函数,如果在延迟期间再次触发函数,就会重新计时,直到延迟期结束,才会执行函数。这样就可以避免短时间内频繁触发函数,从而降低服务器压力。 下面是一个使用 debounce 函数实现搜索按钮防抖的示例: ``` <template> <div> <input type="text" v-model="keyword"> <button @click="debounceSearch">搜索</button> </div> </template> <script> import { debounce } from 'lodash' export default { data() { return { keyword: '', delay: 500 // 延迟时间,单位毫秒 } }, methods: { debounceSearch: debounce(function () { // 实际执行的搜索函数 console.log('搜索关键字:', this.keyword) }, this.delay) } } </script> ``` 在上面的示例中,使用了 lodash 库的 debounce 函数。在 methods 中定义了 debounceSearch 函数,它会在点击搜索按钮时触发。debounceSearch 函数会调用 debounce 函数,将实际执行的搜索函数作为参数传入,并指定延迟时间为 this.delay。这样,每次点击搜索按钮时,都会执行 debounceSearch 函数,但实际执行的搜索函数会在延迟期结束后才会执行。如果在延迟期内再次点击搜索按钮,就会重新计时,直到延迟期结束后执行搜索函数。
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值