一、问题

做搜索功能时,监听input的value值变化实时请求数据,每增加一个字符,就发送一次请求。例如输入12345,会监听到5次变化1 12 123 1234 12345,导致连续请求5次。这是没必要的,增加服务器负担,可能出现卡顿的情况。
甚至,一定概率下会发生请求返回顺序问题,当输入速度很快时,连续发请求,服务器可能先返回12345请求的结果,然后再返回12请求的结果,导致最后页面上显示的结果是12请求到的结果列表,而不是想要搜索的12345的结果。一定程度上降低这种情况。

二、想法

不希望input框中值一改变,就马上去请求数据,而是在指定间隔内没有输入时,才会执行函数。如果停止输入但是在指定间隔内又输入,会重新触发计时。这就是函数防抖。
实时监听input值的变化,输入一个字符,300ms后再去获取input中的输入值。

三、关键代码

<input ref="searchInput" v-model="inputVal" type="text" placeholder="搜索目的地" maxlength="20"/>
data() {
   return {
      inputVal: '',
      timeout: null,
   }
}

watch: {
    inputVal(curVal, oldVal) {
        // 实现input连续输入,只发一次请求
        clearTimeout(this.timeout);
        this.timeout = setTimeout(() => {
          this.getListPOI(curVal);
        }, 300);
    }
}

四、再优化,解决异步请求可能发生先请求后返回问题,导致结果列表不是预料展示的效果

假如300ms的延迟,服务器还是可能存在先发送的请求后返回。避免先请求后返回问题,确保以当前输入的值12345为参数给结果表赋值,可以在请求里做判断。当请求返回结果时,判断请求的参数inputVal和当前输入框的值this.inputVal相等,才进行相关操作:if (this.inputVal === inputVal) {...}

methods:{
      /**
       * poi模糊搜索列表
       */
      async getListPOI(inputVal) {
        if (inputVal === '') {
          return false;
        }
        this.searchPoi = [];
        this.divLoading = true;
        if (!navigator.onLine) { // 没有网络
          this.onLine = false;
          this.divLoading = false;
          return false;
        } else {
          this.onLine = true;
        }
        try {
          const res = await getListPOI({
            "buildId": this.$store.state.showBuildId,
            "coor": 1,
            "floorId": this.$store.state.showFloorId,
            "latitude": this.$store.state.userCurLoc[1] || 0,
            "longitude": this.$store.state.userCurLoc[0] || 0,
            "name": inputVal,
            "pageNum": 1,
            "pageSize": 30
          });
          if (this.inputVal === inputVal) { // 关键代码 避免先请求后返回问题,确保给列表赋值是以当前输入的值为参数的
            if (res.code === 0 && res.data) {
              let data = res.data;
              if (data.length === 0) {
                this.hasResult = false;// 没有结果
                this.searchPoi = [];
              } else { // 有结果
                this.hasResult = true;
                this.searchPoi = data;
              }
            } else {
              this.searchPoi = [];
              console.log("请检查/poi/list/POI接口返回的数据格式");
            }
            this.divLoading = false;
          }
        } catch (err) {
          this.divLoading = false;
          console.log("poi模糊搜索列表接口请求失败", err);
        }
      }
}

五、效果图

vue 监控input变化 vue监听input输入_搜索

参考:https://www.jianshu.com/p/3d23efcefb38