相信大家都封装过弹窗组件,基本思路都是父组件给子组件传递一个变量,子组件props进行接收,当点击确认或者关闭按钮时,通过emit回传事件供父组件调用。这种封装方式缺点是复用性查、使用频繁时需要定义多份{isVisible、handleSubmit、handleClose}代码,代码冗余,今天分享一种命令式组件封装的方式。
命令式组件封装是一种将功能封装在组件内部,并通过命令式的方式进行调用和控制的封装方法。在命令式组件封装中,组件负责封装一定的功能逻辑,并提供一组接口或方法,供外部代码调用来触发和控制组件的行为。调用方式大致为:
async function showMsg(){
const [,res]= await msgBox('测试内容',{type:'success',iconType:'question'})
if(res){
consloe.log('点击了确定')
}else{
console.log('点击了取消')
}
}
首先创建一个MessageBox.vue
文件,编写组件样式代码,这里我使用的是unocss
进行编写。
组件需要接收参数
export interface HuiMsgBoxProp {
/** 控制图标展示类型 info:叹号 success:钩 question:问号 */
iconType:'info' | 'success' | 'question',
/** 控制图标展示的颜色 */
type:'info' | 'warning' | 'success' | 'danger',
/** 弹窗显示的内容 */
content:string,
/** 取消按钮的文本 */
cancelText:string,
/** 确定按钮的文本 */
confirmText:string,
/** 关闭事件 */
closeBox: ()=> void,
/** 确定事件事件 */
confirmHandler:()=> void,
/** 取消事件 */
cancelHandler:()=> void,
}
其次创建index.ts
文件,由于组件调用方式是通过一个函数进行调用的,并提供.then
和.catch
方法,所以需要编写一个函数,该函数返回一个Promise。当调用该函数,创建组件实例,组件进行挂载。
import { h, render } from 'vue'
import confirmComponent from './message-box.vue'
import { to } from "@hua5/hua5-utils"
export interface PayLoadType {
/** 控制图标展示类型 info:叹号 success:钩 question:问号 */
iconType?:'info' | 'success' | 'question',
/** 控制图标展示的颜色 */
type?: "info" | "success" | "danger" | "warning",
/** 取消按钮的文本 */
cancelText?:string,
/** 确定按钮的文本 */
confirmText?:string
}
export const hua5MsgBox = (content: string, payLoad:PayLoadType = {}) => {
const { iconType = 'info', type = 'info', cancelText, confirmText } = payLoad
return new Promise((resolve) => {
// 取消按钮事件
const cancelHandler = () => {
resolve(false)
}
// 确定按钮事件
const confirmHandler = () => {
resolve(true)
}
// 关闭弹层事件
const closeBox = () => {
render(null, document.body)
}
// 1. 生成 vnode
const vnode = h(confirmComponent, {
content,
iconType,
type,
cancelText,
confirmText,
cancelHandler,
confirmHandler,
closeBox,
})
// 2. render 渲染
render(vnode, document.body)
})
}
export const msgBox = (content: string, payLoad?:PayLoadType) => {
return to(hua5MsgBox(content, payLoad))
}
/**
* @param { Promise } promise
* @param { Object= } errorExt - Additional Information you can pass to the err object
* @return { Promise }
*/
export function to(promise: Promise): Promise {
return promise.then(res => [null, res]).catch(error => [error, null])
}