从 Thickbox 到原生 <dialog>:WPJAM Basic 已经实现了 WordPress 弹窗全面升级
熟悉 WordPress 后台开发的都知道,长期以来后台弹窗默认依赖 Thickbox 实现。
我之前也专门整理过文章,讲解 Thickbox 在 WordPress 中的用法与适配实践:在 WordPress 后台使用 ThickBox 制作弹出窗的教程。
但随着现代浏览器标准完善,原生 HTML <dialog> 标签已经全面普及,用来做弹窗比 Thickbox 更简洁、原生、无依赖、体验更好。
所以 WPJAM Basic 新版已经正式弃用 Thickbox,全面切换为原生 <dialog> 弹窗。
为什么放弃 Thickbox
Thickbox 是 jQuery 时代的老牌弹窗插件,由 Cody Lindley 开发,核心版本冻结在 3.1(2007 年),2009 年 9 月 30 日正式停止维护,至今已超过 15 年无更新。官网已明确标注 “不再维护,建议使用替代方案”。尽管长期被 WordPress 后台默认集成,但它已彻底成为 “遗留组件”:依赖老旧 jQuery 1.x、无响应式适配、缺少无障碍支持、在现代浏览器与移动端存在兼容性缺陷,且无法适配现代布局与交互标准。
而 <dialog> 是浏览器原生支持的标准标签,语义化、原生自带弹窗逻辑。

目前主流现代浏览器全都完整支持 <dialog>,除了可怜的 IE,不过我们是在 WordPress 后台后使用,运行环境完全可以覆盖,也无需兼容老旧低端浏览器。
相比 Thickbox 需要写复杂的 CSS 和 JS 来实现垂直和水平居中,原生 <dialog> 标签完全不用额外写任何样式,浏览器默认就自动垂直水平居中,省去大量样式适配和定位调试的麻烦,并且还原生自带遮罩层。
而且 <dialog> 自定义自由度更高,可以随意定制弹窗外观、标题栏、关闭按钮和内容区域,轻松适配 WordPress 后台设计风格;
同时开发更简单、代码更轻量化,原生自带遮罩层、模态锁定、ESC 关闭等能力,不用像 Thickbox 那样手动处理层级冲突、滚动穿透、定位偏移等各种兼容问题,几行代码就能实现标准弹窗效果。
比如我们要实现一个简单的弹窗,首先只需要简单的 HTML 代码:
<dialog id="my-dialog">
<p>弹窗内容</p>
<button class="close-dialog">关闭</button>
</dialog>
然后就可以通过 JS 代码实现打开和关闭
// 打开弹窗
$('#my-dialog')[0].showModal();
// 关闭弹窗
$('#my-dialog')[0].close();
汇总在一起,下面这个例子就是通过页面上的按钮打开弹窗了,然后弹窗中也有按钮可以关闭它。
<button class="open-dialog-btn">打开弹窗</button>
<dialog id="my-dialog" style="padding:20px;">
<h3>原生 Dialog</h3>
<p>WordPress 后台推荐使用!</p>
<button class="close-dialog">关闭</button>
</dialog>
<script>
jQuery(function($){
// 打开
$('.open-dialog-btn').on('click', function(){
$('#my-dialog')[0].showModal();
});
// 关闭
$('.close-dialog').on('click', function(){
$('#my-dialog')[0].close();
});
});
</script>
此外还可以动态创建弹窗,以及监控关闭等事件,后面我在 WPJAM Basic 插件中的实现会详细展示如何动态创建,以及如何使用和自定义事件。
WPJAM Basic 封装的 dialog 方法
为了方便统一调用,WPJAM Basic 基于原生 <dialog> 封装了 wpjam.dialog() 方法,可以一键实现动态实现弹窗,以及事件监控:
wpjam.dialog = function(...args){
let id = 'wpjam_dialog';
// 无参数:返回当前打开的弹窗实例
if(!args.length){
return $('#'+id+'[open]');
}
// 获取弹窗 DOM
let $dialog = $('#'+id);
// 如果是 close 命令:关闭弹窗
if(args[0] === 'close'){
return $dialog[0]?.close(args[1]);
}
// 获取弹窗配置参数
let data = args[0];
// 弹窗不存在:创建弹窗结构并插入页面
if(!$dialog[0]){
$dialog = $('<dialog id="'+id+'" class="wpjam-dialog"><div class="title"><h2></h2><button type="button" commandfor="'+id+'" command="close"></button></div><div class="content"></div></dialog>').appendTo('body');
// 弹窗关闭事件
$dialog.on('close', ()=> {
// 触发关闭自定义事件
$dialog.trigger('wpjam:dialog:closed');
}).on('click', 'button[command="close"]', ()=> $dialog[0].close());
}
// 设置弹窗宽度、标题、内容
$dialog.css('width', (data.width || 700)+'px')
.find('h2').text(data.page_title || '').end()
.find('.content').html(data.form || data.data || '');
// 原生方法:打开模态弹窗
$dialog[0].showModal();
// 触发打开自定义事件
$dialog.trigger('wpjam:dialog:opened');
return $dialog;
};
然后可以通过下面的代码进行调用:
// 打开弹窗
wpjam.dialog({
page_title: '弹窗标题',
data: '这里是弹窗内容',
width: 700
});
// 关闭弹窗
wpjam.dialog('close');
比如 WordPress 后台文章列表页面快速编辑的弹窗:

