Vue 弹框实现,防抖(useDebounceFn)
index.vue
<template>
<div class="app-container">
<el-card shadow="never">
<el-table v-loading="loading" :data="pageData" highlight-current-row border>
<el-table-column label="医院" width="150" prop="HospitalName" show-overflow-tooltip />
<el-table-column label="科室" width="100" prop="DeptName" show-overflow-tooltip />
<el-table-column
fixed="right"
label="操作"
width="280"
prop="describe"
>
<template #default="scope">
<el-button
type="primary"
size="small"
@click="openDetailDialog(scope.row)"
>
详情
</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-if="total > 0"
v-model:total="total"
v-model:page="queryParams.PageNum"
v-model:limit="queryParams.PageSize"
@pagination="handleQuery"
/>
</el-card>
<!-- 添加 Detail 组件,并绑定 visible 属性 -->
<Detail v-model="detailVisible" :detailData="currentDetailData" />
</div>
</template>
<script setup lang="ts">
import Detail from "./components/Detail.vue";
import { ref, reactive } from "vue";
defineOptions({
name: "Order",
inheritAttrs: false,
});
import OrderAPI, { PageVO, PageQuery } from "@/api/order";
const queryFormRef = ref();
const loading = ref(false);
const total = ref(0);
const detailVisible = ref(false); // 控制 Detail 对话框的显示和隐藏
const currentDetailData = ref<any>(null); // 存储当前行的数据
const queryParams = reactive<PageQuery>({
PageNum: 1,
PageSize: 10,
});
// 日志表格数据
const pageData = ref<PageVO[]>();
/** 查询 */
function handleQuery() {
loading.value = true;
OrderAPI.getPage(queryParams)
.then((data) => {
console.log(data);
pageData.value = data.BussinessData;
total.value = data.Page.TotalCount;
})
.finally(() => {
loading.value = false;
});
}
const openDetailDialog = (row: any) => {
currentDetailData.value = row; // 保存当前行的数据
detailVisible.value = true; // 显示对话框
};
onMounted(() => {
handleQuery();
});
</script>
detail.vue
<template>
<el-dialog
v-model="visible"
:show-close="false"
width="50%"
append-to-body
@close="closeDetailDialog"
>
<template #header>
<div class="flex-x-between">
<span>通知公告详情</span>
<div class="dialog-toolbar">
<el-button circle @click="closeDetailDialog">
<template #icon>
<Close />
</template>
</el-button>
</div>
</div>
</template>
<el-descriptions :column="1">
<el-descriptions-item label="标题:">
{{ props.detailData?.HospitalName || '无数据' }}
</el-descriptions-item>
</el-descriptions>
<template #footer>
<span class="dialog-footer">
<el-button type="primary" @click="handleSubmit">确 定</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts">
const props = defineProps({
//update:modelValue 是 v-model 默认监听的事件,用于更新父组件的绑定值。
modelValue: {
type: Boolean,
default: false,
},
detailData: {
type: Object,
default: () => ({}), // 默认空对象,避免 undefined
},
});
//父页面,通过 update:modelValue 感知 <ChildComponent: modelValue="someValue" @update:modelValue="(newValue) => someValue = newValue" />
const emit = defineEmits(["update:modelValue"]);
//从 Vue 3.4 开始,推荐的实现方式是使用 defineModel() 父组件可以用 v-model 绑定一个值:
const visible = defineModel("modelValue", {
type: Boolean,
required: true,
default: false,
});
const closeDetailDialog = () => {
visible.value = false;
};
const formRef = ref();
// 提交用户表单(防抖)
const handleSubmit = useDebounceFn(() => {
formRef.value.validate((valid: boolean) => {
if (valid) {
const { Id } = props.detailData.Id
const { MonitorHour } = props.detailData.MonitorHour
OrderAPI.update(Id,MonitorHour)
.then((data) => {
ElMessage.success('设置成功')
emit("update-sucess");
handleClose();
})
.finally(() => {
//loading.value = false;
});
}
});
}, 1000);
</script>
关键点说明
-
v-model双向绑定:- 在
index.vue中,Detail组件通过v-model="detailVisible"绑定了一个布尔值,用于控制对话框的显示和隐藏。 - 在
Detail.vue中,通过props接收modelValue,并通过emit("update:modelValue")实现双向绑定。
- 在
-
传递数据:
index.vue通过:detailData="currentDetailData"将当前行的数据传递给Detail.vue。Detail.vue通过props接收detailData并显示在对话框中。
-
关闭对话框:
- 点击关闭按钮或对话框外部时,
visible会被设置为false,并通过emit通知父组件更新状态。
- 点击关闭按钮或对话框外部时,
效果
- 点击“详情”按钮时,
Detail对话框会弹出并显示当前行的数据。 - 点击关闭按钮或对话框外部时,对话框会关闭。
这样就实现了在 index.vue 中弹出 Detail.vue 的功能。
const emit = defineEmits(["update:modelValue"]); 是 Vue 3 的 <script setup> 语法中用于声明组件可以触发(emit)哪些自定义事件的写法。
1. 作用
- 它告诉 Vue,这个组件可以触发一个名为
"update:modelValue"的事件。 - 这个事件通常用于实现
v-model双向绑定。
2. 为什么需要 update:modelValue?
在 Vue 中,v-model 是语法糖,它实际上是 :modelValue(props) + @update:modelValue(emit)的组合。
例如:
<ChildComponent v-model="someValue" />
等价于:
<ChildComponent
:modelValue="someValue"
@update:modelValue="(newValue) => someValue = newValue"
/>
所以,子组件需要通过 emit('update:modelValue', newValue) 来更新父组件的绑定值。
3. defineEmits 详解
defineEmits是 Vue 3<script setup>特有的 API,用于声明组件可以触发哪些事件。- 它接收一个事件名数组(或更复杂的类型定义),并返回一个
emit函数,用于触发这些事件。
示例:
const emit = defineEmits(["update:modelValue", "change", "close"]);
// 触发事件
emit("update:modelValue", false); // 通知父组件更新 v-model
emit("change", newValue); // 触发自定义事件
emit("close"); // 不带参数的事件
4. 在你的代码中的具体作用
在 Detail.vue 中:
const emit = defineEmits(["update:modelValue"]);
// 当 visible 变化时,通知父组件更新 v-model 绑定的值
watch(() => visible.value, (val) => {
emit("update:modelValue", val); // 触发事件,让父组件的 detailVisible 同步更新
});
这样:
- 当
visible变为false(比如点击关闭按钮),emit('update:modelValue', false)会通知父组件index.vue更新detailVisible为false。 - 父组件的
v-model="detailVisible"会自动同步这个变化,实现双向绑定。
5. 总结
| 代码 | 作用 |
|---|---|
defineEmits(["update:modelValue"]) |
声明组件可以触发 update:modelValue 事件(用于 v-model 双向绑定) |
emit("update:modelValue", newValue) |
触发事件,通知父组件更新绑定的值 |
这样,Detail.vue 就可以通过 v-model 和父组件 index.vue 进行双向数据同步了。
本文来自博客园,作者:VipSoft 转载请注明原文链接:https://www.cnblogs.com/vipsoft/p/19039089
浙公网安备 33010602011771号