escapeChars: function (str) {
if (typeof str !== 'string') {
- q
str = String(str);
}q 是遗留的无效语句,应删除。
transformResponse: function (text, xhr, elt) {
if (xhr.getResponseHeader('Content-Type')
.includes('application/json')) {
const data = JSON.parse(xhr.responseText)
bny.alert(data.msg, data.code || 0, data.anim || 'scale', data.time || 3)
return elt.innerHTML
}
+ return text
}当响应非 JSON 时,没有 return text,会导致返回 undefined。
removeClass: function (elt, cls) {
if (!elt) console.error('removeClass: 元素不存在')
- if (typeof elt === 'object') {
+ if (typeof elt === 'object' && !Array.isArray(elt) && !(elt instanceof NodeList)) {
Object.keys(elt).forEach((key) => {
elt[key].classList.remove(cls)
})
+ return
}
if (Array.isArray(elt) || elt instanceof NodeList) {
Array.from(elt).forEach(e => e.classList.remove(cls))
return
}typeof elt === 'object' 会同时匹配普通对象和 NodeList,导致 NodeList 走不到正确分支。
当前所有组件只有初始化逻辑,没有清理逻辑。应利用 htmx:beforeCleanupNode 钩子:
// 示例:dropdown 清理
onEvent: function (name, evt) {
if (name === 'htmx:beforeCleanupNode') {
if (bny.hasExtName(evt.target, 'bny-dropdown')) {
const dropdown = bny.queryChild(evt.target, '.bny-dropdown')
if (dropdown) dropdown.remove()
// 移除 document 上绑定的 click 监听器
}
}
}所有 transformResponse 中的 JSON.parse 应加上 try-catch:
transformResponse: function (text, xhr, elt) {
if (xhr.getResponseHeader('Content-Type').includes('application/json')) {
try {
const data = JSON.parse(xhr.responseText)
// ...
} catch (e) {
console.error('[bny-menu] JSON 解析失败:', e)
return text
}
}
return text
}| 组件 | 需要支持的键盘操作 |
|---|---|
bny-menu |
↑↓ 导航、Enter 激活、Escape 关闭、→ 展开子菜单 |
bny-dropdown |
Escape 关闭、Tab 焦点管理 |
bny-tab |
←→ 切换标签、Delete 关闭(当 closable 时) |
bny-nav |
Tab 导航、Enter 激活 |
bny-collapse |
Enter/Space 切换展开 |
bny-confirm |
Enter 确认、Escape 取消 |
建议创建 types/bunny.d.ts,提供 API 智能提示:
declare namespace bny {
function alert(msg: string, code?: number, anim?: string, time?: number): void
function confirm(msg: string, options?: ConfirmOptions): void
function page(content: string, options?: PageOptions): HTMLElement
function load(style?: number, options?: LoadOptions): HTMLElement
// ...
}当前 312 行过于臃肿,建议拆分为:
tab-core.js— 初始化、标签切换、去重逻辑tab-scroll.js— 滚动按钮、左右滑动tab-close.js— 关闭当前/其他/全部逻辑
&[color="green"] {
border-color: var(--green);
- background-color: rgba(5, 150, 105, 0.08);
+ background-color: var(--green-alpha-10);
color: var(--green);
}在 base.css 中补充颜色半透明变量:
--green-alpha-10: rgba(5, 150, 105, 0.08);
--green-alpha-20: rgba(5, 150, 105, 0.15);
--blue-alpha-10: rgba(2, 132, 199, 0.08);
--yellow-alpha-10: rgba(217, 119, 6, 0.08);
--red-alpha-10: rgba(225, 29, 72, 0.08);- &[model~="border"] {
+ &[variant="border"] {
background-color: transparent;model 改为 variant 更符合业界惯例。
- & .col-xs-offset1 { grid-column-end: 2; }
+ & .col-xs-offset1 { grid-column-start: 2; }使用 grid-column-start 比 grid-column-end 更准确地表达"偏移"语义。
大量组件中 green/yellow/red/blue 四色变体代码重复,可考虑使用 CSS 预处理器或 PostCSS 插件(如 postcss-each)生成:
/* 伪代码示例 */
@each $color in green, yellow, red, blue {
&[color="$(color)"] {
background-color: var(--$(color));
border-color: var(--$(color));
}
}| 组件 | 说明 | 参考 API |
|---|---|---|
| Toast / Notification | 非阻塞式消息通知,支持多位置、多类型 | bny.toast('操作成功', { type: 'success' }) |
| Pagination | 分页组件,配合表格使用 | <div hx-ext="bny-page"> |
| Tooltip / Popover | 气泡提示,12 方向自动定位 | data-tooltip="提示内容" |
| Skeleton | 骨架屏加载占位 | <div class="bny-skeleton"> |
| 组件 | 说明 |
|---|---|
| Drawer | 屏幕边缘滑出面板,可替代 page 做侧边栏表单 |
| Upload | 拖拽上传 + 点击上传,hx-post 驱动 |
| Progress | 百分比进度条,支持条纹动画 |
| Breadcrumb | 面包屑导航 |
| Tree | 树形控件,可复用 menu 部分逻辑 |
| Carousel | 轮播图 |
| 组件 | 说明 |
|---|---|
| Steps | 步骤条,多步骤表单引导 |
| Timeline | 时间轴 |
| Avatar / Badge | 头像/徽标,纯 CSS 组件 |
| Rate | 星级评分 |
| DatePicker | 日期选择器,复杂度较高 |
| Image Preview | 图片预览,点击放大 |
Phase 1(补基础)
├── Bug 修复(3 项)
├── JSON 解析错误处理
├── Toast / Notification
└── Pagination
Phase 2(提体验)
├── 组件销毁机制
├── 键盘无障碍支持
├── Skeleton
├── Tooltip / Popover
└── Drawer
Phase 3(扩场景)
├── CSS 硬编码颜色变量化
├── Upload
├── Progress
├── Breadcrumb
└── Tree
Phase 4(增丰富)
├── button.css 属性语义化
├── tab.js 拆分重构
├── TypeScript 类型定义
├── Carousel / Steps / Timeline
└── Rate / Avatar / Badge
当前 bny 全局对象已提供 alert、confirm、page、load 四个顶层 API,建议新增:
window.bny = {
// 现有 API
alert: function (msg, code, anim, time) { ... },
confirm: function (msg, options) { ... },
page: function (content, options) { ... },
load: function (style, options) { ... },
// 建议新增
toast: function (msg, options) { ... }, // 通知
drawer: function (content, options) { ... }, // 抽屉
modal: function (content, options) { ... }, // 模态框(增强版 confirm)
}- 当前
test/目录下有丰富示例页面,但缺少组件 API 文档 - 建议为每个组件编写
data-*属性说明和 JavaScript API 说明 index.html中的文档站可进一步结构化