FBro 的 JS 交互 - 小白入门指南
本帖最后由 mosheng 于 2025-12-12 13:09 编辑# FBro 的 JS 交互 - 小白入门指南
## 💡 为什么要用 JS 交互?
### 传统方式的问题
如果不用 JS 交互,前端(网页)和后端(C#)就像两个**完全隔离的世界**:
| 问题 | 说明 |
|------|------|
| 😢 网页是"死"的 | 网页只能展示静态内容,无法操作电脑 |
| 😢 C# 看不到网页 | C# 不知道用户在网页上点了什么 |
| 😢 无法联动 | 用户点按钮,C# 不知道;C# 有结果,网页不知道 |
### JS 交互的好处
| 好处 | 说明 |
|------|------|
| ✅ **双向通讯** | 网页和 C# 可以互相"说话" |
| ✅ **实时响应** | 用户点击按钮,C# 立刻知道并执行 |
| ✅ **动态更新** | C# 有新数据,网页立刻更新显示 |
| ✅ **功能强大** | 网页负责好看的界面,C# 负责强大的功能 |
| ✅ **各司其职** | 前端专注 UI,后端专注逻辑,分工明确 ,无需使用第三方UI模块支持库比如exui,前端好看的网页UI太多了,比如vue和react|
!(https://img.msblog.cc/img/ScreenShot_2025-12-12_130847_844.png)
### 项目的实际例子
**没有 JS 交互**:
```
用户点击"添加账号" → 什么都不会发生(网页不会动)
```
**有了 JS 交互**:
```
用户点击"添加账号"
→ 网页告诉 C#:"用户要添加账号"
→ C# 打开新浏览器窗口
→ C# 告诉网页:"浏览器已打开"
→ 网页更新按钮变成"关闭浏览器"
```
**简单说**:JS 交互让你的桌面应用"活"起来了!
---
## 🤔 什么是 FBro 的 JS 交互?
简单来说,就是让网页(JavaScript)和桌面程序(C#)能够"对话"。
想象一下:
- **网页(前端)** = 服务员
- **C# 程序(后端)** = 厨师
服务员需要把客人的点单(请求)告诉厨师,厨师做好菜后再把菜(响应)传给服务员。
FBro 提供了这个"传话"的机制,叫做 **cefQuery**。
---
## 📱 两种通讯方向
### 方向1:网页 → C#(前端调用后端)
**场景**:用户在网页上点击按钮,想让 C# 程序做点事情
```
网页点击按钮
→ 调用 cefQuery 发送消息
→ C# 的 OnQuery 方法收到消息
→ C# 处理完毕
→ 返回结果给网页
```
**网页端代码示例**:
```javascript
// 发送消息给 C#
window.cefQuery({
request: JSON.stringify({
action: 'createBrowser',// 告诉 C# 要做什么
accountId: '123',
username: '张三'
}),
onSuccess: function(response) {
// C# 处理成功后的回调
console.log('成功了!', response);
},
onFailure: function(error_code, error_message) {
// C# 处理失败后的回调
console.log('失败了!', error_message);
}
});
```
**C# 端代码示例**:
```csharp
// 在 OnQuery 方法中接收消息
public override bool OnQuery(IFBroSharpBrowser browser, IFBroSharpFrame frame,
long queryId, string request, bool persistent, IFBroSharpQueryCallback callback)
{
// request 就是网页发过来的 JSON 字符串
var data = JObject.Parse(request);
string action = data["action"]?.ToString();
if (action == "createBrowser")
{
// 做点事情...
// 处理完毕,返回成功
callback.Success("创建成功!");
}
return true;
}
```
**易语言 端代码示例**:
```
.版本 2
.支持库 spec
.子程序 JS交互回调, 逻辑型, , !
.参数 浏览器指针, 整数型, , 使用该回调的浏览器指针,创建”类_FBrowser_浏览器“浏览器变量后,通过调用"浏览器.绑定 (浏览器指针)"后使用类相关功能
.参数 框架指针, 整数型, , 使用该回调的浏览器框架指针,创建”类_FBrowser_框架“框架变量后,通过调用"框架.绑定 (框架指针)"后使用类相关功能
.参数 request, 文本型, , 对应JS函数中的“request”变量
.参数 返回文本类值指针, 整数型, , 返回JS值的指针,通过“FBrowser_置文本类值”设置返回的文本值
.参数 errorcode, 整数型, 参考, 对应JS函数中的“code”变量,返回JS的错误代码
.参数 query_id, 整数型, , 对应JS函数返回值request_id
.参数 type, 整数型, , 0为cefQuery 1为cefQueryCancel,为1时request不会有值
.局部变量 json, zyJsonValue
.局部变量 jx, 逻辑型
.局部变量 action, 文本型
.局部变量 activationCode, 文本型
.局部变量 data, 文本型
.局部变量 uri, 文本型
调试输出 (取程序名称 (1), “收到JS请求”, request)
errorcode = 111
jx = json.解析 (request, , , , )
.如果真 (jx = 假)
FBrowser_置文本类值 (返回文本类值指针, “未知的操作类型”)
返回 (真)
.如果真结束
action = json.取文本 (“action”)
.判断开始 (action = “activate”)' 激活产品
' 简单的激活码验证逻辑(你可以根据需要修改)
activationCode = json.取文本 (“data.activationCode”)
.如果 (activationCode = “00000000000000000000”)
FBrowser_置文本类值 (返回文本类值指针, #激活成功)' 因为HTML代码需要JSON格式消息,所以这里返回的信息是JSON格式
返回 (真)
.否则
FBrowser_置文本类值 (返回文本类值指针, #激活码错误)' 因为HTML代码需要JSON格式消息,所以这里返回的信息是JSON格式
返回 (真)
.如果结束
.判断 (action = “enterApp”)' 进入功能界面
data = 编码_Utf8到Ansi (读入文件 (取运行目录 () + “\web\Webui_功能界面.html”))
uri = FBrowser_Parser_取数据URI (“text/html”, data)
全_浏览器 .取主框架 ().载入地址 (uri)
FBrowser_置文本类值 (返回文本类值指针, #进入功能界面)' 因为HTML代码需要JSON格式消息,所以这里返回的信息是JSON格式
返回 (真)
.判断 (action = “contactService”)' 联系客服
FBrowser_置文本类值 (返回文本类值指针, #联系客服)' 因为HTML代码需要JSON格式消息,所以这里返回的信息是JSON格式
返回 (真)
.默认
.判断结束
FBrowser_置文本类值 (返回文本类值指针, request)
返回 (真)
```
---
### 方向2:C# → 网页(后端调用前端)
**场景**:C# 程序检测到某个事件,想通知网页更新界面
```
C# 检测到事件
→ 获取浏览器的 Frame
→ 执行 JavaScript 代码
→ 网页收到通知并更新界面
```
**C# 端代码示例**:
```csharp
// 调用网页上的 JavaScript 函数
public void NotifyWebpage(string message)
{
// 获取主框架
var frame = browser.GetMainFrame();
// 执行 JavaScript(调用网页上预先定义好的函数)
frame.ExecuteJavaScript(
$"window.onLoginSuccess({{ message: '{message}' }});",
"",
0
);
}
```
**易语言 端代码示例**:
```csharp
.版本 2
.子程序 调用网页上的JavaScript函数
.参数 browser, 类_FBrowser_浏览器, , 这个必须是加载了js交互页面的浏览器
.局部变量 框架, 类_FBrowser_框架
框架 = browser.取主框架 ()
框架.执行JS代码 (“window.onLoginSuccess({ message: '你主动推动到网页的消息' });”, , )
```
**网页端需要预先定义好函数**:
```javascript
// 在网页上预先定义好接收函数
window.onLoginSuccess = function(data) {
console.log('登录成功!', data.message);
// 更新界面...
};
```
---
## 🎯 实际应用场景
### 场景1:点击按钮打开浏览器
```
用户点击"添加账号"按钮
↓
网页发送 cefQuery 请求: { action: 'createBrowser' }
↓
C# 收到请求,创建新浏览器窗口
↓
C# 返回: callback.Success("创建成功")
↓
网页收到成功响应,更新界面显示"浏览器已打开"
```
### 场景2:用户扫码登录后通知网页
```
用户在新浏览器中扫码登录
↓
C# 拦截到登录成功的请求
↓
C# 执行: frame.ExecuteJavaScript("window.onLoginSuccess({...})")
↓
网页收到通知,添加新账号到列表
```
---
## ⚠️ 最重要的一点:不能阻塞!
**错误做法** ❌:
```csharp
public override bool OnQuery(..., IFBroSharpQueryCallback callback)
{
// 做一些耗时的操作...
Thread.Sleep(5000);// ❌ 等待5秒 = 阻塞 = 卡死!
callback.Success("完成");
return true;
}
```
**正确做法** ✅:
```csharp
public override bool OnQuery(..., IFBroSharpQueryCallback callback)
{
// 启动异步操作,立即返回
Task.Run(() => {
// 在后台做耗时操作...
// 完成后再调用 callback
callback.Success("完成");
});
return true;// 立即返回,不等待
}
```
**记住**:`OnQuery` 方法必须"秒回",不能让网页等太久!
---
## 📝 简化版理解
把整个通讯想象成**微信聊天**:
| 概念 | 类比 |
|------|------|
| cefQuery | 发送消息 |
| OnQuery | 收到消息 |
| callback.Success | 回复"收到,已处理" |
| callback.Failure | 回复"出错了" |
| ExecuteJavaScript | 给对方发语音消息(主动通知) |
| window.xxx 函数 | 对方预先设置的"自动回复" |
## 🎓 总结
1. **网页想叫 C#(易语言) 做事** → 用 `cefQuery(易语言是JS交互回调)` 发消息
2. **C#(易语言) 做完后回复** → 用 `callback.Success()` 或 `callback.Failure()`
3. **C#(易语言) 想通知网页** → 用 `ExecuteJavaScript`(易语言是框架执行JS代码) 调用预定义的函数
4. **最重要** → 不能阻塞 `OnQuery`,必须秒回!
🟨 源码参考
[*]下载FBro官方demo里面有,易语言是JS交互实例.e ,C#是JS交互测试
🟨 成品参考
赞!赞!赞!赞!赞!赞!赞!赞!赞!
页:
[1]