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

子组件 UserFormDialog.vue

html 复制代码
<!-- 用户新增和修改组件 -->
<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

html 复制代码
<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>
相关推荐
莪_幻尘1 小时前
Skill 体检:30 个 Skill 全凭感觉?体检器先自曝了 8 个“假 0 分
前端·人工智能·llm
风骏时光牛马1 小时前
AI模型综合能力评测:性能、指令遵循与多场景实测对比
前端
Frag0ut1 小时前
Chrome与Chromium内核浏览器在Windows 11上的新特性全景解析
前端·chrome·windows·web安全·chromium·gemini ai·playready drm
hiahiahia1232 小时前
实现完整 Tool Dispatcher
开发语言·前端
IT_陈寒2 小时前
Java线程池这破玩意,差点让我周末加班排查到凌晨
前端·人工智能·后端
Mr_Mao3 小时前
告别选型困难!集 VueUse、ahooks、Mantine 于一身:286 个 Hook 的 ReaUse 来了
前端·javascript·react.js
泡海椒4 小时前
趋势分析报表:jquick-pdf折线图PDF生成实战
java·大数据·运维·服务器·前端·pdf
qwfy4 小时前
我要用 AI-native 架构,从零重建一套制造业 ERP/MES
vue.js·spring boot·架构
默_笙4 小时前
🚙 一条腿走路会摔:ES 关键词检索、混合召回与 ReRank 裁判
前端·javascript
YIAN4 小时前
从跨域代理到 WebSocket:梳理前端实时通信的底层逻辑与完整实践
前端·websocket