功能实现分析(页面弹框)
记录时间:2024-02-27
【使用“文心一言”搜索】指令:Vue项目使用ts setup 语法,实现页面遮幕弹框,封装Hook函数,包含ShowAlert、ShowConfirm、ShowPrompt、ShowMsg、ShowError、HideMsg、PageLoading、PageLoaded、MenuUnableUse
在 Vue 3 项目中,结合 Composition API 和 TypeScript,我们可以封装一系列自定义的 Hook 函数来实现页面遮幕弹框、页面加载状态以及菜单使用状态的管理。
下面我会给你展示如何封装 useDialog.ts
Hook 来实现 ShowAlert
、ShowConfirm
、ShowPrompt
、ShowMsg
、ShowError
、HideMsg
这些功能,以及 usePageStatus.ts
来实现 PageLoading
、PageLoaded
和 MenuUnableUse
。
首先,我们需要创建 useDialog.ts
文件来封装与弹框相关的逻辑:
import { ref } from 'vue'; | |
interface DialogState { | |
isVisible: boolean; | |
title: string; | |
message: string; | |
type: 'alert' | 'confirm' | 'prompt' | 'msg' | 'error'; | |
resolve?: (value?: string | boolean) => void; | |
reject?: () => void; | |
} | |
export function useDialog() { | |
const dialogState = ref<DialogState>({ | |
isVisible: false, | |
title: '', | |
message: '', | |
type: 'msg', | |
resolve: undefined, | |
reject: undefined, | |
}); | |
const showDialog = (options: Partial<DialogState>) => { | |
dialogState.value = { | |
...dialogState.value, | |
isVisible: true, | |
...options, | |
}; | |
}; | |
const hideDialog = () => { | |
dialogState.value.isVisible = false; | |
}; | |
const showAlert = (message: string, title = 'Alert') => { | |
showDialog({ type: 'alert', title, message }); | |
}; | |
const showConfirm = (message: string, title = 'Confirm') => { | |
return new Promise<boolean>((resolve, reject) => { | |
showDialog({ | |
type: 'confirm', | |
title, | |
message, | |
resolve, | |
reject, | |
}); | |
}); | |
}; | |
// 类似的,你可以添加 showPrompt, showMsg, showError 方法 | |
// ... | |
const hideMsg = () => { | |
if (dialogState.value.type === 'msg' || dialogState.value.type === 'error') { | |
hideDialog(); | |
} | |
}; | |
return { | |
dialogState, | |
showAlert, | |
showConfirm, | |
// showPrompt, | |
// showMsg, | |
// showError, | |
hideMsg, | |
}; | |
} |
接下来,创建 usePageStatus.ts
来封装页面状态和菜单状态:
import { ref } from 'vue'; | |
export function usePageStatus() { | |
const isLoading = ref(false); | |
const isPageLoaded = ref(false); | |
const isMenuDisabled = ref(false); | |
const pageLoading = () => { | |
isLoading.value = true; | |
isPageLoaded.value = false; | |
}; | |
const pageLoaded = () => { | |
isLoading.value = false; | |
isPageLoaded.value = true; | |
}; | |
const menuUnableUse = () => { | |
isMenuDisabled.value = true; | |
}; | |
const menuAbleUse = () => { | |
isMenuDisabled.value = false; | |
}; | |
return { | |
isLoading, | |
isPageLoaded, | |
isMenuDisabled, | |
pageLoading, | |
pageLoaded, | |
menuUnableUse, | |
menuAbleUse, | |
}; | |
} |
在 Vue 组件中使用这些自定义 Hook:
<template> | |
<div> | |
<!-- 遮罩层、弹框等组件可以根据 dialogState 来渲染 --> | |
<!-- 页面加载状态可以根据 isLoading 来展示 --> | |
<!-- 菜单使用状态可以根据 isMenuDisabled 来禁用或启用 --> | |
</div> | |
</template> | |
<script lang="ts" setup> | |
import { useDialog, usePageStatus } from '@/hooks'; // 假设你的 hooks 文件夹在项目的 src 目录下 | |
const { | |
showAlert, | |
showConfirm, | |
// ...其他方法 | |
hideMsg, | |
} = useDialog(); | |
const { | |
isLoading, | |
pageLoading, | |
pageLoaded, | |
menuUnableUse, | |
// ...其他方法 | |
} = usePageStatus(); | |
// 示例:在某个操作开始时调用 pageLoading | |
// 示例:在某个操作结束时调用 pageLoaded | |
// 示例:在需要禁用菜单时调用 menuUnableUse | |
// 你可以在这里调用 showAlert 或 showConfirm 来测试弹框功能 | |
</script> |
请确保你已经在项目中安装了 Vue 3 和 TypeScript,并且配置了相应的 Vue 3 Composition API 和 TypeScript 支持。以上代码提供了一个大致的框架,具体的弹框 UI 组件、样式以及事件处理逻辑需要根据你的项目需求来实现。
指令:接以上,Vue 组件中使用这些自定义 Hook,具体示例
在 Vue 组件中使用这些自定义 Hook 的具体示例中,我们需要先定义一些 UI 元素来响应这些状态,如弹框、加载指示器等。以下是一个简单的示例,展示了如何在组件中使用 useDialog
和 usePageStatus
Hook。
首先,我们创建一个简单的弹框组件 Dialog.vue
:
<template> | |
<div v-if="dialogState.isVisible" class="dialog-overlay"> | |
<div class="dialog"> | |
<h2>{{ dialogState.title }}</h2> | |
<p>{{ dialogState.message }}</p> | |
<button @click="handleConfirm" v-if="dialogState.type === 'confirm'">Confirm</button> | |
<button @click="handleCancel" v-if="dialogState.type === 'confirm'">Cancel</button> | |
<button @click="handleClose" v-if="dialogState.type !== 'confirm'">Close</button> | |
</div> | |
</div> | |
</template> | |
<script lang="ts" setup> | |
import { ref, watch } from 'vue'; | |
const props = defineProps<{ | |
dialogState: { | |
isVisible: boolean; | |
title: string; | |
message: string; | |
type: string; | |
resolve?: (value?: any) => void; | |
reject?: () => void; | |
}; | |
}>(); | |
const handleConfirm = () => { | |
if (props.dialogState.resolve) { | |
props.dialogState.resolve(true); | |
} | |
props.dialogState.isVisible = false; | |
}; | |
const handleCancel = () => { | |
if (props.dialogState.reject) { | |
props.dialogState.reject(); | |
} | |
props.dialogState.isVisible = false; | |
}; | |
const handleClose = () => { | |
props.dialogState.isVisible = false; | |
}; | |
watch(() => props.dialogState.isVisible, (newValue) => { | |
if (!newValue) { | |
// Reset the dialog state when it's closed | |
props.dialogState.resolve = undefined; | |
props.dialogState.reject = undefined; | |
} | |
}); | |
</script> | |
<style> | |
.dialog-overlay { | |
position: fixed; | |
top: 0; | |
left: 0; | |
width: 100vw; | |
height: 100vh; | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
} | |
.dialog { | |
padding: 20px; | |
border-radius: 5px; | |
} | |
</style> |
然后,我们在主组件中使用这个 Dialog
组件以及自定义的 Hook:
<template> | |
<div> | |
<button @click="showAlertMessage">Show Alert</button> | |
<button @click="confirmAction">Confirm Action</button> | |
<!-- ...其他按钮和操作 --> | |
<Dialog :dialogState="dialogState" /> | |
<div v-if="isLoading" class="loading-spinner">Loading...</div> | |
</div> | |
</template> | |
<script lang="ts" setup> | |
import { useDialog, usePageStatus } from '@/hooks'; | |
import Dialog from './Dialog.vue'; | |
const { dialogState, showAlert, showConfirm } = useDialog(); | |
const { isLoading, pageLoading, pageLoaded } = usePageStatus(); | |
const showAlertMessage = () => { | |
showAlert('This is an alert message!'); | |
}; | |
const confirmAction = async () => { | |
pageLoading(); // 开始加载状态 | |
try { | |
const result = await showConfirm('Are you sure you want to perform this action?'); | |
if (result) { | |
// 用户点击了确认按钮 | |
pageLoaded(); // 结束加载状态 | |
// 执行确认后的操作... | |
} | |
} catch { | |
// 用户点击了取消按钮或者关闭了弹框 | |
pageLoaded(); // 结束加载状态 | |
// 执行取消后的操作... | |
} | |
}; | |
</script> | |
<style> | |
.loading-spinner { | |
position: fixed; | |
top: 50%; | |
left: 50%; | |
transform: translate(-50%, -50%); | |
/* 添加加载指示器的样式 */ | |
} | |
</style> |
在这个示例中,我们创建了一个 Dialog
组件,它接收 dialogState
作为属性,并根据其状态来显示不同类型的弹框。在主组件中,我们导入了 useDialog
和 usePageStatus
Hook,并使用它们来控制弹框的显示和页面的加载状态。通过调用 showAlert
和 showConfirm
方法,我们可以在用户交互时显示不同的弹框。同时,我们使用 isLoading
来控制加载指示器的显示。
指令:接以上,进一步封装成Vue插件,组件中动态调用弹框
要将自定义的弹框封装成 Vue 插件并在组件中动态调用,我们需要执行几个步骤:
- 创建一个插件文件,比如
DialogPlugin.js
。 - 在插件文件中定义全局方法或属性,用于显示不同类型的弹框。
- 使用
app.use()
方法将插件注册到 Vue 应用中。 - 在组件中通过全局方法动态调用弹框。
首先,我们创建 DialogPlugin.js
文件,并定义插件:
// DialogPlugin.js | |
import DialogComponent from './Dialog.vue'; | |
const DialogPlugin = { | |
install(app, options) { | |
// 注册全局组件 | |
app.component('DialogComponent', DialogComponent); | |
// 在原型上定义方法,以便在组件中通过 this.$dialog 访问 | |
app.config.globalProperties.$dialog = { | |
showAlert(message) { | |
// 这里需要实现显示警告弹框的逻辑 | |
// 可以使用事件总线、Vuex 或其他状态管理方案来触发弹框的显示 | |
console.log('Show alert:', message); | |
// 实际实现中,这里会触发一个事件或更改全局状态来打开弹框 | |
}, | |
showConfirm(message) { | |
// 这里需要实现显示确认弹框的逻辑,并返回一个 Promise | |
return new Promise((resolve, reject) => { | |
console.log('Show confirm:', message); | |
// 实际实现中,这里会触发一个事件或更改全局状态来打开弹框,并在用户选择后调用 resolve 或 reject | |
// 这里只是模拟用户点击确认 | |
setTimeout(() => resolve(true), 1000); | |
}); | |
}, | |
}; | |
}, | |
}; | |
export default DialogPlugin; |
注意:上面的 showAlert
和 showConfirm
方法目前只是打印消息到控制台,并没有真正触发弹框的显示。在实际应用中,你需要使用事件总线、Vuex 或其他状态管理方案来触发弹框组件的状态变更。
然后,在你的主应用文件(比如 main.js
或 main.ts
)中注册这个插件:
// main.js | |
import { createApp } from 'vue'; | |
import App from './App.vue'; | |
import DialogPlugin from './DialogPlugin'; | |
const app = createApp(App); | |
// 注册 Dialog 插件 | |
app.use(DialogPlugin); | |
app.mount('#app'); |
现在,你可以在任何组件中通过 this.$dialog
访问弹框方法:
<template> | |
<div> | |
<button @click="showAlertMessage">Show Alert</button> | |
<button @click="confirmAction">Confirm Action</button> | |
</div> | |
</template> | |
<script> | |
export default { | |
methods: { | |
showAlertMessage() { | |
this.$dialog.showAlert('This is an alert message!'); | |
}, | |
async confirmAction() { | |
try { | |
const result = await this.$dialog.showConfirm('Are you sure you want to perform this action?'); | |
if (result) { | |
// 用户点击了确认按钮 | |
console.log('User confirmed the action'); | |
} | |
} catch (error) { | |
// 用户点击了取消按钮或者关闭了弹框 | |
console.log('User canceled the action'); | |
} | |
}, | |
}, | |
}; | |
</script> |
请注意,上面的 DialogPlugin.js
文件中的 showAlert
和 showConfirm
方法并没有真正实现弹框的显示逻辑。你需要根据你的应用架构来实现这部分逻辑。例如,你可以使用 Vuex 来管理弹框的状态,或者使用事件总线来在组件之间通信。当这些方法被调用时,你可以更改全局状态或触发事件来通知弹框组件显示或隐藏。