Vue3 Composition API动态CSS类引发递归更新超限警告求助
问题原因
你碰到的「Maximum recursive updates exceeded」警告,根源是setImgIcon函数里修改了全局的reduceSizeIcon响应式变量,而这个变量又绑定在模板的动态类上。每一次渲染<img>时,调用setImgIcon会更新reduceSizeIcon的值,触发组件重新渲染;重新渲染又会再次调用setImgIcon,形成无限循环,最终触发Vue的递归更新保护机制。
解决方法
核心思路是让每个列表项独立管理自己的图标和类名状态,不要用全局响应式变量共享状态,避免在模板调用的函数里修改响应式变量。
方案一:让函数返回包含图标地址和类名的对象
修改setImgIcon为返回包含src和className的对象,每个列表项获取自己的独立状态:
<script setup lang="ts"> import { ref } from "vue"; import { ISugerenciaGlobalStar } from "@/types/IMapas"; // 图标导入部分保持不变 import aviaFrance from '@/assets/AVIA FRANCE.svg' import petromiralles from '@/assets/PETROMIRALLES.svg' import andamur from '@/assets/ANDAMUR.svg' import cepsa from '@/assets/CEPSA.svg' import esso from '@/assets/ESSO.svg' import galp from '@/assets/GALP.svg' import nieves from '@/assets/NIEVES.svg' import q8 from '@/assets/Q8.svg' import repsol from '@/assets/REPSOL.svg' import shell from '@/assets/SHELL.svg' import texaco from '@/assets/TEXACO.svg' import valcarce from '@/assets/VALCARCE.svg' import eni from '@/assets/ENI.svg' import mtw from '@/assets/MTW.svg' import tpetromiralles from '@/assets/T-PETROMIRALLES.svg' import globalStar from '@/assets/web/logo-globalstar.png' const props = defineProps<{ sugerenciasGlobarStar: ISugerenciaGlobalStar[]; }>(); // 修改函数,返回包含src和类名的对象 function getIconInfo(marca: string): { src: string, className: string } { switch (marca) { case 'AVIA': case 'AVIA FRANCE': return { src: aviaFrance, className: "" }; case 'PETROMIRALLES': return { src: petromiralles, className: "" }; case 'T-PETROMIRALLES': return { src: tpetromiralles, className: "" }; case 'ANDAMUR': return { src: andamur, className: "" }; case 'CEPSA': return { src: cepsa, className: "" }; case 'ESSO': return { src: esso, className: "" }; case 'GALP': return { src: galp, className: "" }; case 'NIEVES': return { src: nieves, className: "" }; case 'Q8': return { src: q8, className: "" }; case 'REPSOL': return { src: repsol, className: "" }; case 'SHELL': return { src: shell, className: "" }; case 'TEXACO': return { src: texaco, className: "" }; case 'VALCARCE': return { src: valcarce, className: "" }; case 'ENI': return { src: eni, className: "" }; case 'MTW': return { src: mtw, className: "" }; default: return { src: globalStar, className: "mapIconSugerencias" }; } } </script>
模板部分可以用v-bind直接展开对象,更简洁:
<template> <v-card v-for="(objeto, key) in sugerenciasGlobarStar" elevation="6" class="mt-2 pa-2" :key="key"> <v-row justify="center" align="center" class="mr-0 ml-0"> <v-col cols="2" align="center"> <!-- 直接用v-bind展开返回的对象 --> <img v-bind="getIconInfo(objeto.marca)" /> </v-col> <!-- 其余模板内容保持不变 --> <v-col cols="10"> <v-card-item class="ma-0 pa-0 text-caption"> <template v-slot:prepend> {{ objeto.marca }} </template> <template v-slot:append> <v-icon v-if="objeto.favorito" color="amber-accent-4" class="mr-2 pb-2">mdi-star</v-icon> <span v-if="objeto.precio != '-'"> {{ objeto.precio + " €" }} </span> </template> </v-card-item> <v-divider></v-divider> <v-card-item class="ma-0 pa-0 text-caption"> <template v-slot:prepend> <span>{{ objeto.provincia }}</span> </template> <template v-slot:append> <span>{{ objeto.poblacion }}</span> </template> </v-card-item> </v-col> </v-row> </v-card> </template> <style scoped> .mapIconSugerencias { width: 100%; } </style>
方案二:拆分图标地址和类名的获取函数
如果不想修改函数返回结构,可以把获取图标地址和类名的逻辑拆成两个独立函数,避免在获取地址时修改全局变量:
<script setup lang="ts"> // ...导入部分不变 const props = defineProps<{ sugerenciasGlobarStar: ISugerenciaGlobalStar[]; }>(); // 单独获取图标地址 function getIconSrc(marca: string): string { switch (marca) { case 'AVIA': case 'AVIA FRANCE': return aviaFrance; case 'PETROMIRALLES': return petromiralles; case 'T-PETROMIRALLES': return tpetromiralles; case 'ANDAMUR': return andamur; case 'CEPSA': return cepsa; case 'ESSO': return esso; case 'GALP': return galp; case 'NIEVES': return nieves; case 'Q8': return q8; case 'REPSOL': return repsol; case 'SHELL': return shell; case 'TEXACO': return texaco; case 'VALCARCE': return valcarce; case 'ENI': return eni; case 'MTW': return mtw; default: return globalStar; } } // 单独获取类名 function getIconClass(marca: string): string { // 定义不需要加类的品牌列表 const normalBrands = ['AVIA', 'AVIA FRANCE', 'PETROMIRALLES', 'T-PETROMIRALLES', 'ANDAMUR', 'CEPSA', 'ESSO', 'GALP', 'NIEVES', 'Q8', 'REPSOL', 'SHELL', 'TEXACO', 'VALCARCE', 'ENI', 'MTW']; return normalBrands.includes(marca) ? "" : "mapIconSugerencias"; } </script>
模板部分分别调用两个函数:
<img :src="getIconSrc(objeto.marca)" :class="getIconClass(objeto.marca)" />
内容的提问来源于stack exchange,提问作者francesco14
相关产品推荐
相关产品推荐

