一、vue2
效果:
@/components/TestDialog.vue
<template>
<el-dialog
title="弹框"
:visible.sync="dialogVisible"
:before-close="handleClose"
>
<span>这是一段信息</span>
<div slot="footer">
<el-button @click="handleClose">取 消</el-button>
<el-button type="primary" @click="handleSubmit">确 定</el-button>
</div>
</el-dialog>
</template>
<script>
export default {
name: 'TestDialog',
props: { value: { type: Boolean, default: false } },
computed: {
dialogVisible: {
get() {
return this.value
},
set(flag) {
this.$emit('input', flag)
}
}
},
methods: {
handleSubmit() {
this.handleClose()
},
handleClose() {
this.dialogVisible = false
}
}
}
</script>
如果不使用computed:
<template>
<el-dialog title="标题" :visible.sync="value" :before-close="handleClose">
<span>这是一段信息</span>
<div slot="footer">
<el-button @click="handleClose">取 消</el-button>
<el-button type="primary" @click="handleSubmit">确 定</el-button>
</div>
</el-dialog>
</template>
<script>
export default {
name: 'TestDialog',
props: { value: { type: Boolean, default: false } },
watch: {
value(flag) {},
},
methods: {
handleSubmit() {
this.handleClose()
},
handleClose() {
this.$emit('input', false)
},
},
}
</script>
如果需要设置弹框样式:
<style lang="scss" scoped>
::v-deep .el-dialog__body {
padding: 0 40px;
}
</style>
App.vue
<template>
<div id="app">
<el-button @click="open">打开</el-button>
<TestDialog v-model="dialogVisible" />
</div>
</template>
<script>
export default {
data() {
return { dialogVisible: false }
},
methods: {
open() {
this.dialogVisible = true
}
}
}
</script>
拓展:sync修饰符
细心的小伙伴发现el-dialog标签使用的是:visible.sync="dialogVisible",如果我想要TestDialog标签也使用:visible.sync="dialogVisible",该怎么实现呢
<TestDialog :visible.sync="dialogVisible" />
TestDialog.vue
为什么我建议封装弹框组件使用v-model或sync?
这样封装完组件,在使用组件的时候只需要绑定v-model或visible.sync属性就可以实现开启和关闭弹框,不需要借助ref或其他方式去实现,在繁复的代码中,能简洁一点是一点
同样地,在封装一些表单组件时,也应该尽量考虑使用v-model去绑定数据,ref只是一种方式,但不是首选
二、vue3 基于computed封装一个dialog弹框
data-situation-dialog.vue
<template>
<el-dialog v-model="dialogVisible" title="Tips" width="500" :before-close="handleClose">
<span>This is a message</span>
<template #footer>
<div class="dialog-footer">
<el-button @click="handleClose">Cancel</el-button>
<el-button type="primary" @click="handleConfirm">Confirm</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, computed } from "vue"
const props = defineProps({ modelValue: { type: Boolean, default: false } })
const emit = defineEmits(["update:modelValue"])
const dialogVisible = computed({
get() {
return props.modelValue
},
set(val) {
emit("update:modelValue", val)
},
})
const handleClose = () => {
dialogVisible.value = false
}
const handleConfirm = () => {
handleClose()
}
</script>
<style lang="scss" scoped></style>
使用:
<DataSituationDialog v-model="dataSituationVisible" />
import DataSituationDialog from "./components/data-situation-dialog.vue"
const dataSituationVisible = ref<boolean>(false)
vue3 - computed的get方法中进行异步请求
const dialogVisible = computed({
get() {
if (props.modelValue) getData() // 打开弹框时,触发搜索
return props.modelValue
},
set(val) {
emit("update:modelValue", val)
},
})
问题复现:(v2中不存在此问题)
问题原因:
【如果你在computed属性的get方法中使用了异步操作,那么每次调用get方法都会执行该异步操作。这是因为Vue无法预测异步操作何时完成,因此它无法确定是否需要重新计算computed属性的值。
为了解决这个问题,你可以使用watcher或methods来处理异步逻辑。watcher可以监听特定的数据变化,并在变化时触发异步操作。而methods则可以在需要的时候手动调用异步操作。】
解决方式:通过watch监听去触发搜索
computed就不需要了,直接v-model="props.modelValue"
在弹框关闭时执行emit('update:modelValue', false)