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

Vue3中ESLint报no-mutating-props错误是否为误报?

Vue3中v-model绑定prop子属性触发ESLint警告的原因分析

问题场景

在Vue3项目中,尝试用v-model绑定父组件props中objVehicle的engine_options属性时,ESLint抛出警告:

Unexpected mutation of "objVehicle" prop.eslint(vue/no-mutating-props)

尝试两种父组件写法都无法消除警告,需求是按需创建objVehicle的engineOptions属性,相关代码如下:

父组件代码1

<template>
    <div>
        <ChildComponent
            v-model:engineOptions="objVehicle.engine_options"
            @update:engineOptions="emit('update:objVehicle', objVehicle)"
        />
    </div>
</template>
<script setup lang="ts">
import ChildComponent from "@....vue"

const props = defineProps({
    objVehicle: {
        type: Object,
        required: true,
    }
})

const emit = defineEmits(['update:objVehicle'])
</script>

父组件代码2

<template>
    <div>
        <ChildComponent
            v-model:objVehicle="objVehicle"
            @update:objVehicle="(event) => emit('update:objVehicle', event)"
        />
    </div>
</template>
<script setup lang="ts">
import ChildComponent from "@....vue"

const props = defineProps({
    objVehicle: {
        type: Object,
        required: true,
    }
})

const emit = defineEmits(['update:objVehicle'])
</script>

子组件代码

<template>Form elements for the engineOptions property are placed here...</template>

<script setup lang="ts">
const props = defineProps({
    engineOptions: {
        type: Object,
        required: false, // create on-demand
    },
})

const emit = defineEmits(['update:engineOptions'])

const initEngineOptions = async () => {
    if (!Array.isArray(props.engineOptions)) {
        emit('update:engineOptions', [])
    }
}

const engineOptions = computed({
    get() {
        return props.engineOptions as TEngineOptions[]
    },
    set(newVal: TEngineOptions[] | undefined) {
        emit('update:engineOptions ', newVal)
    },
})

// Remove self
const atRemove = () => {
    engineOptions.value = undefined
}
</script>

警告并非误报,原因如下

ESLint的vue/no-mutating-props规则核心是禁止直接修改props本身或其引用类型的子属性,这是为了遵循Vue的单向数据流原则:props只能由父组件传递更新,子组件不能直接修改。

你的两种写法都触发了规则检测:

  1. 父组件1:v-model:engineOptions="objVehicle.engine_options"本质是语法糖,展开后相当于:engineOptions="objVehicle.engine_options" @update:engineOptions="objVehicle.engine_options = $event",这里直接修改了objVehicle(父组件的props)的子属性engine_options,属于修改引用类型props的内部状态,违反单向数据流。后续的emit('update:objVehicle', objVehicle)只是把已经被修改的原props对象传回父组件,并没有解决直接修改props的问题。
  2. 父组件2:v-model:objVehicle="objVehicle"直接把props对象绑定给子组件,子组件修改objVehicle的engineOptions属性时,同样是直接修改了父组件传入的props对象,触发规则警告。

解决方案:转成本地响应式对象处理

要解决这个问题,父组件需要先把props的objVehicle复制为本地的响应式对象,操作本地对象后再emit新的对象给父组件更新,避免直接修改props:

<template>
    <div>
        <ChildComponent
            v-model:engineOptions="localVehicle.engine_options"
            @update:engineOptions="handleUpdateEngine"
        />
    </div>
</template>
<script setup lang="ts">
import ChildComponent from "@....vue"
import { reactive } from 'vue'

const props = defineProps({
    objVehicle: {
        type: Object,
        required: true,
    }
})

const emit = defineEmits(['update:objVehicle'])

// 将props对象复制为本地响应式对象,避免直接修改props
const localVehicle = reactive({ ...props.objVehicle })

const handleUpdateEngine = (newEngineOptions: TEngineOptions[] | undefined) => {
    localVehicle.engine_options = newEngineOptions
    // 传递新对象给父组件,而不是原props引用
    emit('update:objVehicle', { ...localVehicle })
}
</script>

这样修改后,所有对engine_options的操作都是基于本地响应式对象,不会直接修改父组件传入的props,ESLint的警告会自动消除,同时符合Vue的单向数据流规范。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 14:32:42