You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Vue计算属性中启用输入字段的loading状态?

如何在计算属性中启用输入字段的loading状态?

在演示示例中,遇到错误提示:unexpected side effect in "inputFilterParentsAndChilds" computed property.

搜索字段与列表代码

<template>
    <q-input
        label="Search"
        v-model="searchValue"
        placeholder="Minimum 3 characters"
        :loading="loadingState"
    />

    <q-list
      v-for="pater in inputFilterParentsAndChilds"
      :key="pater.id_parent"
    >
      <q-item>
        <q-item-section>
          <q-item-label>
            {{ pater.name }}
          </q-item-label>
        </q-item-section>
      </q-item>

        <q-list
        v-for="filius in pater.allfilius"
        :key="filius.id_filius"
        >
        <q-item>
            <q-item-section>
            <q-item-label>
                {{ filius.title }}
            </q-item-label>
            </q-item-section>
        </q-item>
        </q-list>
    </q-list>
</template>

原计算属性代码(存在问题)

<script>
export default {
  data() {
    return {
      loadingState: false,
      searchValue: ''
    };
  }
}

computed: {
    // 筛选包含嵌套子数据的父级列表
    inputFilterParentsAndChilds() {
      if (this.searchValue.length > 2) {

        this.loadingState = true; // 错误来源:计算属性中产生了意外副作用

        const filteredPaterArr = this.records.map((rows) => {          
          const filteredParent = rows.filius.filter(
            ({ name }) =>
               name.toLowerCase().match(this.searchValue.toLowerCase())
          );

          const filteredChilds = rows.filius.filter(
            ({ title }) =>
              title.toLowerCase().match(this.searchValue.toLowerCase())
          );

          if (filteredChilds.length) {
            this.loadingState = false;
            return { ...rows, filius: filteredParent };
          } else {
            this.loadingState = false;
            return { ...rows, filius: filteredChilds };
          }
        });

        return filteredPaterArr.filter((obj) => obj.filius.length);
      } else {
        return this.records;
      }      
    }
}
</script>

需求背景

当列表包含数百条记录时,筛选操作会变慢,页面看似卡顿,需通过loading状态告知用户筛选正在进行。

解决方案

Vue的计算属性设计为纯函数,仅依赖响应式数据返回结果,不能直接修改组件状态(比如赋值this.loadingState),这就是错误提示的原因。正确的做法是将loading状态的控制逻辑移到监听器中,保持计算属性的纯特性:

修改后的脚本代码

<script>
export default {
  data() {
    return {
      loadingState: false,
      searchValue: '',
      records: [] // 替换为你的实际数据源
    };
  },
  watch: {
    searchValue(newVal) {
      if (newVal.length > 2) {
        this.loadingState = true;
        // 利用$nextTick确保筛选完成后再关闭loading,适配同步计算场景
        this.$nextTick(() => {
          this.loadingState = false;
        });
      } else {
        this.loadingState = false;
      }
    }
  },
  computed: {
    inputFilterParentsAndChilds() {
      if (this.searchValue.length > 2) {
        const filteredPaterArr = this.records.map((rows) => {          
          const filteredParent = rows.filius.filter(
            ({ name }) =>
               name.toLowerCase().includes(this.searchValue.toLowerCase())
          );

          const filteredChilds = rows.filius.filter(
            ({ title }) =>
              title.toLowerCase().includes(this.searchValue.toLowerCase())
          );

          return { 
            ...rows, 
            filius: filteredChilds.length ? filteredParent : filteredChilds 
          };
        });

        return filteredPaterArr.filter((obj) => obj.filius.length);
      } else {
        return this.records;
      }      
    }
  }
}
</script>

关键调整说明

  • 将loadingState的赋值逻辑从计算属性移到watch监听器中,规避副作用问题
  • 用includes替代match,更适合简单的字符串模糊匹配(若需正则匹配可保留match)
  • 通过$nextTick确保筛选逻辑执行完成后再关闭loading,保证状态显示的准确性

内容的提问来源于stack exchange,提问作者jose

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 09:31:31