如何在Apache Wicket中将焦点设置到组件上?

7

如何在Apache Wicket中将焦点设置在组件上?搜索得到的信息很少,大多是关于设置默认字段的。我不想设置默认字段,而是希望在选择特定单选按钮时设置焦点。

7个回答

20

我建议使用原生的org.apache.wicket.ajax.AjaxRequestTarget#focusComponent()。例如:

/**
 * Sets the focus in the browser to the given component. The markup id must be set. If            
 * the component is null the focus will not be set to any component.
 * 
 * @param component
 *            The component to get the focus or null.
 */
 org.apache.wicket.ajax.AjaxRequestTarget#focusComponent(Component component)

1
听听马丁-g说的话吧;-) - Jesse
martin-g的解决方案是唯一一个在我的场景中(模态/弹出)使其工作的解决方案。我认为autofocus只在页面加载时起作用,而不是在模态加载时起作用,因此任何试图在HTML中巧妙设置autofocus属性的努力都会失败 - 总是失败。确保调用myInput.setOutoutMarkupId(true),然后覆盖show(ART target) { super.show(target); target.focusComponent(myInput) }。像买来的一样好用!也许我会写一个完整的答案。 - Volksman

8
一旦您创建了设置焦点的行为,您应该能够在任何事件中将其添加到组件中,只需确保该组件是AjaxRequestTarget的一部分。我不明白为什么这不能起作用...
myRadioButton.add(new AjaxEventBehavior("onchange") {
 @Override
 protected void onEvent(AjaxRequestTarget target) {
    myOtherComponent.add(new DefaultFocusBehavior());
        target.addComponent(myForm);
 }
});

这里有一个链接,展示了如何创建默认的焦点行为,如果您还没有这个功能:http://javathoughts.capesugarbird.com/2009/01/wicket-and-default-focus-behavior.html

1
我建议您将代码复制到答案中(当然要保留原始引用),这样它就不依赖于外部资源。 - tetsuo
这个解决方案的问题在于,一旦你附加它,每次刷新(AjaxRequestTarget#addComponent)时它都会被聚焦(或者至少聚焦JavaScript会被评估)。使用AjaxRequestTarget#focusComponent是一次性的聚焦,因此更适合于问题中请求的行为(“单选按钮已选择”)。 - Michal Bernhard

3
如果您只想通过javascript设置焦点,而不想重新加载表单或组件,您可以使用以下代码:

import org.apache.wicket.Component;

public class JavascriptUtils {
    private JavascriptUtils() {

    }

    public static String getFocusScript(Component component) {
        return "document.getElementById('" + component.getMarkupId() + "').focus();";
    }
}

然后在任何Ajax方法中,您都可以使用:

target.appendJavascript(JavascriptUtils.getFocusScript(componentToFocus));

1

对于类似弹出式的modalWindow,我的解决方法是在第一个输入标签上使用"autofocus"属性。一种简单的解决方案是直接将其添加到HTML中。

<input ..... autofocus>

另一种解决方案是将其添加到modalWindow本身:

@Override
public void show(AjaxRequestTarget target) {
    super.show(target);
    setUpFocus();
}

protected void setUpFocus() {
    DeepChildFirstVisitor visitor = new DeepChildFirstVisitor() {

        @Override
        public void component(Component component, IVisit<Void> iVisit) {
            if (isAutofocusable(component)) {
                component.add(new AttributeAppender("autofocus", ""));
                iVisit.stop();
            }
        }

        @Override
        public boolean preCheck(Component component) {
            return false;
        }
    };
    this.visitChildren(FormComponent.class, visitor);
}

    protected boolean isAutofocusable(Component component) {
        if (component instanceof TextArea ||
                component instanceof DropDownChoice ||
//                component instanceof RadioChoice ||
                component instanceof AjaxCheckBox ||
                component instanceof AjaxButton || 
                component instanceof TextField) {
            return true;
        }
        return false;
    }

RadioChoice已被注释掉,因为这个解决方案在那上面不起作用。对于RadioChoice,我建议实现一个FocusedRadioChoice:

public class FocusedRadioChoice<T> extends RadioChoice<T> {
//constructors...
    @Override
    protected IValueMap getAdditionalAttributes(int index, T choice) {
        super.getAdditionalAttributes(0, choice);
        AttributeMap am = new AttributeMap();
        am.put("autofocus", "");
        return am;
    }
}

这两种解决方案都对我不起作用:直接在HTML中设置自动对焦或使用上面的代码来使用属性附加器来设置焦点。我认为,也许自动对焦属性只在页面加载时有效,而不是在模态对话框加载时有效? - Volksman

0

有没有一种方法可以在不使用JavaScript的情况下实现相同的功能?

(我正在实现一个带有反馈面板的表单,只有在关闭JavaScript时才会出现,因此在那里依赖JavaScript是没有意义的...,-)

我只能找到使用JS .focs()的答案...也许Wicket 1.5会提供Component.setFocus()方法...


3
如果不使用 JavaScript,就无法设置 HTML 元素的焦点。HTML 没有标签或属性可以实现这一点(目前还没有)。如果 Wicket 实现了 Component.setFocus() 方法,仍然需要生成一些 JavaScript 代码来启用它。 - Marcelo
1
你可以使用简单的HTML属性“autofocus”。你可以直接将其添加到HTML的第一个输入标签中,或者像“component.add(new AttributeAppender("autofocus", ""));”这样动态添加。请查看我的简短回答。 - BlondCode

0
如果您正在使用Ajax按钮,则可以在按钮的 onSubmit 方法中调用 target.focusComponent(myComponent); 来简单地聚焦于组件。

0

@martin-g的解决方案是唯一一个在我的场景中(模态/弹出)使其正常工作的解决方案。

注意: 我认为在HTML中明确嵌入autofocus只能在页面加载时起作用,而不是在模态加载时起作用,因此任何试图巧妙地在模态的HTML中设置autofocus属性的努力都会失败 - 总是如此。

在这里,我列出了使用Wicket的全部功能(无需JS!)来设置名为“myInput”的输入字段上的焦点的步骤:

在onInitialize中:

// Make sure the field has an ID in markup
myInput.setOutoutMarkupId(true);

提供一个重写的 show 方法,在其中调用 focusComponent 方法:
public void show(AjaxRequestTarget target)
{
    // Make sure you call the super method first!
    super.show(target);

    target.focusComponent(myInput);
}

这需要您的组件是模态内容类的属性,以便您可以在show方法中访问它。为了避免为输入组件创建类属性,您可以将此解决方案与BlondCode的解决方案混合,通过替换该解决方案的

部分。

component.add(new AttributeAppender("autofocus", ""));

使用

target.focusComponent(component);

这个也可以运行!


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