【问题标题】:Dojo dijit tree with checkbox is not keyboard accessible带有复选框的 Dojo dijit 树无法通过键盘访问
【发布时间】:2016-06-10 12:13:43
【问题描述】:

我创建了一个 dijit.Tree 对象,其中每个节点都是一个复选框。当您选择/取消选择父节点时,子节点会被选择/取消选择; 当其中一个孩子被取消选择时,父母被取消选择;当所有孩子都被选中时,父母被选中。它工作得很好。
但是我需要它可以通过键盘访问。当我导航到树节点并按空格键或 Enter 时,没有任何反应。

我尝试将 tabindex 和 aria-role 添加到复选框(以编程方式),但没有成功。

这是小提琴 - http://jsfiddle.net/pdabade/pyz9Lcpv/65/

require([ 
"dojo/_base/window", "dojo/store/Memory",
"dijit/tree/ObjectStoreModel",
"dijit/Tree", "dijit/form/CheckBox", "dojo/dom",
"dojo/domReady!"
], function(win, Memory, ObjectStoreModel, Tree, checkBox, dom) {

// Create test store, adding the getChildren() method required by      ObjectStoreModel
var myStore = new Memory({
data: [{
  id: 'allDocuments',
  name: 'All Documents'
}, {
  id: 'inboxDocuments',
  name: 'Inbox Documents',
  parent: 'allDocuments'
}, {
  id: 'outboxDocuments',
  name: 'Outbox Documents',
  parent: 'allDocuments'
}, {
  id: 'draftDocuments',
  name: 'Draft Documents',
  parent: 'allDocuments'
}, {
  id: 'finalDocuments',
  name: 'Final Documents',
  parent: 'allDocuments'
}],
getChildren: function(object) {
  return this.query({
    parent: object.id
  });
}
});
// Create the model
var myModel = new ObjectStoreModel({
store: myStore,
query: {
  id: 'allDocuments'
}
});

// Create the Tree.
var tree = new Tree({
model: myModel,

autoExpand: true,
getIconClass: function(item, opened) {
  // console.log('tree getIconClass', item, opened);
  // console.log('tree item type', item.id);
},

onClick: function(item, node, event) {
  //node._iconClass= "dijitFolderClosed";
  //node.iconNode.className = "dijitFolderClosed";
  var _this = this;
  console.log(item.id);
  var id = node.domNode.id,
    isNodeSelected = node.checkBox.get('checked');

  dojo.query('#' + id + ' .dijitCheckBox').forEach(function(node) {
    dijit.getEnclosingWidget(node).set('checked', isNodeSelected);
  });

  if (item.id != 'allComments') {
    if (!isNodeSelected) {
      var parent = node.tree.rootNode; // parent node id
      //console.log(node);
      parent.checkBox.set('checked', false);
    } else {
      var parent = node.tree.rootNode;
      var selected = true;
      var i = 0;
      dojo.query('#' + parent.id +  '.dijitCheckBox').forEach(function(node) {
        if (i > 0) {
          var isSet = dijit.getEnclosingWidget(node).get('checked');
          console.log(isSet);
          if (isSet == false) {
            selected = false;
          }
        }
        i++;
      });
      if (selected) {
        parent.checkBox.set('checked', true);
      }
    }

  }
  //console.log(node.id);
},
_createTreeNode: function(args) {
  var tnode = new dijit._TreeNode(args);
  tnode.labelNode.innerHTML = args.label;
  console.log(args);
  var cb = new dijit.form.CheckBox({
    "aria-checked": "false",
    "aria-describedby": args.label
  });
  cb.placeAt(tnode.labelNode, "first");
  tnode.checkBox = cb;


  return tnode;
}

});
tree.placeAt(contentHere);
tree.startup();
tree.checkedItems();
//tree.expandAll();


});

}

关于如何使其键盘可访问的任何想法?

谢谢!

【问题讨论】:

    标签: dojo accessibility dijit.tree


    【解决方案1】:

    查看 dijit/Tree 源代码,我发现它将函数 _onNodePress() 设置为键盘事件的事件处理程序。您可以覆盖它(或在其后添加一个方面)并手动处理您想要的按键。它将树节点和一个事件对象作为参数,您可以使用它来专门检查空格和回车键。

    我用一个例子叉了你的 jsfiddle:https://jsfiddle.net/pgianna/jjore5sm/1/

    _onNodePress: function(/*TreeNode*/ nodeWidget, /*Event*/ e){
        // This is the original implementation of _onNodePress:
        this.focusNode(nodeWidget);
    
        // This requires "dojo/keys"
        if (e.keyCode == keys.ENTER || e.keyCode == keys.SPACE)
        {
            var cb = nodeWidget.checkBox;
            cb.set('checked', !cb.get('checked'));
        }
    }
    

    【讨论】:

    【解决方案2】:

    不要在复选框中添加rolearia-checkedtabindex。这些已经内置在控件中,因此您增加了将其破坏的风险。您可能还可以摆脱每个role="presentation",因为它们在<div>s 和<span>s 上,它们本质上是展示性的。最后,如果您希望它可以访问,您需要在与复选框关联的每个文本块上使用<label>aria-describedby 不正确,无论如何都是不太好的选择。

    我收到错误:Uncaught TypeError: tree.checkedItems is not a function(第 159 行)

    你还有一个很大的焦点管理问题。将以下内容放入您的 CSS 中,您将看到每个控件都需要按两次 Tab 键(如果从焦点复选框开始)::focus {outline:2px solid #f00;}

    看起来您的包含元素窃取了任何点击,这意味着永远不会选择正确的元素。带有dijit dijitReset dijitInline dijitCheckBox 类的<span> 一直在窃取焦点,因为它将tabindex-1 切换到0,将自己进出标签顺序。这可能是一个因素。

    我建议解决脚本错误,然后查看焦点管理。

    【讨论】:

    • 修复了jsfiddle.net/pdabade/pyz9Lcpv/65 中的错误。我理解您所说的“每个控件按两次 Tab 键”。但是我们如何解决这个焦点管理问题呢?
    【解决方案3】:

    使用 dijit,后台会发生各种您无法控制的事情。正如 aardrian 所说,有很多 role=presentation 并且 已经处理了选择,它的角色本质上是一个复选框。这些 aria 属性适用于您使用 div/span 标签制作自定义复选框时。

    代码中隐藏了一个本机复选框,但它的不透明度设置为 0,因此您看不到它。 dijit 可能将它用于复选框事件。

    本机复选框也有 data-dojo-attach-event="ondijitclick:_onClick"。我不确定这意味着什么,但每当我在事件名称中看到“点击”时,我都会怀疑它可能不适用于键盘。

    我在https://dojotoolkit.org/reference-guide/1.10/dijit/form/CheckBox.html 上尝试了该示例,它适用于键盘。点击空格将选中和取消选中该框。能否看到复选框的焦点是另一个问题。

    附带说明,如果您的复选框树使用 aria-checked="mixed" 作为父分支,那可能会很好。每当您有一些子复选框被选中而一些未被选中时,您可以使用父复选框的“混合”来指示混合选择。不确定 dijit 是否支持。

    【讨论】:

    • 我已经实现了普通的 dijit/form/CheckBox 并且它可以在键盘上正常工作。问题是当我在 dijit/Tree 中使用复选框时。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-15
    • 2013-12-12
    相关资源
    最近更新 更多