原生 js - showModal 显示一个模态对话框。
loading
参数
textOrOptions
: string | Object - 对话框显示的文本内容或配置选项options
: Object - 配置选项text
: string - 对话框显示的文本内容(当第一个参数为对象时使用)title
: string - 对话框标题,默认为'提示'type
: string - 对话框类型,可选值:'success'|'info'|'warning'|'error'showCancel
: boolean - 是否显示取消按钮,默认 falseshowIcon
: boolean - 是否显示图标,默认 trueonConfirm
: Function - 点击确认按钮的回调函数onCancel
: Function - 点击取消按钮的回调函数
使用示例
javascript
// 基础用法
showModal('操作成功')
// 快捷方式调用
showModal.success('保存成功')
showModal.error('操作失败')
// 带确认和取消回调
showModal('是否删除?', {
type: 'warning',
showCancel: true,
onConfirm: () => {
console.log('确认删除')
},
onCancel: () => {
console.log('取消删除')
}
})
源码
源码
js
/**
* 显示一个模态对话框
* @author chuxiao
* @param {string|Object} textOrOptions - 对话框显示的文本内容或配置选项
* @param {Object} [options={}] - 配置选项
* @param {string} [options.text] - 对话框显示的文本内容(当第一个参数为对象时使用)
* @param {string} [options.title='提示'] - 对话框标题
* @param {string} [options.type=''] - 对话框类型,可选值:'success'|'info'|'warning'|'error'
* @param {boolean} [options.showCancel=false] - 是否显示取消按钮
* @param {boolean} [options.showIcon=true] - 是否显示图标
* @param {Function} [options.onConfirm=()=>{}] - 点击确认按钮的回调函数
* @param {Function} [options.onCancel=()=>{}] - 点击取消按钮的回调函数
* @example
* // 基础用法-直接传文本
* showModal('操作成功');
*
* // 快捷方式调用
* showModal.success('操作成功');
* showModal.error('操作失败');
*
* // 基础用法-通过options传文本
* showModal({
* text: '操作成功',
* showIcon: true
* });
*
* // 带类型的提示
* showModal('保存成功', {
* title: '系统提示',
* type: 'success',
* onConfirm: () => {
* console.log('确认');
* }
* });
*
* // 带确认和取消回调
* showModal('是否删除?', {
* type: 'warning',
* showCancel: true,
* onConfirm: () => {
* console.log('确认删除');
* },
* onCancel: () => {
* console.log('取消删除');
* }
* });
*/
function showModal(textOrOptions, options = {}) {
let text, finalOptions
if (typeof textOrOptions === 'string') {
text = textOrOptions
finalOptions = options
} else {
text = textOrOptions.text || ''
finalOptions = textOrOptions
}
const {
title = '提示',
type = '',
showCancel = false,
showIcon = true,
onConfirm = () => {},
onCancel = () => {}
} = finalOptions
const iconColorMap = {
success: '#4CAF50',
info: '#2196F3',
warning: '#ff9800',
error: '#f44336'
}
const svgIcons = {
success: `<svg viewBox="0 0 1024 1024" width="20" height="20"><path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm193.5 301.7l-210.6 292a31.8 31.8 0 0 1-51.7 0L318.5 484.9c-3.8-5.3 0-12.7 6.5-12.7h46.9c10.2 0 19.9 4.9 25.9 13.3l71.2 98.8 157.2-218c6-8.3 15.6-13.3 25.9-13.3H699c6.5 0 10.3 7.4 6.5 12.7z" fill="${iconColorMap[type]}"/></svg>`,
info: `<svg viewBox="0 0 1024 1024" width="20" height="20"><path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm32 664c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8V456c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v272zm-32-344c-26.5 0-48-21.5-48-48s21.5-48 48-48 48 21.5 48 48-21.5 48-48 48z" fill="${iconColorMap[type]}"/></svg>`,
warning: `<svg viewBox="0 0 1024 1024" width="20" height="20"><path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm-32 232c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v272c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8V296zm32 440c-26.5 0-48-21.5-48-48s21.5-48 48-48 48 21.5 48 48-21.5 48-48 48z" fill="${iconColorMap[type]}"/></svg>`,
error: `<svg viewBox="0 0 1024 1024" width="20" height="20"><path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359c-1.2-1.5-1.9-3.3-1.9-5.2 0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z" fill="${iconColorMap[type]}"/></svg>`
}
// document.body.style.overflow = 'hidden'
const mask = document.createElement('div')
mask.style.cssText = `
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.6);
display: flex;
justify-content: center;
align-items: center;
z-index: 999;
backdrop-filter: blur(3px);
margin: 0;
padding: 0;
`
if (showCancel) {
mask.onclick = e => {
if (e.target === mask) {
closeModal()
onCancel()
}
}
}
const modal = document.createElement('div')
modal.style.cssText = `
background: white;
padding: 16px 20px;
border-radius: 8px;
min-width: 320px;
max-width: 360px;
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
animation: modalFadeIn 0.3s ease;
position: relative;
margin: 0;
`
const titleEl = document.createElement('h3')
titleEl.textContent = title
titleEl.style.cssText = `
font-size: 16px;
color: #333;
margin: 0 0 12px 0;
padding: 0 0 8px 0;
border-bottom: 1px solid #eee;
text-align: left;
`
modal.appendChild(titleEl)
if (showCancel) {
const closeBtn = document.createElement('div')
closeBtn.innerHTML = '×'
closeBtn.style.cssText = `
position: absolute;
right: 16px;
top: 12px;
font-size: 22px;
color: #999;
cursor: pointer;
line-height: 1;
margin: 0;
padding: 0;
`
closeBtn.onclick = () => {
closeModal()
onCancel()
}
modal.appendChild(closeBtn)
}
const contentWrapper = document.createElement('div')
contentWrapper.style.cssText = `
display: flex;
align-items: center;
gap: 8px;
margin: 12px 0;
padding: 0;
`
if (showIcon && type && svgIcons[type]) {
const iconContainer = document.createElement('div')
iconContainer.innerHTML = svgIcons[type]
iconContainer.style.cssText = `
flex-shrink: 0;
display: flex;
align-items: center;
margin: 0;
padding: 0;
`
contentWrapper.appendChild(iconContainer)
}
const content = document.createElement('div')
content.textContent = text
content.style.cssText = `
font-size: 14px;
color: #666;
line-height: 1.5;
margin: 0;
padding: 0;
flex: 1;
`
contentWrapper.appendChild(content)
modal.appendChild(contentWrapper)
const btnContainer = document.createElement('div')
btnContainer.style.cssText = `
display: flex;
justify-content: flex-end;
gap: 12px;
margin: 16px 0 0 0;
padding: 0;
`
if (showCancel) {
const cancelBtn = document.createElement('button')
cancelBtn.textContent = '取消'
cancelBtn.style.cssText = `
padding: 6px 20px;
cursor: pointer;
background: #f5f5f5;
color: #666;
border: none;
border-radius: 4px;
font-size: 14px;
transition: all 0.3s ease;
margin: 0;
`
cancelBtn.onmouseover = () => {
cancelBtn.style.background = '#e0e0e0'
cancelBtn.style.transform = 'scale(1.05)'
}
cancelBtn.onmouseout = () => {
cancelBtn.style.background = '#f5f5f5'
cancelBtn.style.transform = 'scale(1)'
}
cancelBtn.onclick = () => {
closeModal()
onCancel()
}
btnContainer.appendChild(cancelBtn)
}
const confirmBtn = document.createElement('button')
confirmBtn.textContent = '确定'
confirmBtn.style.cssText = `
padding: 6px 20px;
cursor: pointer;
background: ${type ? iconColorMap[type] : '#2196F3'};
color: white;
border: none;
border-radius: 4px;
font-size: 14px;
transition: all 0.3s ease;
margin: 0;
`
confirmBtn.onmouseover = () => {
confirmBtn.style.opacity = '0.9'
confirmBtn.style.transform = 'scale(1.05)'
}
confirmBtn.onmouseout = () => {
confirmBtn.style.opacity = '1'
confirmBtn.style.transform = 'scale(1)'
}
confirmBtn.onclick = () => {
closeModal()
onConfirm()
}
btnContainer.appendChild(confirmBtn)
modal.appendChild(btnContainer)
const style = document.createElement('style')
style.textContent = `
@keyframes modalFadeIn {
from {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes modalFadeOut {
from {
opacity: 1;
transform: translateY(0);
}
to {
opacity: 0;
transform: translateY(20px);
}
}
`
document.head.appendChild(style)
mask.appendChild(modal)
document.body.appendChild(mask)
function closeModal() {
modal.style.animation = 'modalFadeOut 0.3s ease forwards'
mask.style.opacity = '0'
mask.style.transition = 'opacity 0.3s ease'
setTimeout(() => {
document.body.style.overflow = ''
document.body.removeChild(mask)
document.head.removeChild(style)
}, 300)
}
}
// 添加快捷方式
;['success', 'info', 'warning', 'error'].forEach(type => {
showModal[type] = (text, options = {}) => {
return showModal(text, { ...options, type })
}
})
:::