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

相关推荐
子兮曰1 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰1 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万1 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝1 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
A黄俊辉A1 天前
uniapp webview中实现 app和内嵌的H5双向通信
vue.js·json
三十而立洋1 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁1 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
李少兄1 天前
JavaScript 隐式全局变量解析
javascript
honkun61 天前
vue 表格组件 vxe-table 配置 ajax 请求自动加载数据与表单查询
vue.js·vxe-table
kybs19911 天前
全球灾害数据分析可视化 毕业设计-附源码66794
vue.js·spring boot·mysql·安全·django·c#·asp.net