GWT UiBinder - 在呈现模板后执行 JS?
GWT UiBinder - Execute JS after template is rendered?
我的 UiBinder 模板中有一个 div,ID 为 "test",我想在其上执行一些 jQuery 操作。如果我在 UiBinder java class 末尾执行本地方法,java 脚本调用失败,因为 div 似乎还不存在:
public MyWidget() {
initWidget(uiBinder.createAndBindUi(this));
AppUtils.initializeSomething();
}
解决方法是使用计时器并稍微延迟我的 JS 代码。这可行,但在我看来非常难看。如果 UiBinder 模板已完全加载,是否有任何干净的解决方案来执行我的 java 脚本?
public MyWidget() {
initWidget(uiBinder.createAndBindUi(this));
new Timer(){
@Override
public void run() {
AppUtils.initializeSomething();
};
}.schedule(1000);
}
原生方法:
public static native void initializeSomething()/*-{
$wnd.$('#test').doSomeJsStuff();
}-*/;
public MyWidget() {
initWidget(uiBinder.createAndBindUi(this));
AppUtils.initializeSomething();
}
由于这只是构造函数,此时 DOM 元素全部存在,但尚未附加,因此任何试图查找附加的 dom 元素的代码都将失败(因为例如,jQuery 将尝试执行 document.getElementById
来计算 $('#test')
,这将失败,因为小部件尚未附加到文档)。
相反,您有两个基本选项:
- 运行 立即初始化,但实际上传入了 dom 元素而不是试图找到它(并且失败),或者
- 等待 dom 元素实际附加后再尝试初始化。
运行初始化只是已经知道要修改哪个元素的问题。由于您使用的是 uiBinder,因此您可以在 Java class 中创建一个 Element
字段,并要求将其分配给某个设置了 ui:field
属性的元素同名。这就像你当前如何将元素的 ID 设置为 "test",然后期望通过 `$('#test') 找到它。像这样:
在您的 .ui.xml 文件中:
<g:HTMLPanel>
<div ui:field="testElement">...</div>
...
</g:HTMLPanel>
在你的.java class:
@UiField Element testElement;
然后在你的JSNI方法中你可以传入元素或者在调用的时候引用它。这是您的 initializeSomething
和构造函数的样子:
public MyWidget() {
initWidget(uiBinder.createAndBindUi(this));
AppUtils.initializeSomething(this.testElement);
}
public static native void initializeSomething(Element elt)/*-{
//jQuery lets you wrap a dom element instead of finding it,
//and we already know where it is
$wnd.$(elt).doSomeJsStuff();
}-*/;
接下来,等到附加到DOM到运行doSomeJsStuff()
——这两个简单的方法。在原始 JS 中,您会以第一种方式执行此操作,但我建议这对 JS 来说是非常错误的。所以这是第一个错误的方法:
//make the elements
MyWidget widget = new MyWidget();
//attach them to the dom (note that if you attach to a different
// parent, that parent too must be attached
// and so on).
RootPanel.get().add(widget);
//now that we are attached, run the setup code!
widget.doSomeJsStuff();
这显然很愚蠢 - 我们正在编写 class,而 class 应该足够聪明,可以照顾好自己!
让我们再试一次,这次将 class 指示为 运行 doSomeJsStuff()
已附加。有两种方法可以完成这项工作,onAttach
和 onLoad
- 没有关于 doSomeJsStuff
做什么的具体细节,我不知道你需要什么,但是 onLoad
是更容易使用的。
请务必注意,每次附加小部件时都会调用这些方法,而不仅仅是第一次。如果这对您很重要,您可能需要检查是否尚未附加小部件。如果没有,我们只需要这个:
@Override
protected void onLoad() {
doSomeJsStuff();
}
我的 UiBinder 模板中有一个 div,ID 为 "test",我想在其上执行一些 jQuery 操作。如果我在 UiBinder java class 末尾执行本地方法,java 脚本调用失败,因为 div 似乎还不存在:
public MyWidget() {
initWidget(uiBinder.createAndBindUi(this));
AppUtils.initializeSomething();
}
解决方法是使用计时器并稍微延迟我的 JS 代码。这可行,但在我看来非常难看。如果 UiBinder 模板已完全加载,是否有任何干净的解决方案来执行我的 java 脚本?
public MyWidget() {
initWidget(uiBinder.createAndBindUi(this));
new Timer(){
@Override
public void run() {
AppUtils.initializeSomething();
};
}.schedule(1000);
}
原生方法:
public static native void initializeSomething()/*-{
$wnd.$('#test').doSomeJsStuff();
}-*/;
public MyWidget() { initWidget(uiBinder.createAndBindUi(this)); AppUtils.initializeSomething(); }
由于这只是构造函数,此时 DOM 元素全部存在,但尚未附加,因此任何试图查找附加的 dom 元素的代码都将失败(因为例如,jQuery 将尝试执行 document.getElementById
来计算 $('#test')
,这将失败,因为小部件尚未附加到文档)。
相反,您有两个基本选项:
- 运行 立即初始化,但实际上传入了 dom 元素而不是试图找到它(并且失败),或者
- 等待 dom 元素实际附加后再尝试初始化。
运行初始化只是已经知道要修改哪个元素的问题。由于您使用的是 uiBinder,因此您可以在 Java class 中创建一个 Element
字段,并要求将其分配给某个设置了 ui:field
属性的元素同名。这就像你当前如何将元素的 ID 设置为 "test",然后期望通过 `$('#test') 找到它。像这样:
在您的 .ui.xml 文件中:
<g:HTMLPanel>
<div ui:field="testElement">...</div>
...
</g:HTMLPanel>
在你的.java class:
@UiField Element testElement;
然后在你的JSNI方法中你可以传入元素或者在调用的时候引用它。这是您的 initializeSomething
和构造函数的样子:
public MyWidget() {
initWidget(uiBinder.createAndBindUi(this));
AppUtils.initializeSomething(this.testElement);
}
public static native void initializeSomething(Element elt)/*-{
//jQuery lets you wrap a dom element instead of finding it,
//and we already know where it is
$wnd.$(elt).doSomeJsStuff();
}-*/;
接下来,等到附加到DOM到运行doSomeJsStuff()
——这两个简单的方法。在原始 JS 中,您会以第一种方式执行此操作,但我建议这对 JS 来说是非常错误的。所以这是第一个错误的方法:
//make the elements
MyWidget widget = new MyWidget();
//attach them to the dom (note that if you attach to a different
// parent, that parent too must be attached
// and so on).
RootPanel.get().add(widget);
//now that we are attached, run the setup code!
widget.doSomeJsStuff();
这显然很愚蠢 - 我们正在编写 class,而 class 应该足够聪明,可以照顾好自己!
让我们再试一次,这次将 class 指示为 运行 doSomeJsStuff()
已附加。有两种方法可以完成这项工作,onAttach
和 onLoad
- 没有关于 doSomeJsStuff
做什么的具体细节,我不知道你需要什么,但是 onLoad
是更容易使用的。
请务必注意,每次附加小部件时都会调用这些方法,而不仅仅是第一次。如果这对您很重要,您可能需要检查是否尚未附加小部件。如果没有,我们只需要这个:
@Override
protected void onLoad() {
doSomeJsStuff();
}