通用封装弹窗 / 自定义组件模板,可套用
// 子组件<template><el-dialog v-model="innerFlag"title="弹窗">// 业务内容<template #footer><spanclass=""><el-button @click="state.peopleDialogShow = false">取消</el-button><el-button type="primary"@click="confirm">确定</el-button></span></template></el-dialog></template><script setup>import{computed}from'vue'// 1. 定义接收的开关参数constprops=defineProps(['show'])// 2. 定义更新事件 + 业务事件constemit=defineEmits(['update:show','confirmSelect'])// 封装双向绑定constinnerFlag=computed({get(){returnprops.show},set(val){emit('update:show',val)}})// 业务操作,抛出数据constconfirm=()=>{emit('confirmSelect','选中的数据')}</script>// 父组件<CustomDialog v-model:show="isDialogShow"@confirmSelect="getData"/><script setup>constisDialogShow=ref(false)constgetData=(res)=>{console.log('子组件传回数据',res)isDialogShow.value=false}</script>业务示例:
<template><el-dialogv-model="innerVisible"title="组件Library"v-if="innerVisible"width="90%"style="margin-top:4%"><divclass="comBox"><divclass="xxBox"@click="selectComp('msg')"><XxCom></XxCom></div><divclass="rwBox"@click="selectComp('task')"><RwCom></RwCom></div><divclass="chartBox"@click="selectComp('chart')"><BarChartref="barChartsChild"></BarChart></div></div></el-dialog></template><scriptsetup>import{ref,onMounted,reactive,computed,}from'vue'importXxComfrom'@/components/text/xx.vue'importRwComfrom'@/components/text/rw.vue'importBarChartfrom'@/components/chart/barChart.vue'constemit=defineEmits(['select','update:comDialogShow'])constprops=defineProps(['comDialogShow'])constinnerVisible=computed({get(){returnprops.comDialogShow},//父组件传进来的弹窗显示状态set(val){emit('update:comDialogShow',val)}//通知父组件更新变量})// 自定义业务事件 把用户选中的组件标识 传给父页面constselectComp=(key)=>{emit('select',key)}onMounted(()=>{})</script><stylelang="scss"scoped>//dialog 相关样式 .comBox{display:flex;flex-wrap:wrap;gap:12px;/* 模块间距,按需调整 */width:100%;height:100%;overflow:auto;.xxBox, .rwBox, .chartBox, .zbBox{width:24.4%;height:36%;background:#f5f7fa;border-radius:8px;padding:12px;overflow-y:auto;/* 内容超出时滚动 */}}</style>主页面引入
<template><ComponentLibDialogv-model:comDialogShow="state.dialogVisible"@select="selectCompHandle"/></template><scriptsetup>conststate=reactive({dialogVisible:false,})// 自定义事件;弹窗选中组件,赋值给对应模块constselectCompHandle=(compKey)=>{// 给当前操作模块赋值moduleData[activeModuleId].key=compKey// 关闭弹窗state.dialogVisible=false}</script>详解 v-model:visible 和 @select 分别是什么、为什么这么写
Vue3 组件自定义双向绑定规范:
v-model:xxx="变量" 等价于 :xxx="变量" @update:xxx="新值 => 变量 = 新值"- v-model:comDialogShow=“dialogVisible” —— Vue3 多参数 v-model 语法
规则:绑定参数名 xxx,更新事件必须固定叫 update:xxx,这是 Vue 语法约定,不能随便改事件名。
// 弹窗组件里定义了:constemit=defineEmits(['select','update:comDialogShow'])constprops=defineProps(['comDialogShow'])constinnerVisible=computed({get(){returnprops.comDialogShow},//父组件传进来的弹窗显示状态set(val){emit('update:comDialogShow',val)}//通知父组件更新变量})// 父组件对应写法,两种写法完全等价//写法1. 简写(推荐)<ComponentLibDialog v-model:comDialogShow="dialogVisible"/>//写法2. 完整展开写法,更好理解底层<ComponentLibDialog:comDialogShow="dialogVisible"@update:comDialogShow="val => dialogVisible = val"/>//能不能换名字?完全可以,举例子//比如不想用 visible,改用 open://1.子组件改 props、emit 名称:constprops=defineProps(['open'])constemit=defineEmits(['update:open'])constinnerOpen=computed({get(){returnprops.open},set(val){emit('update:open',val)}})//2.父组件同步改成:<ComponentLibDialog v-model:open="dialogVisible"/>- @select=“selectCompHandle” —— 自定义业务事件
子组件触发: emit(‘select’, 参数):第一个参数是事件名,后面是要传给父页面的数据
// 弹窗需要把 用户选中的组件标识(msg/task/chart)传给父页面,所以自定义事件 select// 选中组件时抛出keyconstselectComp=(key)=>{emit('select',key)}父组件接收: @select=“selectCompHandle”
constselectCompHandle=(compKey)=>{if(!activeModuleId)return// 给当前操作模块赋值组件moduleData[activeModuleId].key=compKey// 关闭弹窗state.comDialogShow=false}事件名可以随便自定义,没有强制约束
比如你想叫 chooseComponent、pick 都没问题:
子组件:emit(‘chooseComponent’, compKey)
父组件:@chooseComponent=“handleSelectComp”
举个对比示例,换一套名字演示。功能完全不变,只是参数和事件名换了。
//子组件constprops=defineProps(['open'])constemit=defineEmits(['update:open','pickComponent'])constinnerOpen=computed({get(){returnprops.open},set(val){emit('update:open',val)}})consthandleSelect=(key)=>{emit('pickComponent',key)innerOpen.value=false}//父组件<ComponentSelectDialog v-model:open="dialogVisible"@pickComponent="handleSelectComp"/>总结:两类事件的区别
| 类型 | 语法规则 | 作用 | 命名约束 |
|---|---|---|---|
| v-model:xxx 双向绑定 | 事件固定 update:xxx | 同步开关类状态(弹窗显隐、开关、输入框值) | 更新事件名不能自定义,必须 update:xxx |
| 自定义业务事件 @xxx | 事件名完全自定义 | 传递业务数据(选中项、提交、删除、点击) | 随便起名,见名知意即可 |
使用场景:
什么时候用 v-model:xxx,什么时候用自定义事件?
1.控制开关、输入值、显隐这类双向同步状态 → 用 v-model:xxx
2.点击选择、提交、删除、获取业务数据这类单向回调传参 → 自定义事件 @xxx