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

相关推荐
高彬22 分钟前
SAP ECC6.0 对接 C# web Services服务
开发语言·前端·c#·sap
小江的记录本23 分钟前
【CSS】CSS 核心:盒模型、BFC/IFC、Flex/Grid 布局、响应式布局、移动端适配(附《思维导图》)
前端·css·面试·前端框架·tensorflow·html5·xss
Coodor23 分钟前
BS架构下在前端读写超高频UHF标签
前端·超高频·rfid读写器web插件·uhf标签
一晌小贪欢28 分钟前
python-第20天:关键字参数与不定长参数
java·开发语言·前端·python·数据可视化·函数参数·python办公
我命由我1234530 分钟前
JS Mock(Mock 拦截请求的前提、Mock 使用、关闭 Mock)
开发语言·前端·javascript·前端框架·html·html5·js
开开心心就好36 分钟前
手机精确倒计时工具悬浮窗口秒数实时显示
android·前端·javascript·jupyter·智能手机·pdf·html
小江的记录本42 分钟前
【HTML】HTML5 新特性、语义化标签、浏览器渲染流程(附《思维导图》)
前端·css·面试·前端框架·html·css3·html5
风骏时光牛马1 小时前
手机端高效实用技巧,看完直接上手用
前端