【问题标题】:JSNI script fails, but script succeeds when ran in Chrome Devtools consoleJSNI 脚本失败,但在 Chrome Devtools 控制台中运行时脚本成功
【发布时间】:2019-12-11 09:21:43
【问题描述】:

我正在使用测试数据通过 JSNI 使用名为 cytoscape.js 的外部 javascript 库。当我在我的 java 类中运行我想通过 JSNI 的脚本时,它无法生成图形。但是,当我通过 Chrome Devtools 控制台运行它时,它可以正常工作。

所有值似乎都正确传递给了 cytoscape.js 库。目前,JSNI 代码未能通过控制台代码能够通过的 Javascript 库执行的测试。

这是我正在使用的 JSNI 代码:

public static native void cytoscape() /*-{
        var cy = $wnd.cy = $wnd.cytoscape({container: $wnd.document.getElementById('cy'),
            elements: $wnd.glyElements, 
            style: [ { selector: 'node', style: { 'background-color': '#666', 'label': 'data(id)' } }, 
                { selector: 'edge', style: { 'width': 3, 'line-color': '#ccc', 'target-arrow-color': '#ccc', 'target-arrow-shape': 'triangle' } } ],
            layout: { name: 'grid', rows: 1 } });
    }-*/;

“$wnd”。用于获取正确的范围。

这是控制台代码:

var cy = window.cy = cytoscape({ 
            container: document.getElementById('cy'),
            elements: glyElements, 
            style: [ { selector: 'node', style: { 'background-color': '#666', 'label': 'data(id)' } }, { selector: 'edge', style: { 'width': 3, 'line-color': '#ccc', 'target-arrow-color': '#ccc', 'target-arrow-shape': 'triangle' } } ], 
            layout: { name: 'grid', rows: 1 } 
        });

我在这两种情况下使用的元素都存储在一个 .js 文件中,并且我确保它们在这两种情况下都可以访问。就像我提到的,Devtools 调试显示正确的值被传递到 cytoscape.js 库中。

JSNI 代码未能通过 cytoscape.js 库中的此返回语句:

var plainObject = function plainObject(obj) {
    return obj != null && _typeof(obj) === typeofobj && !array(obj) && obj.constructor === Object;
  };

如果我注释掉“&& obj.constructor === Object;”在 cytoscape.js 的第 145 行,代码可以使用我的 JSNI 脚本正确运行。这让我相信通过 JSNI 创建 cytoscape 对象的方式与通过控制台不同。尽管如此,开发工具将控制台和 JSNI 方法列为提供相同的对象。如何更新我的 JSNI 代码以使其符合此检查?

理想情况下,JSNI 应该在这种情况下可用。我不确定为什么通过 JSNI 传递值会导致这个 if 语句在通过控制台运行它时失败并传递 if 语句。

【问题讨论】:

    标签: javascript java gwt cytoscape.js jsni


    【解决方案1】:

    问题在于 Object 与 Object 并不完全相同,检查 instanceof 几乎肯定比 cytoscape 的作者认为的要多得多——JS 不是很伟大吗?

    cytoscape.js 项目的instanceof Object 测试不仅仅是测试“这个东西是普通对象而不是其他类型的实例”,而是实际测试“这个东西是 my 窗口实例,而不是来自任何其他 iframe/窗口”。

    GWT 的默认链接器在 iframe 中评估您的代码,以防止意外泄漏全局变量和混淆加载到同一页面的 JS,或让同一页面上的其他 JS 覆盖或以其他方式混淆 GWT 的代码。

    除了尝试将 cytoscape 的代码更正为不那么僵硬和不灵活的代码之外,还有一些方法可以解决此问题。

    • 从外部页面创建 Object 实例:为此,您必须直接创建对象,而不是使用 {...} 语法,该语法默认为您碰巧在其中执行的任何窗口。像这样:李>
           public static native void cytoscape() /*-{
               var obj = new $wnd.Object();
               obj.container = $wnd.document.getElementById('cy');//can also be simply $doc.getElementById('cy')
               obj.elements = $wnd.glyElements;
               // Note that you may have to repeat this for each of these nested objects, depending
               // on how picky the library is being on otherwise identically structured code...
               obj.style = [ { selector: 'node', style: { 'background-color': '#666', 'label': 'data(id)' } }, 
                       { selector: 'edge', style: { 'width': 3, 'line-color': '#ccc', 'target-arrow-color': '#ccc',
       'target-arrow-shape': 'triangle' } } ];
               obj.layout = { name: 'grid', rows: 1 };
               var cy = $wnd.cy = $wnd.cytoscape(obj);
           }-*/; 
    
    • 将 cytoscape.js 加载到执行 GWT 代码的同一 iframe 中。请注意,它实际上可能无法在其中运行,这会导致其他问题,但您可以尝试使用 ScriptInjector 将脚本内容插入 GWT 应用程序直接在您的 .html 页面中引用它。

    【讨论】:

      猜你喜欢
      • 2017-12-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-04
      • 2017-03-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多