feat(mobile): 底部TabBar溢出「更多」机制+MobileSheet底部上滑竖向菜单(2026-09-08用户要求:tab多于4个时第5格收更多,点击弹竖菜单,选中项照常open_tab进内容区)——TabBar opts.more追加更多格(派发more事件,永不高亮);TabPanel createMobileBar按max_visible(默认4)切visible/overflow,more.dataurl动态项打开时实时拉(已购产线购买即出现,无需改index.ui);新增MobileSheet控件(蒙层9500>TabBar9000<PopupWindow10000起,功能弹窗不被蒙层挡;面板justify-content:flex-end贴底,column下align-items会挤右侧;同屏单例;_teardown自实现摘除防蒙层残留;popup:true项点击直接widgetBuild urlwidget走PopupWindow自开链路);css含dark变体
This commit is contained in:
parent
44411712d0
commit
5648da13c7
@ -1068,6 +1068,91 @@ hr {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* ══════════ MobileSheet 底部上滑竖向菜单(2026-09-08) ══════════
|
||||
「更多」溢出 tab / 手机端功能按钮收缩共用。
|
||||
蒙层盖全屏(含底部 TabBar 上方);z-index 高于 TabBar(9000)。 */
|
||||
.tabbar-more { flex: 0 0 auto; }
|
||||
.sheet-mask {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
/* 高于 TabBar(9000),低于 PopupWindow(app.new_zindex 从 10000 起)——
|
||||
sheet 里选「功能」项弹出的窗口必须盖在蒙层之上可交互 */
|
||||
z-index: 9500;
|
||||
background: rgba(15, 23, 42, 0.45);
|
||||
display: flex;
|
||||
/* VBox 基底是 flex column:主轴垂直,面板贴底用 justify-content
|
||||
(align-items:flex-end 在 column 下会把面板挤到右侧,实测会翻车) */
|
||||
justify-content: flex-end;
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
.sheet-mask-open { opacity: 1; }
|
||||
.sheet-panel {
|
||||
width: 100%;
|
||||
flex: 0 0 auto;
|
||||
max-height: 70vh;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
background: var(--sage-bg, #ffffff);
|
||||
border-radius: 16px 16px 0 0;
|
||||
padding: 8px 0 calc(12px + env(safe-area-inset-bottom, 0px));
|
||||
box-shadow: 0 -4px 24px rgba(15, 23, 42, 0.18);
|
||||
transform: translateY(100%);
|
||||
transition: transform 0.22s ease;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.sheet-panel-open { transform: translateY(0); }
|
||||
[data-theme="dark"] .sheet-panel {
|
||||
background: #0f172a;
|
||||
box-shadow: 0 -4px 24px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
.sheet-handle {
|
||||
flex: 0 0 auto;
|
||||
align-self: center;
|
||||
height: 4px;
|
||||
border-radius: 2px;
|
||||
background: #cbd5e1;
|
||||
margin: 4px auto 8px;
|
||||
}
|
||||
[data-theme="dark"] .sheet-handle { background: #475569; }
|
||||
.sheet-title {
|
||||
font-size: 12px;
|
||||
color: #94a3b8;
|
||||
padding: 0 20px 6px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.sheet-empty {
|
||||
font-size: 13px;
|
||||
color: #94a3b8;
|
||||
padding: 18px 20px;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.sheet-item {
|
||||
min-height: 48px; /* 触控目标 >= 44px */
|
||||
padding: 10px 20px !important;
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
transition: background 0.12s ease;
|
||||
}
|
||||
.sheet-item:active { background: rgba(37, 99, 235, 0.06); }
|
||||
.sheet-item-active { background: rgba(37, 99, 235, 0.08); }
|
||||
.sheet-item-active .sheet-item-label { color: #2563eb !important; font-weight: 600; }
|
||||
[data-theme="dark"] .sheet-item:active { background: rgba(96, 165, 250, 0.10); }
|
||||
[data-theme="dark"] .sheet-item-active { background: rgba(96, 165, 250, 0.12); }
|
||||
[data-theme="dark"] .sheet-item-active .sheet-item-label { color: #60a5fa !important; }
|
||||
.sheet-item-icon { font-size: 18px; flex: 0 0 auto; width: 26px; text-align: center; }
|
||||
.sheet-item-label { font-size: 15px; color: #1e293b !important; line-height: 1.4; }
|
||||
[data-theme="dark"] .sheet-item-label { color: #e2e8f0 !important; }
|
||||
.sheet-item-desc { font-size: 12px; color: #94a3b8 !important; line-height: 1.3; }
|
||||
|
||||
/* 胶囊切换条(ChipBar) */
|
||||
.chipbar {
|
||||
gap: 8px;
|
||||
@ -1112,7 +1197,13 @@ hr {
|
||||
/* ══════════ 手机视口全局规则(<=768px;平板按桌面处理) ══════════ */
|
||||
@media (max-width: 768px) {
|
||||
/* PopupWindow 全屏化:bricks 弹窗行内 width/height/left/top,用 !important 覆盖。
|
||||
* 只针对 .popupwindow —— 普通 .popup(下拉菜单/小提示)保持锚定小窗。
|
||||
* 只针对 .popupwindow —— 普通 .popup(下拉菜单/小提示)保持锚定小窗,
|
||||
* 但同样钳制 max-height 不许超出可视屏(2026-09-08 用户报障:
|
||||
* 弹出窗口/控件高度超出屏幕,要求高度=屏幕高)。
|
||||
* 100vh 在手机浏览器是 large viewport(含地址栏遮挡区),可能大于可视高,
|
||||
* 支持 dvh 的内核用 dvh(dynamic viewport,随地址栏收缩);
|
||||
* 不支持的(老微信 X5 等)由 popup.js _mobile_clamp 以 window.innerHeight
|
||||
* 实测内联 important 覆盖兜底(JS 权威,CSS 只是首帧静态兜底)。
|
||||
* 底部让出 TabBar 高度:全屏弹窗不盖住底部标签栏(2026-09-08 用户要求),
|
||||
* 用户随时可点 Tab 离开弹窗页 */
|
||||
.popupwindow {
|
||||
@ -1125,6 +1216,24 @@ hr {
|
||||
border-radius: 0 !important;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
/* 普通弹出控件(.popup:下拉/提示/锚定小窗)不许高出可视屏。
|
||||
* :not(.popupwindow) —— PopupWindow 同时带两个类,它的高度由上面
|
||||
* .popupwindow 规则钳制(要让出 TabBar),别被这里覆盖 */
|
||||
.popup:not(.popupwindow) {
|
||||
max-width: 100vw !important;
|
||||
max-height: calc(100vh - env(safe-area-inset-bottom, 0px)) !important;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
@supports (height: 100dvh) {
|
||||
.popupwindow {
|
||||
height: calc(100dvh - 56px - env(safe-area-inset-bottom, 0px)) !important;
|
||||
max-height: calc(100dvh - 56px - env(safe-area-inset-bottom, 0px)) !important;
|
||||
}
|
||||
.popup:not(.popupwindow) {
|
||||
max-height: calc(100dvh - env(safe-area-inset-bottom, 0px)) !important;
|
||||
}
|
||||
}
|
||||
/* 输入控件 16px:iOS Safari 对 <16px 输入框聚焦时自动放大页面 */
|
||||
.inputbox, .auto-textarea, textarea,
|
||||
input[type="text"], input[type="password"], input[type="number"], select {
|
||||
|
||||
143
bricks/mobile.js
143
bricks/mobile.js
@ -3,7 +3,9 @@
|
||||
// 提供:
|
||||
// bricks.is_mobile() — 当前是否手机视口(<=768px,平板按桌面)
|
||||
// bricks.on_mobile_mode(fn) — 视口模式变化监听(fn(is_mobile))
|
||||
// bricks.TabBar — 底部标签栏控件(手机专用,TabPanel mobile_bar 模式使用)
|
||||
// bricks.TabBar — 底部标签栏控件(手机专用,TabPanel mobile_bar 模式使用;
|
||||
// opts.more 时末尾追加「更多」格,点击派发 more 事件)
|
||||
// bricks.MobileSheet — 底部上滑竖向菜单(「更多」溢出项/功能按钮收缩用)
|
||||
// bricks.ChipBar — 横向胶囊切换条(dataurl 动态数据,select 事件带整条数据)
|
||||
|
||||
var bricks = window.bricks || {};
|
||||
@ -99,6 +101,12 @@ bricks.TabBar = class extends bricks.HBox {
|
||||
for (var i=0;i<this.bar_items.length;i++){
|
||||
this._create_item(this.bar_items[i]);
|
||||
}
|
||||
// 「更多」格(2026-09-08):opts.more = {label, icon},固定占末位;
|
||||
// 点击不走 command(不是 tab),派发 more 事件由宿主(TabPanel)弹 MobileSheet
|
||||
this.more_desc = opts.more || null;
|
||||
if (this.more_desc){
|
||||
this._create_more(this.more_desc);
|
||||
}
|
||||
this._start_badge_polling(opts.badge_interval || 60);
|
||||
}
|
||||
_create_item(item){
|
||||
@ -120,6 +128,20 @@ bricks.TabBar = class extends bricks.HBox {
|
||||
this.add_widget(cell);
|
||||
this.bar_btns[item.name] = {cell: cell, icon: icon, label: label, badge: badge};
|
||||
}
|
||||
_create_more(m){
|
||||
var cell = new bricks.VBox({css:'filler tabbar-item tabbar-more', gap:'1px', alignItems:'center'});
|
||||
var icon = new bricks.Text({otext: m.icon || '⋯', i18n: true, css:'tabbar-icon', cfontsize:1.3});
|
||||
var label = new bricks.Text({otext: m.label || '更多', i18n: true, css:'tabbar-label'});
|
||||
cell.add_widget(icon);
|
||||
cell.add_widget(label);
|
||||
cell.dom_element.style.cursor = 'pointer';
|
||||
var self = this;
|
||||
cell.bind('click', function(){ self.dispatch('more', m); });
|
||||
cell.dom_element.addEventListener('touchstart', function(){ cell.set_css('tabbar-item-press'); }, {passive:true});
|
||||
cell.dom_element.addEventListener('touchend', function(){ cell.set_css('tabbar-item-press', true); }, {passive:true});
|
||||
this.add_widget(cell);
|
||||
this.more_btn = {cell: cell, icon: icon, label: label};
|
||||
}
|
||||
_clicked(item){
|
||||
this.set_active(item.name);
|
||||
this.dispatch('command', item);
|
||||
@ -131,6 +153,8 @@ bricks.TabBar = class extends bricks.HBox {
|
||||
if (k === name) b.cell.set_css('tabbar-item-active');
|
||||
else b.cell.set_css('tabbar-item-active', true);
|
||||
}
|
||||
// 「更多」格永远不高亮为选中(它不是 tab,选中态属于 sheet 里的项)
|
||||
if (this.more_btn) this.more_btn.cell.set_css('tabbar-item-active', true);
|
||||
}
|
||||
set_badge(name, n){
|
||||
var b = this.bar_btns[name];
|
||||
@ -176,6 +200,123 @@ bricks.TabBar = class extends bricks.HBox {
|
||||
}
|
||||
bricks.Factory.register('TabBar', bricks.TabBar);
|
||||
|
||||
/* ══════════════════════════ MobileSheet ══════════════════════════
|
||||
底部上滑竖向菜单(2026-09-08)。两个场景:
|
||||
1. TabPanel mobile_bar 的「更多」溢出项(第 5 格起收进来,含 dataurl 动态项
|
||||
如已购产线)—— select 后宿主 open_tab;
|
||||
2. 手机端功能按钮收缩(agent_menus.dspy 桌面一排按钮 → 一个「⋯ 功能」按钮
|
||||
+ 本控件竖排),给会话区留最大空间 —— item.popup=true 时点击直接
|
||||
widgetBuild urlwidget(服务端返回 PopupWindow 自开,与桌面按钮同链路)。
|
||||
options: {
|
||||
title: 顶部小标题(可空)
|
||||
items: [{name, label, icon(emoji), desc(灰色小字), url, popup, active_tab, _raw}]
|
||||
selected: 高亮项 name
|
||||
empty_text: items 为空时的提示
|
||||
}
|
||||
events: select → item(派发后自动收起)
|
||||
用法:var sh = new bricks.MobileSheet({...}); sh.bind('select', fn); sh.open();
|
||||
同屏只保留一个实例(重复 open 自动收掉旧的)。
|
||||
*/
|
||||
bricks.MobileSheet = class extends bricks.VBox {
|
||||
constructor(opts){
|
||||
opts.width = '100%';
|
||||
opts.height = '100%';
|
||||
super(opts);
|
||||
this.set_css('sheet-mask');
|
||||
this.sheet_items = opts.items || [];
|
||||
this._closed = false;
|
||||
this.panel = new bricks.VBox({css:'sheet-panel', width:'100%', height:'auto'});
|
||||
var handle = new bricks.VBox({css:'sheet-handle', width:'36px', height:'4px'});
|
||||
this.panel.add_widget(handle);
|
||||
if (opts.title){
|
||||
this.panel.add_widget(new bricks.Text({text: opts.title, css:'sheet-title'}));
|
||||
}
|
||||
if (!this.sheet_items.length){
|
||||
this.panel.add_widget(new bricks.Text({
|
||||
text: opts.empty_text || '暂无内容', css:'sheet-empty'}));
|
||||
}
|
||||
for (var i=0;i<this.sheet_items.length;i++){
|
||||
this._create_row(this.sheet_items[i], opts.selected);
|
||||
}
|
||||
this.add_widget(this.panel);
|
||||
// 点蒙层收起;面板内点击不冒泡到蒙层
|
||||
var self = this;
|
||||
this.dom_element.addEventListener('click', function(e){
|
||||
if (e.target === self.dom_element) self.close();
|
||||
});
|
||||
this.panel.dom_element.addEventListener('click', function(e){ e.stopPropagation(); });
|
||||
}
|
||||
_create_row(item, selected){
|
||||
var row = new bricks.HBox({css:'sheet-item', width:'100%', height:'auto', gap:'12px', alignItems:'center'});
|
||||
if (item.icon){
|
||||
row.add_widget(new bricks.Text({text: item.icon, css:'sheet-item-icon'}));
|
||||
}
|
||||
var col = new bricks.VBox({css:'filler', gap:'2px'});
|
||||
col.add_widget(new bricks.Text({text: item.label || item.name || '', css:'sheet-item-label'}));
|
||||
if (item.desc){
|
||||
col.add_widget(new bricks.Text({text: item.desc, css:'sheet-item-desc'}));
|
||||
}
|
||||
row.add_widget(col);
|
||||
if (selected && item.name === selected){
|
||||
row.set_css('sheet-item-active');
|
||||
}
|
||||
row.dom_element.style.cursor = 'pointer';
|
||||
row.bind('click', this._row_clicked.bind(this, item));
|
||||
this.panel.add_widget(row);
|
||||
}
|
||||
_row_clicked(item){
|
||||
this.dispatch('select', item);
|
||||
// item.popup + url:直接构建(服务端 dspy 返回 PopupWindow 自开自挂 Body,
|
||||
// 与桌面功能按钮 actiontype=urlwidget 同一链路;非 Popup 结果忽略)。
|
||||
// 先收起 sheet 再构建:PopupWindow 的 z-index 从 10000 起(app.new_zindex),
|
||||
// sheet 蒙层 9500 —— 顺序无所谓,但收起后用户直接看到弹窗,无遮挡残影。
|
||||
if (item.url && item.popup){
|
||||
this.close();
|
||||
try {
|
||||
bricks.widgetBuild({"widgettype":"urlwidget","options":{"url":item.url}}, bricks.Body);
|
||||
} catch(e){ console.log('MobileSheet popup build error', e); }
|
||||
return;
|
||||
}
|
||||
this.close();
|
||||
}
|
||||
open(){
|
||||
// 同屏单例:先收掉已开的 sheet
|
||||
if (bricks.MobileSheet._cur && bricks.MobileSheet._cur !== this){
|
||||
try { bricks.MobileSheet._cur.close(); } catch(e){}
|
||||
}
|
||||
bricks.MobileSheet._cur = this;
|
||||
bricks.Body.add_widget(this);
|
||||
// 强制回流后直接加 open 类触发过渡(不用 rAF:手机浏览器后台/快速
|
||||
// 点击时 rAF 可能延迟合并帧 → 蒙层开着但面板不上滑的竞态)
|
||||
void this.dom_element.offsetHeight;
|
||||
this.set_css('sheet-mask-open');
|
||||
this.panel.set_css('sheet-panel-open');
|
||||
}
|
||||
close(){
|
||||
if (this._closed) return;
|
||||
this._closed = true;
|
||||
if (bricks.MobileSheet._cur === this) bricks.MobileSheet._cur = null;
|
||||
this.set_css('sheet-mask-open', true);
|
||||
this.panel.set_css('sheet-panel-open', true);
|
||||
var self = this;
|
||||
setTimeout(function(){ self._teardown(); }, 240);
|
||||
}
|
||||
// 基类 Widget 没有 destroy()(Popup 系才有)——自己实现摘除,
|
||||
// 不能只靠 try{destroy()}(抛错后 DOM 残留 → 蒙层永远挡屏幕)
|
||||
_teardown(){
|
||||
try {
|
||||
if (this.parent && this.parent.remove_widget){
|
||||
this.parent.remove_widget(this);
|
||||
} else if (this.dom_element && this.dom_element.parentNode){
|
||||
this.dom_element.parentNode.removeChild(this.dom_element);
|
||||
}
|
||||
} catch(e){
|
||||
try { this.dom_element.remove(); } catch(e2){}
|
||||
}
|
||||
}
|
||||
}
|
||||
bricks.Factory.register('MobileSheet', bricks.MobileSheet);
|
||||
|
||||
/* ══════════════════════════ ChipBar ══════════════════════════
|
||||
横向滚动胶囊切换条。数据来自 dataurl(dspy 返回 {items:[...], selected:...}
|
||||
或直接 [...])。选中派发 select 事件,params = 整条 item 数据,
|
||||
|
||||
@ -71,13 +71,35 @@ bricks.TabPanel = class extends bricks.Layout {
|
||||
}
|
||||
createMobileBar(){
|
||||
var mb = this.opts.mobile_bar;
|
||||
var items = ((mb && mb.items) || []).map(function(it){
|
||||
var all_descs = (mb && mb.items) || [];
|
||||
// 溢出规则(2026-09-08 用户要求):max_visible(默认 4)个平铺,
|
||||
// 超出部分收进第 N+1 格「更多」→ 点击弹 MobileSheet 竖向菜单,
|
||||
// 选中项照常 open_tab 进内容区。more.dataurl 可再挂动态项
|
||||
// (如已购产线,打开时实时拉取,购买后无需改 index.ui 即出现)。
|
||||
var max_visible = (mb && typeof mb.max_visible === 'number' && mb.max_visible > 0)
|
||||
? mb.max_visible : 4;
|
||||
var visible = all_descs.slice(0, max_visible);
|
||||
var overflow = all_descs.slice(max_visible);
|
||||
var more_cfg = (mb && mb.more) || {};
|
||||
var has_more = overflow.length > 0 || !!more_cfg.dataurl || !!more_cfg.items;
|
||||
var items = visible.map(function(it){
|
||||
return {name: it.name, label: it.label || it.name, icon: it.micon || '',
|
||||
badge_url: it.badge_url || ''};
|
||||
});
|
||||
this.mobile_bar = new bricks.TabBar({items: items, badge_interval: mb.badge_interval || 60});
|
||||
this._mobile_bar_descs = (mb && mb.items) || [];
|
||||
var bar_opts = {items: items, badge_interval: mb.badge_interval || 60};
|
||||
if (has_more){
|
||||
bar_opts.more = {label: more_cfg.label || '更多', icon: more_cfg.micon || '⋯'};
|
||||
}
|
||||
this.mobile_bar = new bricks.TabBar(bar_opts);
|
||||
// 底部栏可见 tab 的描述集合(open_tab 用);溢出项也注册——
|
||||
// 「更多」里选中后同样走 _mobile_bar_clicked 语义
|
||||
this._mobile_bar_descs = visible.concat(overflow);
|
||||
this._mobile_overflow_descs = overflow;
|
||||
this._mobile_more_cfg = has_more ? more_cfg : null;
|
||||
this.mobile_bar.bind('command', this._mobile_bar_clicked.bind(this));
|
||||
if (has_more){
|
||||
this.mobile_bar.bind('more', this._mobile_more_clicked.bind(this));
|
||||
}
|
||||
bricks.Body.add_widget(this.mobile_bar);
|
||||
var self = this;
|
||||
this._mobile_bar_apply = function(m){
|
||||
@ -103,6 +125,61 @@ bricks.TabPanel = class extends bricks.Layout {
|
||||
bricks.on_mobile_mode(this._mobile_bar_apply);
|
||||
this._mobile_bar_apply(bricks.is_mobile());
|
||||
}
|
||||
// 「更多」点击:静态溢出项 + more.dataurl 动态项(打开时实时拉,
|
||||
// 已购产线购买后立即出现)→ MobileSheet 竖向菜单;选中 → open_tab。
|
||||
async _mobile_more_clicked(){
|
||||
var cfg = this._mobile_more_cfg || {};
|
||||
var items = (this._mobile_overflow_descs || []).map(function(it){
|
||||
return {name: it.name, label: it.label || it.name, icon: it.micon || '',
|
||||
url: it.url, _tab: true};
|
||||
});
|
||||
// 声明式静态附加项(more.items)
|
||||
var extra = cfg.items || [];
|
||||
for (var i=0;i<extra.length;i++){
|
||||
items.push({name: extra[i].name, label: extra[i].label || extra[i].name,
|
||||
icon: extra[i].micon || extra[i].icon || '', url: extra[i].url, _tab: true});
|
||||
}
|
||||
// 动态项(如已购产线):{items:[{name,label,icon,desc,url}]}
|
||||
if (cfg.dataurl){
|
||||
try {
|
||||
var jc = new bricks.HttpJson();
|
||||
var d = await jc.get(cfg.dataurl, {});
|
||||
var dyn = (d && (d.items || d)) || [];
|
||||
if (Array.isArray(dyn)){
|
||||
for (var j=0;j<dyn.length;j++){
|
||||
var it = dyn[j] || {};
|
||||
items.push({name: it.name || ('dyn_' + j), label: it.label || it.name || '',
|
||||
icon: it.icon || '', desc: it.desc || '',
|
||||
url: it.url || '', popup: !!it.popup, _tab: !it.popup && !!it.url});
|
||||
}
|
||||
}
|
||||
} catch(e){ console.log('mobile more dataurl error', e); }
|
||||
}
|
||||
var self = this;
|
||||
var sheet = new bricks.MobileSheet({
|
||||
title: cfg.title || '',
|
||||
items: items,
|
||||
selected: this.cur_tab_name,
|
||||
empty_text: cfg.empty_text || '暂无更多功能'
|
||||
});
|
||||
// 注意:单个 select 监听,先注册后切换——动态项(产线页)不在
|
||||
// _mobile_bar_descs 时 _mobile_bar_clicked 会查不到 desc 直接 return
|
||||
// (两个监听器分先后会踩这个顺序坑,2026-09-08 写完即改)
|
||||
sheet.bind('select', function(ev){
|
||||
var it = ev.params;
|
||||
if (!it || !it._tab || !it.url) return; // popup 项已在 _row_clicked 内构建
|
||||
var found = false;
|
||||
for (var k=0;k<self._mobile_bar_descs.length;k++){
|
||||
if (self._mobile_bar_descs[k].name === it.name){ found = true; break; }
|
||||
}
|
||||
if (!found){
|
||||
self._mobile_bar_descs.push({name: it.name, label: it.label, url: it.url});
|
||||
}
|
||||
// 与平铺 tab 同语义:open_tab + 底部栏高亮态更新
|
||||
self._mobile_bar_clicked({name: it.name});
|
||||
});
|
||||
sheet.open();
|
||||
}
|
||||
_mobile_bar_clicked(item){
|
||||
// bind 事件经 dispatch 包装为 {params: 数据}(Toolbar/Menu 同约定);
|
||||
// 框架内部直调传裸对象 —— 两种形态都兼容(2026-09-08 实测:不解包则
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user