在GWT中通过CSS选择器查找元素

15

我试图在GWT中使用CSS选择器(例如“#someId .className a”)来抓取任意元素。

我正在构建一个可以放置在第三方网站上的JS小部件,并希望能够与页面上的元素进行交互。通过查阅JavaDocs,我没有看到可以按选择器查找元素的任何内容。我确实找到了GQuery,但似乎该项目可能已经停止开发,而且我不确定它是否适用于GWT 2。

我考虑的一个选项是将现有库(jQuery、Mootools、Prototype等)包装成GWT类,并通过JSNI公开所需的行为。但这似乎可能非常笨重。

有人有在GWT中使用通用CSS选择器的经验吗?


1
GWTQuery/GQuery 似乎已经复苏,其不活跃很可能对应于 GWT 2.1 的发布。 - Lam Chau
3
没有原生的querySelector[All]在GWT中真的很令人沮丧。我想知道这个项目是否注定要由讨厌客户端开发的人来运行。 - rxgx
5个回答

8
有一个名为DOM的类,它提供了许多包装器方法来访问DOM树。据我所知,没有像jQuery样使用CSS选择器的函数 - GWT只鼓励/强制通过小部件(等等)直接访问DOM元素 - 尽管我理解在您的情况下可能需要这种“低级”方法。我唯一看到通过纯Java GWT方法实现的方法是通过大量和大量的(可能可怕的)DOM类链接/调用。如果您只需要访问某个id,那么更容易的方法是使用RootPanel.get(id)(和DOM.getElementById(id),它们在返回的对象类型上有所不同)。
但是,正如您已经建议的那样,JSNI可能提供了更好的解决方案 - 例如,尝试从JSNI返回$wnd.$("#someId .className a")作为Element - 实际上,您可以从JSNI返回任何内容作为任何内容,只要尝试将int用作DOM元素或其他内容,GWT就会崩溃。
PS:虽然GQuery项目似乎已经死亡/不活跃,但检查一下他们如何包装jQuery调用(例如$)可能是值得的,以便它们可以在GWT中使用。

尝试这个,我得到了:“未捕获的类型错误:对象[object DOMWindow]没有方法'$'”,我需要在页面上添加jQuery.js或其他什么吗? - Andrew Mackenzie
是的,您需要在主机页面中包含jQuery .js文件。此外,请查看这个问题,但$应该从JSNI正常工作。 - Igor Klimer
我猜测 document.querySelector(...) 不是一个选项? - WORMSS

6

使用GwtQuery,已更新至GWT 2.4:http://code.google.com/p/gwtquery/

选择器示例:

//select an element having id equals to 'container'
GQuery myElement = $("#container");
//select all elements having 'article' as css class
GQuery allArticles = $(".article");
/select all cells of tables
GQuery allCells = $("table > tr > td");
//find the ul elements being inside a element with class 'article' itself inside a element with id 'container'
GQuery articleUls = $("#container .article ul");

http://code.google.com/p/gwtquery/wiki/GettingStarted


3

灵感来自Asfand Yar Qazi的答案

使用JSNI,您只需要定义此方法,并在现代浏览器中运行 Web 应用程序时享受它。

public final native NodeList<Element> querySelectorAll(String selectors) /*-{
 return $doc.querySelectorAll(selectors);
 }-*/;

这真的有效吗?你测试过吗? 如果从本地js返回进行了一些隐式转换到NodeList<Element>,我会感到非常惊讶。 - BuvinJ
1
我没有看到你的文档来源支持这种语法。请提供一份报价。在该链接中,我能找到的最接近的内容是在“将JavaScript值传递到Java代码”部分内。对于返回类型:“任何其他Java对象(包括数组)”,它指出必须传递的是“正确类型的Java对象,必须源自Java代码;无法从JavaScript中“空气中”构造Java对象”。我相信这与你可以隐式转换NodeList<Element>的返回类型的想法直接相反。 - BuvinJ
完美地为我工作! - Daniel De León
1
哇!嗯,我很惊讶,但也很兴奋!那可能非常有用。不错的解决方案!我得自己试试... - BuvinJ

3

querySelectorquerySelectorAll在GWT中不可用。有一个名为'GwtQuery'或'gQuery'的jQuery选择器重写可用。 - rxgx
1
GWT可以调用任何你想要的Javascript方法,你只需要编写一个小包装器方法作为参数的传递即可。请参阅GWT文档中有关本地方法访问的文档。这种方法被用于在我的工作中从GWT中访问querySelector/querySelectorAll。 - Asfand Qazi
我为doc/element的querySelector和querySelectorAll编写了一行GWT JSNI包装器,并且现在使用它们取得了极好的结果。简单、可靠且快速。 - Andrew Mackenzie
当然,你可以通过JNSI向GWT添加属性访问器,但这违反了GWT的思想。你希望能够让GWT构建一个排列,以便与IE6、7、8、Safari、Gecko 1_8和旧版本兼容。这是一个不好的答案。问题要求使用GWT函数来完成这个任务。 - Joseph Lust
3
根据需求而定。如果通过 PhoneGap 开发应用程序,仅针对 iOS 和 Android 浏览器,则只需支持 WebKit,因此请使用 querySelectorAll()。如果针对类似于我以前的工作场所的内部公司应用程序的单个浏览器,请强制所有销售人员在 Chrome 上运行您的应用程序,并使用 querySelectorAll,他们不会注意到 Web 浏览器窗口和桌面应用程序窗口之间的区别。请保持友好的态度。 - Asfand Qazi
优秀的解决方案。 - Andrei Volgin

1
这里有一个使用GWT元素和节点类查找具有给定类名的单个嵌套元素的示例。这不像文字CSS选择器那样开放和强大,但可以根据您特定的用例进行修改:
static public Element findFirstChildElementByClassName( Widget w, String className ){
    return findFirstChildElementByClassName( w.getElement(), className );
}
static private Element findFirstChildElementByClassName( Element e, String className ){     
    for( int i=0; i != e.getChildCount(); ++i ){
        Node childNode = e.getChild(i);
        if( childNode.getNodeType() == Node.ELEMENT_NODE ){
            Element childElement = (Element)childNode;
            if( childElement.getClassName().equalsIgnoreCase( className ) )
                return childElement;
            else if( childElement.hasChildNodes() ){
                Element grandChildElement = 
                    findFirstChildElementByClassName( 
                            childElement, className );
                if( grandChildElement != null ) return grandChildElement;
            }
        }
    }
    return null;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接