Skip to content

CEF3 与 HTML 的 JS 交互示例

目录

  1. CEF3 项目端(注册 JS 交互事件)
  2. HTML 前端端(调用 CEF3 并接收返回数据)
  3. 完整交互流程
  4. 注意事项

1. CEF3 项目端(注册 JS 交互事件)

用于注册 JS 可调用的 C++ 函数,并绑定事件处理类。

代码示例

volcano
变量 JS交互事件 <类型 = 类_FBrowser_事件智能指针>
JS交互事件.创建 (类_FBrowser_JS交互事件测试)
FBrowser_JS交互_注册 ("cefQuery", "cefQueryCancel", JS交互事件)
FBrowser_JS交互_注册 ("cefQuerytest", "cefQueryCanceltest", JS交互事件)

关键说明

  • 类_FBrowser_JS交互事件测试:需实现 C++ 端逻辑,处理来自 JS 的请求。
  • 注册的接口
    • 第一组:cefQuery(发送请求) / cefQueryCancel(取消请求)
    • 第二组:cefQuerytest / cefQueryCanceltest

2. HTML 前端端(调用 CEF3 并接收返回数据)

通过 cefQuery 向 CEF3 发送请求,并在回调中处理返回数据。

HTML 完整代码

html
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Test Cef Query</title>
    <script type="text/javascript">
        var request_id;

        // 第一条通道交互
        function doQuery() {
            request_id = window.cefQuery({
                request: document.getElementById("query").value,
                persistent: true,
                onSuccess: function(response) {
                    alert(response); // C++ 返回的数据
                },
                onFailure: function(code, msg) {
                    alert("错误: " + code + " - " + msg);
                }
            });
        }

        // 第二条通道交互
        function doQuery1() {
            request_id = window.cefQuerytest({
                request: document.getElementById("query1").value,
                persistent: true,
                onSuccess: function(response) {
                    alert(response);
                },
                onFailure: function(code, msg) {
                    alert("错误: " + code + " - " + msg);
                }
            });
        }

        // 取消请求
        function doQueryCancel() {
            window.cefQueryCancel(request_id);
        }
    </script>
</head>
<body>
    <form>
        Query String1: 
        <input type="text" id="query" value="你好CefQuery" />
        <input type="button" value="SendQuery" onclick="doQuery()" />
        <input type="button" value="Cancel" onclick="doQueryCancel()" />

        Query String2: 
        <input type="text" id="query1" value="GiveMeMoney" />
        <input type="button" value="SendQuery1" onclick="doQuery1()" />
    </form>
</body>
</html>

关键功能

  • window.cefQuery:向 CEF3 发送请求,支持参数:
    • request:传递的数据(字符串或 JSON)。
    • persistent:是否允许后续取消请求。
    • onSuccess:成功回调,接收 C++ 返回的数据。
    • onFailure:失败回调,返回错误码和消息。
  • window.cefQueryCancel:取消未完成的请求(需与 persistent: true 配合使用)。

3. 完整交互流程

    HTML->>CEF3: window.cefQuery({ request: "data" })
    CEF3->>C++: OnQuery(request, callback)
    C++-->>CEF3: callback->Success("响应数据")
    CEF3-->>HTML: onSuccess("响应数据")

4. 注意事项

  1. 注册一致性
    • CEF3 的 FBrowser_JS交互_注册 名称需与 HTML 中的 window.cefQuery 完全匹配。
  2. C++ 实现
    • 确保 类_FBrowser_JS交互事件测试 正确处理 OnQueryOnQueryCanceled
  3. 错误排查
    • 如果 cefQuery 未定义,检查 CEF3 是否成功注册接口。
    • 如果无响应,检查 C++ 回调是否调用了 callback->Success
  4. 扩展建议
    • 使用 JSON 格式化请求数据(如 request: JSON.stringify({cmd: "test"}))。
    • 在 C++ 端解析 JSON 并返回结构化数据。

5、CEF3和VUE3交互示例

VUE代码

javascript
<template>
<button class="btn batch-open-btn" @click="batchOpen" :disabled="!hasSelectedBrowsers">
        <i class="icon">▶</i> 批量打开
      </button>
</template>

