功能实现分析(页面弹框)
记录时间: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 来管理弹框的状态,或者使用事件总线来在组件之间通信。当这些方法被调用时,你可以更改全局状态或触发事件来通知弹框组件显示或隐藏。
浙公网安备 33010602011771号