如何在C、GTK4、GObject中实现webkit_web_view_evaluate_javascript()
我在开发一个带有内嵌浏览器的应用程序。我已经用Lisp和 C(gtk4)写了一段时间,但对JavaScript还是完全新手。我需要在浏览器里执行JavaScript来查找元素。目前我在对这个功能做总体测试,等它能工作后再实现具体的用例。
按照文档的指引,我遇到了一个问题:用于查找元素的函数返回了null。
我的做法是使用文档中 webkit_web_view_evaluate_javascript() 的示例实现代码:https://webkitgtk.org/reference/webkitgtk/unstable/method.WebView.evaluate_javascript.html
我唯一的改动,是让调用 webkit_web_view_evaluate_javascript() 的函数改为选择一个元素。它所做的只是用一个元素的ID来执行JavaScript window.document.getElementById('');。最终我还会对这个元素做一些操作,这只是一个测试。
static void
web_view_get_element (WebKitWebView *web_view,
const gchar *uuid)
{
gchar *script = g_strdup_printf ("window.document.getElementById('%s');", uuid);
gpointer result;
webkit_web_view_evaluate_javascript (web_view, script, -1, NULL, NULL, NULL, web_view_javascript_finished, NULL);
g_free (script);
}
我的 web_view_javascript_finished() 函数和文档中的完全相同。
我已经在嵌入式浏览器的控制台里手动测试了这段JavaScript,结果工作正常:
然而,当我的程序运行 web_view_get_element() 时,web_view_javascript_finished() 显示该值为null。
有什么线索吗?谢谢!
解决方案
核心问题在于 getElementById() 返回的是一个DOM元素对象,而WebKit的 JS桥只能把原始类型(字符串、数字、布尔值)传回C。DOM元素无法跨越这座桥,因此会返回null。
解决办法是在JS表达式本身就提取你需要的部分:
c
// Does the element exist?
gchar *script = g_strdup_printf(
"document.getElementById('%s') !== null;", uuid);
// Or grab a property from it
gchar *script = g_strdup_printf(
"var el = document.getElementById('%s'); el ? el.tagName : null;", uuid);
如果你的目标是对该元素进行某些操作,直接把所有操作都放在脚本字符串里并返回一个状态:
c
gchar *script = g_strdup_printf(
"var el = document.getElementById('%s');"
"if (el) { el.style.border = '2px solid red'; 'done'; } else { 'not found'; }",
uuid);
另外,确保不要在页面加载完成之前就调用。请监听 load-changed,等待 WEBKIT_LOAD_FINISHED 的触发,否则脚本运行时该元素在DOM中还不存在。