最近在使用Vue3 + Vite + Naive UI开发新项目,发现Naive对于dialog,model组件都提供了API方式的调用实现,同时支持传入render函数,可以轻松地实现弹出式的组件功能。
但是同样是弹出式组件的抽屉(drawer)却被不公平对待😡, 居然没提供API方式的调用,只能老老实实在template引入使用,这简直无法忍受,网上查了一圈没有找到相关的实现,到官方github的Issues居然没人提这个需求😮,所以我以hooks方式自己实现一个useDrawer。
直接上代码:
// @/hooks/useDrawer.ts
import { createApp, defineComponent, RenderFunction } from 'vue'
import { NConfigProvider, NDrawer, NDrawerContent, zhCN, dateZhCN, DrawerProps, DrawerContentProps } from 'naive-ui'
interface CreateDrawerProps {
drawerProps: DrawerProps;
drawerContentProps: DrawerContentProps;
content: RenderFunction;
[key: string]: any;
}
export default function useDrawer() {
const show = ref(false)
// 创建drawer
function createDrawer(props: CreateDrawerProps) {
// 定义drawer组件
const Drawer = defineComponent({
setup() {
nextTick(() => show.value = true)
},
render() {
return h(
NConfigProvider,
{
inlineThemeDisabled: true,
locale: zhCN,
dateLocale: dateZhCN
},
{
default: () => h(
NDrawer,
{
...props.drawerProps,
show: show.value,
onUpdateShow: (val: boolean) => { show.value = val }
},
{
default: () => h(
NDrawerContent,
props.drawerContentProps,
props.content
)
}
)
})
}
})
// 创建挂载元素
const container = document.createElement('div')
document.body.appendChild(container)
// 创建新应用,挂载到body
const drawer = createApp(Drawer, props)
drawer.mount(container)
// 抽屉关闭后,销毁挂载元素和相关dom
const stopWatcher = watch(show, (val) => {
if (val) return
stopWatcher()
setTimeout(() => {
container.remove()
const drawerContainer = document.getElementsByClassName('n-drawer-container')
drawerContainer[drawerContainer.length - 1]?.remove()
}, 320) // 等drawer关闭动画结束
})
return drawer
}
// 销毁drawer
function destroyDrawer() {
show.value = false
}
return {
createDrawer,
destroyDrawer
}
}
使用方式:
/**
* @description 测试useDrawer
*/
const { createDrawer, destroyDrawer } = useDrawer()
const test = () => {
createDrawer({
// 这里的drawerProps跟文档上的Drawer Props保持一致
drawerProps: {
width: 500
},
// 这里的drawerContentProps跟文档上的DrawerContent Props保持一致
drawerContentProps: {
title: '标题',
closable: true
},
// ChildComponent为自定义的子组件,通过props传值,emit派发事件
content: () => h(ChildComponent, {
detail: { id: '123' },
onCancel: () => {
destroyDrawer()
},
onConfirm: () => {
destroyDrawer()
}
})
})
}
就是这样自己实现了一个Naive UI的userDrawer,使用起来优雅而方便。