Vue3 父组件引用子组件并控制子组件显隐及数据传递

子组件 UserFormDialog.vue

<!-- 用户新增和修改组件 -->
<template>
  <!-- 弹窗 -->
  <el-dialog v-model="visible" :title="title" width="60%" @close="handleClose">
    <el-form ref="dataFormRef" :model="formData" :rules="rules" label-width="80px">      
      ......
    </el-form>

    <template #footer>
      <div class="dialog-footer">
        <el-button type="primary" :loading="loading" @click="handleSubmit">确 定</el-button>
        <el-button @click="handleClose">取 消</el-button>
      </div>
    </template>
  </el-dialog>
</template>

<script setup>
import {ref, reactive, watch, nextTick} from 'vue'
import { ElMessage } from 'element-plus'

// 1.使用 Vue 3.4+ 的 defineModel 定义了一个名为 visible 的双向绑定变量。父组件通过 v-model 传入该值,子组件修改它会自动同步到父组件,常用于控制弹窗显示/隐藏
const visible = defineModel({
  type: Boolean,
  default: false
})

// 定义属性
const props = defineProps({
  // 弹窗类型 add: 新增 edit: 修改
  title: {
    type: String,
    default: ''
  },
  // 表单数据
  initData: {
    type: Object,
    default: () => ({})
  }
})

// 2.定义事件
const emit = defineEmits(['success'])

const loading = ref(false)
const dataFormRef = ref()

// 本地表单数据(用于双向绑定和验证)
const formData = reactive({});

// 表单校验
const rules = {
  ......
};
// 监听外部传入的显示状态,当 visible 为 true 时填充表单数据
watch(visible, (val) => {
  if (val) {
    // 打开时填充表单数据
    nextTick(() => {
      Object.assign(formData, props.initData || {})
      dataFormRef.value.clearValidate()
    })
  }
})

// 关闭弹窗
const handleClose = () => {
  visible.value = false
}

// 提交表单
const handleSubmit = () => {
  dataFormRef.value.validate(async (valid) => {
    if (valid) {
      try {
        loading.value = true;
        const submitData = {...formData}
        // 新增或修改
        if (submitData.userId) {
          await UserAPI.update(submitData)
          ElMessage.success("修改成功");
        } else {
          await UserAPI.add(submitData)
          ElMessage.success("新增成功");
        }
        // 3.通知父组件刷新列表
        emit('success') 
        handleClose();
      } catch (error) {
        ElMessage.error(error?.message || '操作失败');
      } finally {
        loading.value = false;
      }
    }
  });
}
</script>

<style lang="scss" scoped>

</style>

父组件 index.vue

<template>
  <div class="app-container-row">
    <el-button type="success" icon="plus" @click="handleAddOrUpdate(undefined)">新增</el-button>
    <!-- 1.子组件 
        v-model="dialog.visible"  对应子组件的 const visible = defineModel({type: Boolean,  default: false})
        @success="handleQuery"    对应子组件的 const emit = defineEmits(['success']); emit('success') 
	-->
    <UserFormDialog
        v-model="dialog.visible"
        :title="dialog.title"
        :init-data="initFormData"
        @success="handleQuery"
    />
  </div>
</template>

<script setup>
import {onMounted, reactive, ref, toRaw} from 'vue'
import UserFormDialog from "@/views/system/user/UserFormDialog.vue";

/**
 * 定义组件名称:在调试工具(如 Vue DevTools)中会显示为组件名称,便于识别和调试
 * 支持<keep-alive>缓存
 */
defineOptions({
  name: 'User'
})

//==============用户表单=================
// 2.初始化子组件标题和显隐
const dialog = reactive({
  title: "",
  visible: false,
});

const defaultFormData = {
  userId: undefined,
  loginName: '',
  nickName: '',
  gender: 1,
  deptId: undefined,
  phone: '',
  email: '',
  remark: ''
}

const initFormData = reactive({ ...defaultFormData })

// 新增或修改页面
function handleAddOrUpdate(rowData) {
  ......
  dialog.visible = true;
}
    
// 查询
function handleQuery() {
  
}
</script>

<style lang="scss" scoped>

</style>
posted @ 2026-06-16 10:31  码农张3  阅读(1)  评论(0)    收藏  举报