From 6c18dd38f4a641bd6c93d3adb0831b633fa03caf Mon Sep 17 00:00:00 2001 From: Council Date: Sat, 25 Apr 2026 19:40:49 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E8=BF=BD=E5=8A=A0=E7=BB=8F=E9=AA=8C#19?= =?UTF-8?q?=20=E2=80=94=20AdminSidebarInit=20items=20vs=20item=20=E5=B1=9E?= =?UTF-8?q?=E6=80=A7=E5=90=8D=E9=99=B7=E9=98=B1=20+=20=E6=A3=80=E6=9F=A5?= =?UTF-8?q?=E6=B8=85=E5=8D=95=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/EXPERIENCES.md | 68 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/docs/EXPERIENCES.md b/docs/EXPERIENCES.md index 46fdbbd..bc02298 100644 --- a/docs/EXPERIENCES.md +++ b/docs/EXPERIENCES.md @@ -342,6 +342,73 @@ class Index --- +### 19. AdminSidebarInit 子菜单:`items`(复数)不是 `item`(单数) + +**症状**:sidebar 显示"VR票务"顶级菜单,但子菜单项(场馆配置/座位模板/电子票等)全部丢失,控制台无报错。 + +**根因**:`Hook.php` 的 `AdminSidebarInit` 里,子菜单数组的 key 写成 `item`: + +```php +// ❌ 错误:ShopXO 渲染器不认识 `item` +$params[] = [ + 'id' => 'plugins-vr_ticket', + 'name' => 'VR票务', + 'item' => [ // ← 单数,ShopXO sidebar 不认 + ['name' => '场馆配置', 'url' => ..., 'is_show' => 1], + ['name' => '座位模板', 'url' => ..., 'is_show' => 1], + ] +]; +``` + +ShopXO 后台 sidebar 模板(`app/admin/view/default/public/menu.html`)渲染逻辑: + +```html +{{foreach $left_menu as $v}} + {{if empty($v['items'])}} + {{else /}} + + {{/if}} +{{/foreach}} +``` + +ShopXO 渲染器检查的是 **`items`(复数)**,不是 `item`(单数)。`item` 被当作普通属性忽略,所有子菜单项静默丢失。 + +**修复**: + +```php +// ✅ 正确:`items` 复数 +$params[] = [ + 'id' => 'plugins-vr_ticket', + 'name' => 'VR票务', + 'items' => [ // ← 复数,ShopXO sidebar 渲染器认识 + ['name' => '场馆配置', 'url' => ..., 'is_show' => 1], + ['name' => '座位模板', 'url' => ..., 'is_show' => 1], + ] +]; +``` + +**调试方法**:在浏览器控制台执行: + +```javascript +// 提取 sidebar 中所有菜单项 URL +const items = document.querySelectorAll('a.menu-item'); +const vr = []; +items.forEach(a => { + const t = a.textContent.trim(); + if(t.includes('VR')||t.includes('票务')||t.includes('场馆')||t.includes('座位')) + vr.push(a.href + ' => ' + t); +}); +console.log(vr.join('\n')); +``` + +对比 `Hook.php` 中注册的所有 URL,即可发现哪些子菜单项未出现在 DOM 中。 + +**教训**:ShopXO 大量使用复数形式约定(`items`、`menus`、`params`),遇到"数据明明传了但不渲染"的问题时,优先检查属性名的单复数是否与渲染器约定一致。 + +--- + ## 📌 开发前检查清单 接手本插件时,逐项确认以下内容: @@ -351,6 +418,7 @@ class Index - [ ] 引用 JS/CSS 前先查 ShopXO 是否已自带(`public/static/common/lib/`),优先本地文件而非 CDN - [ ] 插件模板使用 `$public_host` 时,控制器已显式传递(不依赖框架自动赋值) - [ ] Hook.php 返回数组包含 `id`、`url`、`name`、`is_show` +- [ ] Hook.php `AdminSidebarInit` 子菜单数组的 key 是 `items`(复数),不是 `item`(单数) - [ ] Admin.php 有缓存锁机制保护 `initialize()` 免于每次请求检查表 - [ ] 改字段名之前查过 Service 层源码或实际表结构 - [ ] 插件视图路径使用 `../../../plugins/vr_ticket/view/...` 前缀