这是我参与8月更文挑战的第17天,活动详情查看:8月更文挑战
前言
在项目开发中,无论是移动端还是PC端,Modal对话框大概是绕不过去的一个功能性组件吧?
常用于重要消息提示,例如网络请求失败等信息,授权访问类功能等情况的信息提示。
相较于上文的Message消息组件,Modal对话框组件的信息提示则更显正式,也更醒目。
默认情况下,我们可以使用window.alert()方法弹出信息提示,或者使用window.prompt()方法弹出输入框和用户进行交互。如下图。
但是这都1202年了,用这样的框不但显得很有时代气息,同时弹框会阻拦系统进程,用于生产环境时怕是会烦死人吧。
所以,时至今日,成熟的组件化早就替代了上个时代的默认系统框了,即便并非自己开发的,市场也有大量成熟的组件库任君采撷。
从结构开始
即便是从默认的系统组件我们也能看出,一个合格的对话框组件,最基本的信息是包含标题、内容、操作按钮的。并且对比两框,取消按钮是可选的,需要状态控制。
并且参考市面上组件库的开发方案,可选的还有是否有蒙版背景,是否有关闭按钮,是否支持点击非组件去关闭的交互。这里也会一并解析。
先布局基本结构。
这一块主要是样式写布局,没什么大的注意事项,把前面说的几个点都考虑一下, 布局就比较随心的。即便是工作中也无非是遵循产品主题。
block content
div(style="display:inline-block")
teleport(
to="body"
:disabled="!teleport"
)
transition(name="fade" appear)
div(
class="yx-mask"
@click="maskCancel"
v-if="isShow"
)
div(
class="yx-modal"
:class="{confirm: type !== '' }"
)
transition(
name="scale"
@before-enter="setOrigin"
@before-leave="setOrigin"
@after-leave="afterLeave"
appear
)
div(
class="yx-modal-content"
v-show="isShow"
:class="{'yx-modal-confirm-wrap': type !== ''}"
:style="modalStyle"
)
div(
class="yx-modal-close"
v-if="closable"
@click="cancel"
)
i.yx-icon-x
div.yx-modal-head
template(v-if="!$slots.head")
i(
v-if="type !== ''"
:class="iconType[type]"
)
| {{title}}
slot(
v-else
name="head"
)
div.yx-modal-body
template(v-if="type !== ''") {{content}}
slot(v-else)
div.yx-modal-footer
template(v-if="!$slots.footer")
yx-button(
class="yx-modal-btn"
v-if="!((type !== '') & (type !== 'confirm'))"
plain
@click="cancel"
) {{cancelText}}
yx-button(
class="yx-modal-btn"
type="primary"
:loading="loading"
@click="confirm"
) {{confirmText}}
slot(v-else name="footer")
这里的按钮用的是之前的Button按钮组件,也可以直接用button标签。
布局随意看看就好,并没有什么固定的说法,按照产品主题或者设计走就行了。
逻辑部分
几个主要的事件
// 是否点击遮罩关闭弹框, maskClosable来自props
const {maskClosable} = toRefs(props);
const maskcancel = () => {
if(maskClosable.value) cancel()
}
// 关闭组件事件,并且调用父级的事件
const cancel = () => {
isShow.value = false;
emits('update:modelValue', isShow.value);
emits('cancel');
props.onCancel && props.onCancel()
}
// 确认事件,同上
const confirm = () => {
emits('confirm');
props.onConfirm && props.onConfirm()
nextTick(() => {
if(!loading.value){
isShow.value = false;
emits('update:modelValue', isShow.value)
}
})
}
挂载组件
这个组件可以是单一的,也可以设计成不同状态的组件,所以挂载的时候可以参考上一章的Message消息组件,供调用不同状态的组件。
// index.js
import Modal from './modal.vue';
export function createComponent(component, props){
const vnode = h(component, props)
render(vnode, document.createElement('div'))
return vnode.component
}
Modal.install = function(app){
app.component('modal', element);
}
let mouseClick;
const getClickPosition = e => {
mouseClick = {
x: e.clientX,
y: e.clientY
}
setTimeout(() => (mouseClick = null), 100);
}
document.addEventListener('click', getClickPosition, true);
function ModalsCreate(option, type){
const props = {
...option,
type,
mouseCLick,
teleport:false,
modalValue: true
}
document.body.style.overflow = 'hidden';
const component = createComponent(Modal, props);
document.body.appendChild(component.vnode.el);
}
let oneKey = null;
;['info','error','success','warning', 'confirm'].forEach(type => {
oneKey || (oneKey = type);
Modal[type] = props => ModalsCreate(props, type)
})
export default Modal;