<script>
batchOpen() {
      if (!this.hasSelectedBrowsers) return;

      // 获取选中的浏览器
      const selectedBrowsers = this.browsers.filter(browser => browser.selected);
      const total = selectedBrowsers.length;
      let completed = 0;
      let failed = 0;
      const that = this;
      
      // 显示批量操作开始的通知
      ElMessage({
        message: `开始批量打开 ${total} 个浏览器...`,
        type: 'info'
      });

      // 为每个浏览器执行打开操作
      selectedBrowsers.forEach(browser => {
        try {
          const index = this.browsers.indexOf(browser);
          const rowNumber = index + 1; // 获取行号(从1开始)
          
          window.cefQuery({
            request: JSON.stringify({ 
              cmd: 'openBrowser',
              browserId: browser.id || '未知ID',
              browserUuid: browser.uuid,
              proxyIp: browser.proxyIp || '',
              rowIndex: index,
              rowNumber: rowNumber // 传入行号
            }),
            persistent: true,
            onSuccess: function(response) {
              console.log('浏览器打开成功:', response);
              
              // 解析响应,更新浏览器ID和状态
              try {
                const result = JSON.parse(response);
                if (result && result.browserId) {
                  browser.id = result.browserId;
                }
                that.updateStatus(browser, '已打开');
              } catch (e) {
                console.error('解析响应失败:', e);
                that.updateStatus(browser, '已打开');
              }
              
              completed++;
              
              // 全部完成后显示结果
              if (completed + failed === total) {
                if (failed > 0) {
                  ElMessage({
                    message: `批量打开完成: ${completed} 个成功, ${failed} 个失败`,
                    type: 'warning'
                  });
                } else {
                  ElMessage({
                    message: `成功打开所有 ${completed} 个浏览器`,
                    type: 'success'
                  });
                }
              }
            },
            onFailure: function(code, msg) {
              console.error('浏览器打开失败:', code, msg);
              failed++;
              
              // 全部完成后显示结果
              if (completed + failed === total) {
                ElMessage({
                  message: `批量打开完成: ${completed} 个成功, ${failed} 个失败`,
                  type: 'warning'
                });
              }
            }
          });
        } catch (e) {
          console.error('调用cefQuery出错:', e);
          failed++;
          
          // 开发环境下不再自动赋值ID和修改状态
          if (process.env.NODE_ENV === 'development') {
            console.log('开发环境:CEF3环境会在此处赋值ID并更新状态为已打开');
            // browser.id = 'test-' + Date.now() + '-' + Math.floor(Math.random() * 1000);
            // that.updateStatus(browser, '已打开');
            completed++;
            failed--;
          }
          
          // 全部完成后显示结果
          if (completed + failed === total) {
            ElMessage({
              message: `批量打开完成: ${completed} 个成功, ${failed} 个失败`,
              type: 'warning'
            });
          }
        }
      });
    }
</script>

6、VUE3的JS方法暴露全局给CEF3调用示例

<script>
    export default {
		mounted() {
        console.log("组件已挂载");

        // 检查是否是首次加载
        this.isFirstLoad = localStorage.getItem('hasBrowsersLoaded') !== 'true';
        console.log("是否首次加载:", this.isFirstLoad);

        this.loadBrowsersFromStorage();

        // 设置已加载标志
        if (this.isFirstLoad) {
          localStorage.setItem('hasBrowsersLoaded', 'true');
        }

        // 全局更新浏览器信息的统一方法
        window.updateBrowserInfo = (data) => {
          if (!data || data.rowIndex === undefined) {
            console.error('更新浏览器信息失败: 无效的数据格式或缺少rowIndex');
            return;
          }

          const index = parseInt(data.rowIndex, 10);
          if (index < 0 || index >= this.browsers.length) {
            console.error(`更新浏览器信息失败: 索引 ${index} 超出范围`);
            return;
          }

          const browser = this.browsers[index];
          let updated = false;

          // 更新浏览器ID
          if (data.cmd === 'updateBrowserId' && data.browserId !== undefined) {
            browser.id = data.browserId;
            console.log(`已更新索引 ${index} 的浏览器ID为: ${data.browserId}`);
            updated = true;
          }

          // 更新浏览器状态
          else if (data.cmd === 'updateBrowserStatus' && data.status !== undefined) {
            browser.status = data.status;
            console.log(`已更新索引 ${index} 的浏览器状态为: ${data.status}`);
            updated = true;
          }

          // 更新备注
          else if (data.cmd === 'updateBrowserRemark' && data.remark !== undefined) {
            browser.remark = data.remark;
            console.log(`已更新索引 ${index} 的浏览器备注为: ${data.remark}`);
            updated = true;
          }

          // 一次性更新多个属性
          else if (data.cmd === 'updateBrowserAll') {
            if (data.browserId !== undefined) {
              browser.id = data.browserId;
            }
            if (data.status !== undefined) {
              browser.status = data.status;
            }
            if (data.remark !== undefined) {
              browser.remark = data.remark;
            }
            console.log(`已更新索引 ${index} 的浏览器多个属性`);
            updated = true;
          }

          if (!updated) {
            console.error(`未知的命令或缺少必要参数: ${data.cmd}`);
          }
        };

        // 为了向后兼容,保留原来的方法,但内部调用新的统一方法
        window.updateBrowserFromCef = (data) => {
          if (data && data.cmd === 'updateBrowserId' && data.rowIndex !== undefined) {
            window.updateBrowserInfo(data);
          }
        };

        // 保持向后兼容的状态更新方法
        window.updateBrowserStatus = (data) => {
          if (data && data.rowIndex !== undefined && data.status !== undefined) {
            window.updateBrowserInfo({
              cmd: 'updateBrowserStatus',
              rowIndex: data.rowIndex,
              status: data.status
            });
          }
        };
      }
    }

</script>

如果文档对您有帮助,欢迎 请喝咖啡 ☕ | 软件发布 | 源码购买