仅针对带有文本的最后一级元素

Target only last level element with text

我正在尝试将 tabindex="0" 应用于一堆元素:

这是我的代码:

$(elems).not("[disabled]").each(function() {
    let n = $(this).attr('tabindex');
    if ((typeof n == typeof undefined || n == !1) && ($(this).text().trim().length)) {
        $(this).attr('tabindex', '0')
    }
});

用户是盲人,用TAB翻页,用语音合成阅读文字。

1#这个案例还可以

    <div>Example text</div>
--> <div tabindex="0">Example text</div>

2#这个case有问题(先关注div再关注p所以"Example text"看了两遍)

    <div>
        <p>Example text</p>
    </div>

--> <div tabindex="0">
        <p tabindex="0">Example text</p>
    </div>

2#这种情况比较有问题("First text Second text"再读一遍"Second text")

<div tabindex="0">First text
    <p tabindex="0">Second text</p>
</div>

我希望先阅读 "First text",然后阅读 "Second text"。

我有很多解决方案,但都很繁琐。如果你有一个简单的,提前谢谢你!

基本上,我只想在带有文本的 TAG 上应用 tabindex,除非它是文本格式选项卡 (b、i、u、strong...)。示例:

<div>
  <p tabindex="0">This is <b>great</b> !</p>
</div>

根据我对您问题的了解,听起来主要问题是 jQuery 的 text() 函数在元素具有子元素的情况下返回过多文本。在以下示例中,您特别希望能够将 "foo" 和 "baz" 与 "bar" 分开:

<div>foo<p>bar</p>baz</div>

如果是这种情况,那么您需要停止使用 "elements" 并开始使用 Nodes。节点更多 fine-grained,让您更深入地了解 DOM 的实际情况。比如上面会被解析成大致如下的节点树:

element: div
    text: "foo"
    element: p
        text: "bar"
    text: "baz"

节点更难处理,因为有更多不同类型和不同特性的节点。不过,当您需要更多控制时,这是您通常必须承担的成本。

这是您可以如何实现目标的一个示例,但您可能需要根据自己的具体需求对其进行调整。

var root = document.getElementById('root');

processChildNodes( root );

// Log the resulting HTML to the console
// so that we can see the tab index attribute:
console.log( root.innerHTML );

function processChildNodes(parent){
  var child;
  // Get either the first child of the parent or the next sibling of
  // the current child.
  // If we don't have any children or we run out of siblings, then
  // we're done here.
  while ( child = child ? child.nextSibling : parent.firstChild ){
    // If the node is disabled, then skip it.
    // Maybe this should be data-disabled?
    switch (child.nodeType){
      case Node.ELEMENT_NODE:
        // If the current node is an element, then set the tabIndex
        // and process the children.
        if ( !child.hasAttribute('disabled') ){
          child.setAttribute( 'tabindex',  '0' );
          processChildNodes( child );
        }
        break;
      case Node.TEXT_NODE:
        // If the current node is text, then "read" the text.
        // You don't have an example of how this is supposed to work,
        // so I'll just print it to the console.
        var text = (child.nodeValue || "").trim();
        if (text.length > 0) console.log( 'reading: ' + text );
        break;
    }
  }
}
<div id="root">
  <div>Example text 1</div>

  <div>
    <p>Example text 2</p>
  </div>

  <div>
      First text
      <p>Second text</p>
      Third text
      <p>
        Fourth text
        <span>Fifth text</span>
      </p>
      <p disabled>
        Skip this one.
      </p>
  </div>
</div>