✅ 核心机制:主 Grid 监听
selectionchange(选中行变更)→ 取出主表主键 →子Grid.load({params:{主键}})刷新明细,Geejing WebBuilder 原生标准写法,XWL 配置 + 服务端脚本一体。业务示例:订单(主)→订单明细(副)、合同→合同条款、项目→任务台账
一、前置准备(数据库 + 2 个后端 Action)
- 数据表设计
- 主表:
biz_order,主键order_id - 副表:
biz_order_item,外键order_id(关联主表主键)
- 后端准备 2 个查询 action:
getOrderList:加载全部订单主表getOrderItemList:接收参数order_id,查询该订单明细
二、完整可直接导入 XWL 源码(上下双 Grid,最常用)
swift
module
{
"cid":"mainSubOrderModule",
"cls":"Wb.Module",
"properties":{"cid":"mainSubOrderModule"},
"events":{
"initialize":"Wb.apply(app,{\n onLoad(){\n // 页面初始化加载主表\n app.gridMain.load();\n }\n});"
},
"items":[
// ========== 主表Grid ==========
{
"cid":"gridMain",
"cls":"Wb.Grid",
"title":"订单主表",
"url":xpath + "/actions&xaction=getOrderList",
"columns":[
{"text":"订单ID","fieldName":"order_id","width":120},
{"text":"客户名称","fieldName":"cust_name"},
{"text":"下单时间","fieldName":"create_time"}
],
"events":{
// ✅联动核心事件:selectionchange 选中行切换
"selectionchange":`
const row = this.selection;
if(!row){
// 取消选中:清空副表,防止旧数据残留
app.gridSub.clear();
return;
}
// 携带主表主键,刷新副表明细
app.gridSub.load({
params:{
order_id: row.order_id
}
});
`
}
},
// ========== 副表(明细Grid) ==========
{
"cid":"gridSub",
"cls":"Wb.Grid",
"title":"订单明细",
"url":xpath + "/actions&xaction=getOrderItemList",
"columns":[
{"text":"商品名称","fieldName":"goods_name"},
{"text":"单价","fieldName":"price"},
{"text":"数量","fieldName":"qty"},
{"text":"金额","fieldName":"amt"}
]
}
]
}
三、服务端 ServerScript(WebBuilder 内置脚本,直接复制)
ini
let xaction = Params.xaction;
if(xaction === "getOrderList"){
// 主表列表
return Wb.db.query("select order_id,cust_name,create_time from biz_order");
}
if(xaction === "getOrderItemList"){
let orderId = Params.order_id || "";
// 按主表主键过滤明细,参数防注入使用?占位符
return Wb.db.query("select goods_name,price,qty,amt from biz_order_item where order_id=?",[orderId]);
}
四、两种常用联动模式
模式 1:上下双 Grid(上面主、下面明细,上面选中自动刷下面)
👉 就是上面这份标准代码,90% 业务首选
- 单选:
this.selection取单行 - 多选场景:
this.selections数组,后端用IN(...)查询
模式 2:主表行展开嵌套子表(expand 展开行,不单独占页面)
适合不想上下布局,点展开箭头才加载明细:
php
// 在gridMain配置 expand:true,expandRenderer渲染内嵌子Grid
"expandRenderer":`
return Wb.render({
cid:"innerSubGrid",
cls:"Wb.Grid",
url:xpath+"/actions&xaction=getOrderItemList",
params:{order_id:data.order_id}
})
`
五、高频踩坑点 & 最佳实践(Geejing WebBuilder 专属)
- **空选中必须 clear ()**取消行选中时执行
app.gridSub.clear(),否则副表保留上次明细,造成数据混淆 - 主键类型严格一致 数字型主键不要传字符串,否则 SQL 匹配不到数据(
1000vs"1000") - 新增 / 编辑明细联动 新增明细弹窗时,直接读取
app.gridMain.selection.order_id自动回填外键,保存后执行app.gridSub.load()刷新明细 - 多选主子表
ini
// selectionchange内多选写法
const rows = this.selections;
if(!rows.length){app.gridSub.clear();return;}
const ids = rows.map(r=>r.order_id).join(",");
app.gridSub.load({params:{idList:ids}});
后端 SQL:where order_id IN (?)5. 加载体验优化 大数据明细可增加 loading:app.gridSub.loading=true,加载完自动关闭