交互层只有一个文件 src/plui.js,只依赖你上传的 src/common.js(sx 函数库),不引入 jQuery。
全局对象是 window.plui,版本号 plui.version。
页面里写好 data-plui-*,脚本在 DOM 就绪后自动绑定,不用写一行 JS。
<button data-plui-toggle="modal" data-plui-target="#my-modal">打开</button>
<div class="plui-modal" id="my-modal" tabindex="-1">
<div class="plui-modal-dialog">
<div class="plui-modal-header"><h5 class="plui-modal-title">标题</h5>
<button data-plui-dismiss="modal" aria-label="关闭">×</button></div>
<div class="plui-modal-body">内容</div>
</div>
</div>
每个组件都是构造函数,可以 new,也可以走静态方法。
var modal = new plui.Modal(document.getElementById('my-modal'), { backdrop: true, keyboard: true });
modal.show();
plui.Modal.getInstance(el); // 取已有实例,没有返回 null
plui.Modal.getOrCreateInstance(el); // 有就取,没有就建
| 约定 | 说明 |
|---|---|
| 方法 | show() hide() toggle() dispose();返回实例自身,可链式调用 |
| 事件 | show.bs.plui shown.bs.plui hide.bs.plui hidden.bs.plui,全部冒泡 |
| 组件专属事件 | 额外发一份 show.bs.plui.modal、hide.bs.plui.toast 这样的精确事件 |
| 可取消 | show 与 hide 事件 cancelable,在监听器里 e.preventDefault() 即可中止 |
| 事件对象 | e.detail 带 relatedTarget(触发元素)等上下文 |
| 事件细节 | e.target 是组件元素,e.currentTarget 是监听器所在的元素 |
| 销毁 | dispose() 会解绑事件、移除遮罩、归还焦点、恢复滚动条 |
document.addEventListener('show.bs.plui', function (e) {
if (e.target.id === 'my-modal') { e.preventDefault(); } // 拦下这一次打开
});
| 组件 | 构造函数 | 特有方法 | 配置项(默认值) | data 属性 | |
|---|---|---|---|---|---|
| 模态框 Modal | new plui.Modal(el, cfg) | show/hide/toggle | backdrop:true focus:true keyboard:true | data-plui-toggle="modal" data-plui-target data-plui-dismiss="modal" | |
| 离屏面板 Offcanvas | new plui.Offcanvas(el, cfg) | show/hide/toggle | backdrop:true focus:true keyboard:true | data-plui-toggle="offcanvas" data-plui-dismiss="offcanvas" | |
| 下拉菜单 Dropdown | new plui.Dropdown(el, cfg) | show/hide/toggle | autoClose:true | data-plui-toggle="dropdown" | |
| 折叠面板 Collapse | new plui.Collapse(el, cfg) | show/hide/toggle | toggle:true | data-plui-toggle="collapse" data-plui-target data-plui-parent | |
| 标签页 Tab | new plui.Tab(el, cfg) | show | — | data-plui-toggle="tab" / "pill" data-plui-target | |
| 轮播 Carousel | new plui.Carousel(el, cfg) | to/next/prev/cycle/pause | interval:5000 ride:false wrap:true | data-plui-ride="carousel" `data-plui-slide="next | prev"` |
| 吐司 Toast | new plui.Toast(el, cfg) | show/hide/isShown | autohide:true delay:3000 | data-plui-dismiss="toast" data-plui-autohide | |
| 工具提示 Tooltip | new plui.Tooltip(el, cfg) | show/hide/toggle | placement:'top' offset:8 trigger:'hover focus' | data-plui-toggle="tooltip" data-plui-title | |
| 弹出框 Popover | new plui.Popover(el, cfg) | show/hide/toggle | placement:'top' offset:8 | data-plui-toggle="popover" data-plui-title data-plui-content | |
| 滚动监听 ScrollSpy | new plui.ScrollSpy(el, cfg) | refresh | offset:100 | data-plui-spy data-plui-target | |
| 提示框 Alert | new plui.Alert(el, cfg) | close | dismissible:true | data-plui-dismiss="alert" | |
| 按钮 Button | new plui.Button(el, cfg) | toggle | — | data-plui-toggle="button" |
var m = plui.Modal.getOrCreateInstance('#my-modal');
m.show(); // 打开:加 .plui-show、插遮罩、锁滚动条、焦点进面板
m.hide(); // 关闭:移遮罩、解锁滚动条、焦点还给触发按钮
m.toggle();
m.dispose();
body 加 .plui-modal-open,滚动条锁定并按滚动条宽度补 padding-right,避免页面横向跳动。keyboard:false 可关掉);Tab 在面板内循环,不会跑到面板外。backdrop:false 时不插遮罩,也不锁滚动。与模态框同一套骨架,差别是:面板从四边滑入(.plui-offcanvas-start/-end/-top/-bottom),遮罩类是 .plui-offcanvas-backdrop,滚动条锁定同样生效。
<div class="plui-accordion" id="acc">
<div class="plui-accordion-item">
<h3><button class="plui-accordion-button" data-plui-toggle="collapse" data-plui-target="#p1">一</button></h3>
<div class="plui-accordion-collapse" id="p1">
<div class="plui-accordion-body">…</div>
</div>
</div>
</div>
同一 data-plui-parent 下的面板互斥:展开一个会自动收起同组的其它面板,并同步 aria-expanded。
var c = plui.Carousel.getOrCreateInstance('#hero');
c.next(); c.prev(); c.to(2); c.pause(); c.cycle();
data-plui-slide="next|prev" 自动绑定。slide.bs.plui(可取消,取消则不切换),切换完成发 slid.bs.plui。plui.toast.notify({ title: '已保存', body: '内容已写入', delay: 3000 });
自动在页面里找 .plui-toast-container;没有就新建一个。返回 Toast 实例,可以继续 hide()。
定位引擎会按可用空间自动翻转(顶部放不下就翻到下方),并写 data-plui-placement 标明最终位置。
<button data-plui-toggle="popover" data-plui-title="标题" data-plui-content="正文">点我</button>
鼠标悬停与键盘聚焦都会触发,Esc 关闭。
<nav class="plui-scrollspy-nav" data-plui-spy="#spy">
<a class="plui-scrollspy-link" href="#a">A</a>
</nav>
滚动时命中项加 .active 并写 aria-current="true",其余项清掉。offset 用来抵消吸顶导航的高度。
| 项目 | 做法 |
|---|---|
| 焦点管理 | 模态框 / 离屏面板打开时焦点进入面板,关闭后归还触发元素 |
| 焦点陷阱 | 面板内 Tab / Shift+Tab 循环,不会跑到背景内容 |
| Esc | 浮层(模态框、离屏面板、工具提示、弹出框)一律可 Esc 关闭 |
| 键盘 | 轮播支持左右方向键;下拉菜单支持上下方向键;标签页用 Tab 进入后用方向键切换 |
| ARIA | 标签页 aria-selected,折叠 aria-expanded,滚动监听 aria-current,吐司 role="status" aria-live="polite" |
| 隐藏 | 隐藏内容用 display:none(读屏不读),仅给读屏的文本用 .plui-sr-only |
| 对比度 | 文字色板按 WCAG AA 校准(正文 21:1,次级 7.5:1,弱化 4.8:1) |
show.bs.plui,不是 show.bs.modal;组件专属事件另发 show.bs.plui.modal,两者都发。new plui.X(el) 创建,Bootstrap 5 用 new bootstrap.Modal(el),习惯一致。preventOverflow 与虚拟元素等高级能力。data-bs-* 属性别名,只认 data-plui-*。本页由 build/build-docs.mjs 从同名 Markdown 生成,请修改 .md 后重新生成,不要手工编辑本文件。