遇到的小问题,媒体库被遮挡
原以为这样就搞定了,很快就遇到了一个小问题:在弹窗里打开 WordPress 媒体上传器,会被挡在后面。
究其原因,原生 <dialog> 自带顶层图层隔离,后续弹出的媒体框无法穿透层级,被压在后面。
解决这个问题,也非常简单:
打开 WordPress 媒体选择弹窗时,先临时关闭当前 <dialog>
wpjam.dialog('close', 'temp');
媒体弹窗选择完成、关闭之后,再重新唤起 <dialog>
wpjam.dialog('show', '');
大概的代码是:
wp.media(args).on('open', function(){
wpjam.dialog('close', 'temp');
// 其他媒体库初始化代码
}).on('select', function(){
// 选择媒体相关代码
}).on('close', function(){
wpjam.dialog('show', '');
}).open();
然后增强一下 wpjam.dialog 相关代码,实现临时关闭,和显示的功能:
// WPJAM 原生 Dialog 封装方法
wpjam.dialog = function(...args){
let id = 'wpjam_dialog';
// 无参数调用:返回当前处于打开状态的弹窗实例
if(!args.length){
return $('#'+id+'[open]');
}
// 获取弹窗 jQuery 对象
let $dialog = $('#'+id);
// 调用方式一:关闭弹窗
if(args[0] === 'close'){
// 支持带返回值关闭 / 直接关闭
return args[1] ? $dialog[0]?.close(args[1]) : $dialog[0]?.close();
}
// 调用方式二:显示弹窗
else if(args[0] === 'show'){
// 如果弹窗存在且未打开,则重新显示
if($dialog[0] && !$dialog[0].open){
$dialog[0].returnValue = '';
$dialog[0].showModal();
}
return;
}
// 调用方式三:传入配置,打开弹窗
let data = args[0];
// 弹窗 DOM 不存在,则动态创建弹窗结构
if(!$dialog[0]){
$dialog = $('<dialog id="'+id+'" class="wpjam-dialog"><div class="title"><h2></h2><button type="button" commandfor="'+id+'" command="close"></button></div><div class="content"></div></dialog>').appendTo('body');
// 监听弹窗关闭事件
$dialog.on('close', ()=> {
// 如果是临时关闭(temp),不执行后续逻辑
if($dialog[0].returnValue == 'temp'){
return;
}
// 触发弹窗关闭完成自定义事件
$dialog.trigger('wpjam:dialog:closed');
}).on('click', 'button[command="close"]', ()=> $dialog[0].close()); // 点击关闭按钮,关闭弹窗
}
// 设置弹窗宽度、标题、内容
$dialog.css('width', (data.width || 700)+'px')
.find('h2').text(data.page_title || '').end()
.find('.content').html(data.form || data.data || '');
// 调用浏览器原生 API 打开模态弹窗
$dialog[0].showModal();
// 触发弹窗打开自定义事件
$dialog.trigger('wpjam:dialog:opened');
return $dialog;
};
用「临时关闭 + 事后恢复」的方式,完美解决层级遮挡冲突,优雅又省事。
简单总结一下
- WordPress 传统 Thickbox 弹窗老旧笨重,可逐步淘汰;
- 原生的 HTML
<dialog>标签 更标准、更轻量、更易用,是后台弹窗的最优替代方案; - WPJAM Basic 已完成全面封装,统一
wpjam.dialog()调用,结构规范、事件完善; - 遇到媒体弹窗层级遮挡,用「临时 close + 事后 show」即可轻松解决,WPJAM Basic 内置的媒体弹窗已经内置实现。
后续开发 WordPress 后台功能,完全可以直接用原生 <dialog> 替代 Thickbox,开发效率和体验都会提升一大截。