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

Vue3中blur触发emit更新对象后表单Tab切换失效问题求助

解决Vue3中子组件blur更新父组件ref导致Tab切换失效的问题

问题原因

你遇到的Tab键切换失效,本质是父组件直接替换了connection对象的引用,导致子组件的props.connection发生引用变化,触发子组件完全重渲染——原来的输入框DOM被销毁重建,自然丢失了焦点。同时子组件内部的a/b/c ref仅在初始化时赋值,未与后续props更新同步,还会引发数据不一致问题。

解决方案

1. 父组件更新对象属性而非替换整个对象

修改父组件的change函数,用Object.assign修改现有对象的属性,保持对象引用不变。这样Vue的响应式系统只会检测到属性变化,不会触发子组件的完全重渲染:

// Parent.vue
<script setup>
import { ref } from 'vue'
import Child from './Child.vue'
// 初始化空对象而非null,避免可选链的冗余判断
const connection = ref({})

const change = (updated) => {
    // 更新现有对象的属性,保留原引用
    Object.assign(connection.value, updated)
}
</script>
<template>
    <Child :connection="connection" @update="change" />
</template>

2. 子组件监听props变化同步内部状态

子组件通过watch监听props.connection的变化,同步内部状态,确保数据与props一致,同时避免重渲染丢失焦点:

// Child.vue
<script setup>
import { ref, watch } from 'vue'

const props = defineProps({
    connection: {
        type: Object,
        default: () => ({}) // 给默认值,避免可选链判断
    },
})

const emit = defineEmits(['update'])

// 用单个ref对象管理所有表单字段,减少重复代码
const formData = ref({ ...props.connection })

// 监听connection的属性变化,同步内部表单状态
watch(props.connection, (newConn) => {
    Object.assign(formData.value, newConn)
}, { deep: true, immediate: true }) // deep监听对象属性,immediate确保初始化时同步数据

const update = () => {
    emit('update', { ...formData.value })
}
</script>
<template>
    <input v-model="formData.a" @blur="update" />
    <input v-model="formData.b" @blur="update" />
    <input v-model="formData.c" @blur="update" />
</template>

方案优势

  • 父组件无需处理单个字段,仍保持“子组件统一emit整个对象”的简洁性;
  • 保持connection对象引用不变,子组件不会触发完全重渲染,输入框DOM节点得以保留,焦点状态自然维持;
  • 通过watch同步props与内部状态,确保父子组件数据一致性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 17:05:16