Vue监听器设置枚举变量时v-if更新异常问题
Vue中v-if对特定枚举值判定异常问题
问题现象
在Vue 3 + TypeScript的单文件组件中,通过监听器监听game.notation更新当前回合玩家whoseTurn(类型为枚举Color)。当回合切换到玩家A时,模板中v-if="whoseTurn"判定为假,页面显示"No turn",但控制台日志明确显示whoseTurn已被正确设置为Color.A,且其他玩家(B/C/D)的回合都能正常显示。
组件代码
<script lang="ts"> // imports ... export default defineComponent({ data() { return { store, api: new Api(Constants.baseUrl), game: null as (Game | null), playerIcons: Constants.playerIcons, gameId: this.$route.params.id as string, poller: null as number | null, whoseTurn: null as Color | null, }; }, methods: { async pollGame(): Promise<void> { try { this.game = await this.api.readGame(this.gameId); // snip } catch (error) { alert(error); } }, colorToNotation(color: Color): string | null { if (color === Color.A) { return "A"; } else if (color === Color.B) { return "B"; } else if (color === Color.C) { return "C"; } else if (color === Color.D) { return "D"; } return null; }, notationToColor(notation: string): Color | null { if (notation === 'a') { return Color.A; } else if (notation === 'b') { return Color.B; } else if (notation === 'c') { return Color.C; } else if (notation === 'd') { return Color.D; } return null; } }, async mounted() { this.pollGame(); this.poller = setInterval(this.pollGame, Constants.pollingInterval); }, unmounted() { if (this.poller) { clearInterval(this.poller!); } }, watch: { 'game.notation'(newValue) { // snip const playerNotation: string = newValue[newValue.length - 1]; let previousTurn: Color | null = this.whoseTurn; this.whoseTurn = this.notationToColor(playerNotation); console.log(`Set turn from ${this.colorToNotation(previousTurn!)} to ${this.colorToNotation(this.whoseTurn!)}`); } } // snip }); </script> <template> <!-- snip --> <div v-if="game"> <div id="whose-turn" v-if="whoseTurn"> Turn: <img class="player-icon" :src="playerIcons.get(whoseTurn)" /> {{ game.getPlayer(whoseTurn)!.name }} </div> <div v-else> No turn </div> <!-- snip --> </div> <!-- snip --> </template>
控制台日志
Set turn from null to A Set turn from A to B Set turn from B to C Set turn from C to D Set turn from D to A Set turn from A to B Set turn from B to C Set turn from C to D Set turn from D to A ...
页面显示
No turn Turn: B Turn: C Turn: D No turn Turn: B Turn: C Turn: D ...
问题原因
核心问题出在TypeScript数值枚举的默认取值:如果你的Color枚举是默认定义的(未手动指定值),那么Color.A的数值是0,而Vue模板中的v-if会将0视为布尔假值(JavaScript中0、''、null、undefined、NaN都是假值)。其他枚举值B/C/D默认是1、2、3,会被判定为真值,所以能正常显示。
解决方案
方案1:修改枚举起始值
将Color枚举的起始值设为1,避免0的出现:
enum Color { A = 1, B, // 自动为2 C, // 自动为3 D // 自动为4 }
方案2:修改v-if判定条件
如果无法修改枚举定义,直接在模板中明确检查whoseTurn是否不为null,而不是依赖自动类型转换:
<div id="whose-turn" v-if="whoseTurn !== null">
方案3:使用字符串枚举
改用字符串枚举,确保所有枚举值都是非空字符串,不会被判定为假值:
enum Color { A = 'A', B = 'B', C = 'C', D = 'D' }
内容的提问来源于stack exchange,提问作者MartenBE
相关产品推荐
相关产品推荐

