如何在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
相关产品推荐
相关产品推荐

