写在前面
本文仅代表个人对vue组件的一些粗浅认识,仅供参考,如有错漏,欢迎指出。
vue 弹窗组件的几种调用方式
1. 同一组件调用
<template>
<el-button plain @click="dialogVisible = true" >
Click to open the Dialog
</el-button>
<el-dialog
v-model="dialogVisible"
title="Tips"
width="500"
:center="false"
:before-close="handleClose"
>
<template #footer>
<div class="dialog-footer">
<el-button @click="dialogVisible = false">Cancel</el-button>
<el-button type="primary" @click="dialogVisible = false">
Confirm
</el-button>
</div>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { ElMessageBox } from 'element-plus'
const dialogVisible = ref(false)
const handleClose = (done: () => void) => {
ElMessageBox.confirm('Are you sure to close this dialog?')
.then(() => {
done()
})
.catch(() => {
// catch error
})
}
</script>
缺点:弹窗代码在父组件中,导致代码较多
2.父子组件调用
父组件
<template>
<el-button @click="clickBtn">点击出现弹窗</el-button>
<Dialog v-model:visible="visible" @close="close" @submit="submit"></Dialog>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import Dialog from './components/Dialog.vue';
const visible = ref(false)
const clickBtn = () => {
visible.value = true
}
const close = () => {
visible.value = false
}
const submit =() => {
visible.value =false
}
</script>
子组件
<template>
<el-dialog v-model="props.visible" title="dialog" width="452px">
<el-button @click="close">取消</el-button>
<el-button @click="$emit('update:visible', false)">确定</el-button>
</el-dialog>
</template>
<script lang="ts" setup>
const props = defineProps( { visible: Boolean})
const emit = defineEmits(['update:visible'])
const close =() => {
emit('update:visible')
}
</script>
缺点:需要一个变量控制子组件展示隐藏,耦合重
3.父组件调用子组件方法
子组件暴露弹窗打开关闭方法
<template>
<el-dialog v-model="visible" title="dialog" width="452px">
<el-button @click="close">取消</el-button>
<el-button @click="submit">确定</el-button>
</el-dialog>
</template>
<script lang="ts" setup>
import {ref} from 'vue'
const emit = defineEmits(['submit'])
const visible = ref(false)
const open = () => {
visible.value = true
}
const close =() => {
visible.value = false
}
const submit = () => {
visible.value = false
emit('submit', [123])
}
defineExpose({open, close})
</script>
父组件通过ref调用
<template>
<el-button @click="clickBtn">点击出现弹窗</el-button>
<Dialog2 ref="dialogRef" @submit="submit"></Dialog2>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import Dialog2 from './components/Dialog2.vue';
const dialogRef = ref()
const clickBtn = () => {
dialogRef.value.open()
}
const submit =(list) => {
console.log('list :>> ', list);
dialogRef.value.close()
}
</script>
缺点:需要知道子组件暴露的方法,不利于解耦
4.函数式调用
子组件
<template>
<el-dialog v-model="visible" title="dialog" width="452px">
<el-button @click="close">取消</el-button>
<el-button @click="submit">确定</el-button>
</el-dialog>
</template>
<script lang="ts" setup>
import {onMounted, ref} from 'vue'
interface Props {
close?: () => void,
submit?: (list:any) => void
}
const props = defineProps<Props>( )
const visible = ref(false)
onMounted( () => {
visible.value = true
})
const close =() => {
visible.value = false
props?.close?.()
}
const submit = () => {
visible.value = false
props?.submit?.([123])
}
</script>
index.ts: 动态调用
import Dialog3 from './Dialog3.vue'
import { createApp } from 'vue';
const useDialog = (options: any) => {
const mountNode = document.createElement('div')
document.body.appendChild(mountNode)
return new Promise((resolve, reject) => {
let app: any = createApp(Dialog3, {
...options,
close: () => {
app.unmount()
mountNode.remove()
app = undefined
reject()
},
submit: (list: any) => {
app.unmount()
mountNode.remove()
app = undefined
resolve(list)
}
})
if (app) {
app.mount(mountNode)
}
})
}
export default useDialog
父组件中使用
<template>
<el-button @click="clickBtn">点击出现弹窗</el-button>
</template>
<script setup lang="ts">
import useDialog from './index.ts'
const clickBtn = () => {
useDialog({}).then(list => {
console.log('object :>> ', list);
})
}
</script>
优点: 需要使用组件式才调用,只需要传递props,不需要了解子组件内部逻辑
很多组件都是使用这种思想,如element-plus的MessageBox