vue3 在 store里取值,赋值给dialog表单,为什么无效?

如下代码片断,使用onMounted或是watch给表单input赋值都无效,直接用projectStore.currentProject可以显示。
问题出在哪里?

原因已经找到,在下面

1.dialog 片断:

                    <el-dialog :title="titleServerList" v-model="openServerList" width="800px" append-to-body>
                      <el-form ref="serverdetailRef" :model="dataServerList.formServerList" :rules="rulesServerList" label-width="180px">
                        <el-form-item label="项目ID" prop="projecId">
                          <el-input v-model="formServerList.projecId" disabled/>
                        </el-form-item>
                         // ... ... 
                      </el-form>
                      <template #footer>
                        <div class="dialog-footer">
                          <el-button type="primary" @click="submitFormServerList">确 定</el-button>
                          <el-button @click="cancelServerList">取 消</el-button>
                        </div>
                      </template>
                    </el-dialog>
  1. dataServerList 片断:
const dataServerList = reactive({
  formServerList: {
    projecId: null,
  }
});

const { formServerList } = toRefs(dataServerList);
  1. 赋值片断:
watch(
  () => projectStore.currentProject,
  (newVal) => {
    console.log('Watch 监听:', newVal)  //打印成功取到值
    formServerList.projecId = newVal; 
    //dataServerList.formServerList.projecId = newVal; // 直接修改响应式对象也不行
  },
  { immediate: true } 
)

或者用 

onMounted(() => {
    formServerList.projecId = projectStore.currentProject
})
  1. 直接用store赋值可以 ( projectStore.currentProject):
<el-dialog :title="titleServerList" v-model="openServerList" width="800px" append-to-body>
                      <el-form ref="serverdetailRef" :model="dataServerList.formServerList" :rules="rulesServerList" label-width="180px">
                        <el-form-item label="项目ID" prop="projecId">
                          <el-input v-model="projectStore.currentProject" disabled/>
                        </el-form-item>
阅读 1.4k
3 个回答

问题的原因是在执行打开弹窗函数时,进行了表单重置,watch赋的值被清空了。避免清空 或是清空后再赋值 都可以,如下:

/** 新增按钮操作 */
function handleAdd() {
  reset();
  open.value = true;
  title.value = "添加项目用户维护";
  data.form.projecId = projectStore.currentProject; // 直接修改响应式对象
}
function reset() {
  const currentProjecId = form.value.projecId; // 先获取当前值
  form.value = {
    projecId: currentProjecId || null,
    userId: null,
    delFlag: null,
    createBy: null,
    createTime: null,
    updateBy: null,
    updateTime: null
  };
  proxy.resetForm("ProjectUserRef");
}

表单里绑定的是 formServerList.projecId,但 v-model 绑定的是 formServerList 的 toRefs 解构结果,看起来能访问 formServerList.projecId,但其实 formServerList 是一个 ref,而不是响应式对象本身,你不能再 formServerList.projecId = xxx 这么用,表单绑定的 model 和赋值用的 ref 对象其实不同步,Element Plus 不会知道你改了值它不会触发更新。

<el-form :model="dataServerList.formServerList">
<el-form-item label="项目ID" prop="projecId">
<el-input v-model="dataServerList.formServerList.projecId" disabled />
</el-form-item>
</el-form>

问题本质:

<el-form> 绑定的 model 是 dataServerList.formServerList,但你使用的是 toRefs(dataServerList) 解构出来的 formServerList,而这只是一个 ref,不是原始对象本身。你之后对 formServerList.projecId 的赋值并没有真正修改 dataServerList.formServerList.projecId,因此 <el-form> 并未感知到变化。

看起来是响应式的但实际不是

toRefs 会将对象的每一个属性包装成一个 ref,你拿到的 formServerList 是 Ref<{ projecId: null }>,但表单组件是直接监听 dataServerList.formServerList 的属性变化。

改正:

watch(
  () => projectStore.currentProject,
  (newVal) => {
    console.log('Watch 监听:', newVal);
    dataServerList.formServerList.projecId = newVal; // 正确写法
  },
  { immediate: true }
)

//或者

onMounted(() => {
  dataServerList.formServerList.projecId = projectStore.currentProject; //正确写法
});
推荐问题