<p:selectBooleanButton>
这是因为PrimeFaces 实际呈现的状态复选框的方式SelectBooleanButtonRenderer
:
<div id="formId:buttonId" type="button" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only">
<input id="formId:buttonId_input" name="formId:buttonId_input" type="checkbox" class="ui-helper-hidden">
<span class="ui-button-text">no</span>
</div>
display:none
该复选框被类中的 CSS属性完全隐藏,.ui-helper-hidden
因此永远无法获得焦点。
如果我们查看对应的复选框<p:selectBooleanCheckbox>
,它也将复选框替换为一个视觉上更吸引人的实际上是可聚焦的小部件,然后我们会看到该复选框并没有被 CSS 完全隐藏,而是通过被包裹在<div>
绝对不可见的由 CSSposition:absolute
在.ui-helper-hidden-accessible
类中定位,因此仅被复选框小部件覆盖:
<div id="formId:checkboxId" class="ui-chkbox ui-widget">
<div class="ui-helper-hidden-accessible">
<input id="formId:checkboxId_input" name="formId:checkboxId_input" type="checkbox">
</div>
<div class="ui-chkbox-box ui-widget ui-corner-all ui-state-default">
<span class="ui-chkbox-icon"></span>
</div>
</div>
我不会考虑无法<p:selectBooleanButton>
聚焦的“预期”或“直觉”行为,如果我是你,我肯定会将这个 UX 问题报告给 PrimeFaces。
同时,解决此问题的最佳方法是创建一个自定义渲染器,该渲染器将覆盖encodeMarkup()
PrimeFaces 的方法,SelectBooleanButtonRenderer
如下所示,以便class="ui-helper-hidden"
从复选框中删除 并将其包装在 a 中<div class="ui-helper-hidden-accessible>
,就像<p:selectBooleanCheckbox>
正在做的那样:
public class MySelectBooleanButtonRenderer extends SelectBooleanButtonRenderer {
@Override
protected void encodeMarkup(FacesContext context, SelectBooleanButton button) throws IOException {
ResponseWriter writer = context.getResponseWriter();
String clientId = button.getClientId(context);
boolean checked = Boolean.valueOf(ComponentUtils.getValueToRender(context, button));
boolean disabled = button.isDisabled();
String inputId = clientId + "_input";
String label = checked ? button.getOnLabel() : button.getOffLabel();
String icon = checked ? button.getOnIcon() : button.getOffIcon();
//button
writer.startElement("div", null);
writer.writeAttribute("id", clientId, "id");
writer.writeAttribute("type", "button", null);
writer.writeAttribute("class", button.resolveStyleClass(checked, disabled), null);
if(disabled) writer.writeAttribute("disabled", "disabled", null);
if(button.getTitle()!= null) writer.writeAttribute("title", button.getTitle(), null);
if(button.getStyle() != null) writer.writeAttribute("style", button.getStyle(), "style");
//input
writer.startElement("div", null); // <-- Added.
writer.writeAttribute("class", "ui-helper-hidden-accessible", null); // <-- Added.
writer.startElement("input", null);
writer.writeAttribute("id", inputId, "id");
writer.writeAttribute("name", inputId, null);
writer.writeAttribute("type", "checkbox", null);
// writer.writeAttribute("class", "ui-helper-hidden", null); <-- Removed.
if(checked) writer.writeAttribute("checked", "checked", null);
if(disabled) writer.writeAttribute("disabled", "disabled", null);
if(button.getOnchange() != null) writer.writeAttribute("onchange", button.getOnchange(), null);
writer.endElement("input");
writer.endElement("div"); // <-- Added.
//icon
if(icon != null) {
writer.startElement("span", null);
writer.writeAttribute("class", HTML.BUTTON_LEFT_ICON_CLASS + " " + icon, null);
writer.endElement("span");
}
//label
writer.startElement("span", null);
writer.writeAttribute("class", HTML.BUTTON_TEXT_CLASS, null);
writer.writeText(label, "value");
writer.endElement("span");
writer.endElement("div");
}
}
(查看该//input
部分,我添加了<--
注释来解释我在复制粘贴的原始源代码中添加/删除了哪些行)
要让它运行,请在以下位置注册它faces-config.xml
:
<render-kit>
<renderer>
<component-family>org.primefaces.component</component-family>
<renderer-type>org.primefaces.component.SelectBooleanButtonRenderer</renderer-type>
<renderer-class>com.example.MySelectBooleanButtonRenderer</renderer-class>
</renderer>
</render-kit>
(component-family
和renderer-type
值是从SelectBooleanButton
组件中提取的)
这对我有用,嗯,有点。获得焦点,<p:selectBooleanButton>
您可以使用空格键切换布尔状态。但是,焦点以任何方式在视觉上都不可见。这需要在 JavaScript 端解决。当隐藏的复选框获得焦点时,<div class="ui-button">
代表按钮应该获得一个类。.ui-state-focus
以下 jQuery 实现了这一点:
$(".ui-button input[type=checkbox]").focus(function() {
$(this).closest(".ui-button").addClass("ui-state-focus");
}).blur(function() {
$(this).closest(".ui-button").removeClass("ui-state-focus");
});
现在它完全适合我。
在真正的 PrimeFaces 源代码中,这应该通过文件init()
的PrimeFaces.widget.SelectBooleanButton
功能来解决forms.js
。