思路
可以看看抖音渡一袁老师,封装一个函数showModal传入一个options,类似于antd的modal。
- 创建一个外层容器
fragment,把它挂载到body上 - 利用
jsx写个组件,把它挂载到fragment上 - 点击关闭时,则先卸载组件,再移除
fragment jsx中的css与普通单文件组件不一样,可以使用css module,css in js,style component,react怎么用,这里也可以怎么用。- 这里的
children我设计可以传入string,number,() => VNode
效果


实现
- 目录结构

- jsx
import { createApp, ref, h, type VNode } from 'vue'
import style from './modal.module.css'
interface options {
title?: string
maskClosable?: boolean
children?: string | number | (() => VNode)
onClose: (close: () => void) => void
}
function showModal(options: options) {
const defaultOptions = ref<options>({
title: 'Basic Modal',
maskClosable: true,
children: () => h('p', 'some content...'),
onClose: (close) => {
close()
}
})
const mergeOptions = Object.assign(defaultOptions.value, options)
const fragment = document.createElement('div')
fragment.className = style.wrap
document.body.appendChild(fragment)
const app = createApp(
{
render() {
return (
<div class={style.container}>
<div class={style.content}>
<h1>{mergeOptions.title}</h1>
<svg
class={style.closeIcon}
width="1em"
height="1em"
onClick={() => {
mergeOptions.onClose(close)
}}
>
<line x1="0" y1="0" x2="1em" y2="1em" stroke="#242424"></line>
<line x1="0" y1="1em" x2="1em" y2="0" stroke="#242424"></line>
</svg>
{typeof mergeOptions.children === 'function'
? mergeOptions.children!()
: mergeOptions.children}
<button
class={style.closeBtn}
onClick={() => {
mergeOptions.onClose(close)
}}
>
关闭
</button>
</div>
</div>
)
}
},
{
mergeOptions,
onclick() {
mergeOptions.maskClosable && mergeOptions.onClose(close)
}
}
)
app.mount(fragment)
const close = () => {
app.unmount()
fragment.remove()
}
window.addEventListener('unload', () => {
mergeOptions.onClose(close)
})
}
export default showModal
- css
.wrap {
position: fixed;
inset: 0;
background-color: rgba(0, 0, 0, 0.625);
z-index: 9999;
overflow: hidden;
}
.wrap .container {
position: relative;
width: 100%;
height: 100%;
}
.wrap .container .closeIcon {
position: absolute;
top: 20px;
right: 24px;
}
.wrap .container .closeIcon:hover line {
stroke: #e92f20;
}
.wrap .container .closeBtn {
display: block;
margin-left: auto;
margin-top: 20px;
outline: none;
font-weight: 400;
white-space: nowrap;
text-align: center;
border: 1px solid transparent;
cursor: pointer;
color: #fff;
font-size: 14px;
height: 32px;
padding: 4px 15px;
border-radius: 6px;
background-color: #1677ff;
box-shadow: 0 2px 0 rgba(5, 145, 255, 0.1)
}
.wrap .container .content {
position: absolute;
top: 10%;
left: 50%;
transform: translate(-50%);
width: 520px;
background-color: #ffffff;
background-clip: padding-box;
border: 0;
border-radius: 8px;
box-shadow: 0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 9px 28px 8px rgba(0, 0, 0, 0.05);
pointer-events: auto;
padding: 20px 24px;
}
该文章展示了如何在Vue中仿照antd的modal组件,自定义一个showModal函数。通过jsx创建一个挂载在body上的外层容器,并使用cssmodule进行样式管理。函数接受options参数,包括标题、是否允许遮罩关闭、子组件等内容,并提供了关闭回调功能。
1627

被折叠的 条评论
为什么被折叠?



