dialog封装

通用封装弹窗 / 自定义组件模板,可套用

js 复制代码
// 子组件
<template>
  <el-dialog v-model="innerFlag" title="弹窗">
    // 业务内容 
    <template #footer>
      <span class="">
         <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. 定义接收的开关参数
const props = defineProps(['show'])
// 2. 定义更新事件 + 业务事件
const emit = defineEmits(['update:show', 'confirmSelect'])

// 封装双向绑定
const innerFlag = computed({
  get() { return props.show },
  set(val) { emit('update:show', val) }
})

// 业务操作,抛出数据
const confirm = () => {
  emit('confirmSelect', '选中的数据')
}
</script>


// 父组件
<CustomDialog
  v-model:show="isDialogShow"
  @confirmSelect="getData" />

<script setup>
const isDialogShow = ref(false)
const getData = (res) => {
  console.log('子组件传回数据', res)
  isDialogShow.value = false
}
</script>

业务示例:

html 复制代码
<template>
   <el-dialog v-model="innerVisible" title="组件Library" v-if="innerVisible" width="90%" style="margin-top: 4%">
	  <div class="comBox">
	    <div class="xxBox" @click="selectComp('msg')">
	      <XxCom></XxCom>
	    </div>
	    <div class="rwBox" @click="selectComp('task')">
	      <RwCom></RwCom>
	    </div>
	    <div class="chartBox" @click="selectComp('chart')">
	      <BarChart ref="barChartsChild"></BarChart>
	    </div>
	  </div>
    </el-dialog>
</template>

<script setup>
import { ref, onMounted, reactive, computed, } from 'vue'
import XxCom from '@/components/text/xx.vue'
import RwCom from '@/components/text/rw.vue'
import BarChart from '@/components/chart/barChart.vue'

const emit = defineEmits(['select', 'update:comDialogShow'])
const props = defineProps(['comDialogShow'])


const innerVisible = computed({
  get(){ return props.comDialogShow },//父组件传进来的弹窗显示状态
  set(val){ emit('update:comDialogShow', val) } //通知父组件更新变量
})

// 自定义业务事件 把用户选中的组件标识 传给父页面
const selectComp = (key)=>{
  emit('select', key)
}

onMounted(()=>{})
</script>

<style lang="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>

主页面引入

html 复制代码
<template>
  <ComponentLibDialog v-model:comDialogShow="state.dialogVisible" @select="selectCompHandle" />
</template>

<script setup>
const state = reactive({
  dialogVisible: false,
})

// 自定义事件;弹窗选中组件,赋值给对应模块
const selectCompHandle = (compKey) => {
  // 给当前操作模块赋值
  moduleData[activeModuleId].key = compKey
  // 关闭弹窗
  state.dialogVisible = false
}

</script>
详解 v-model:visible 和 @select 分别是什么、为什么这么写

Vue3 组件自定义双向绑定规范:

复制代码
v-model:xxx="变量"
等价于
:xxx="变量" @update:xxx="新值 => 变量 = 新值"
  1. v-model:comDialogShow="dialogVisible" ------ Vue3 多参数 v-model 语法
    规则:绑定参数名 xxx,更新事件必须固定叫 update:xxx,这是 Vue 语法约定,不能随便改事件名。
js 复制代码
// 弹窗组件里定义了:
const emit = defineEmits(['select', 'update:comDialogShow'])
const props = defineProps(['comDialogShow'])

const innerVisible = computed({
  get(){ return props.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 名称:
const props = defineProps(['open'])
const emit = defineEmits(['update:open'])
const innerOpen = computed({
  get() { return props.open },
  set(val) { emit('update:open', val) }
})
//2.父组件同步改成:
<ComponentLibDialog v-model:open="dialogVisible" />
  1. @select="selectCompHandle" ------ 自定义业务事件

子组件触发: emit('select', 参数):第一个参数是事件名,后面是要传给父页面的数据

js 复制代码
// 弹窗需要把 用户选中的组件标识(msg/task/chart)传给父页面,所以自定义事件 select
// 选中组件时抛出key
const selectComp = (key)=>{
  emit('select', key)
}

父组件接收: @select="selectCompHandle"

js 复制代码
const selectCompHandle = (compKey) => {
  if (!activeModuleId) return
  // 给当前操作模块赋值组件
  moduleData[activeModuleId].key = compKey
 // 关闭弹窗
  state.comDialogShow = false
}

事件名可以随便自定义,没有强制约束

比如你想叫 chooseComponent、pick 都没问题:

子组件:emit('chooseComponent', compKey)

父组件:@chooseComponent="handleSelectComp"

举个对比示例,换一套名字演示。功能完全不变,只是参数和事件名换了。

js 复制代码
//子组件 
const props = defineProps(['open'])
const emit = defineEmits(['update:open', 'pickComponent'])

const innerOpen = computed({
  get() { return props.open },
  set(val) { emit('update:open', val) }
})

const handleSelect = (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

相关推荐
Peter-Code2 分钟前
Nginx 常用操作整理(前端)
服务器·前端·nginx
半个落月9 小时前
LangSmith 全链路观测(下):用 Dataset 与 LLM Judge 量化评估 RA
javascript·langchain
半个落月9 小时前
LangSmith 全链路观测(上):用 LangGraph 与 Milvus 构建可追踪的 RAG 客服
javascript·langchain
Java后端的Ai之路10 小时前
06-React-Props
前端·react.js·前端框架
半个落月10 小时前
LangChain.js Agent 中间件实战:生命周期、动态工具与文件权限
javascript·langchain
Flynt10 小时前
开源"间谍卫星"说数据全是真的,我把它的免key数据源挨个试了一遍
前端·开源·数据可视化
Csvn11 小时前
渲染管线
前端
程序员大阳11 小时前
副队长CSS教程(33)–圆角与透明
前端·css·透明·圆角
志尊宝11 小时前
Vue3 零基础每日笔记(082):文件上传实战——el-upload 校验、自定义上传、头像预览
前端·javascript·vue.js·笔记·#javascript·#vue.js
鬼手点金12 小时前
opencode-rules 插件
java·开发语言·前端·人工智能·chrome·git·github