簡體   English   中英

支持框架時,如何讓事件監聽器響應整個文檔?

[英]When supporting frames, How to get an event listener to respond to the whole document?

我正在向使用框架的舊版應用程序添加輔助功能。 我目前正在研究跳過導航功能。

  • 將 SkipNavigation 添加到位於window.top的 DOM
  • 我有一個可中止的keydown偵聽器來捕捉Tab按下並顯示 SkipNav - 它有效
  • 我添加了一個事件列表器來監聽對文檔的點擊,以允許用戶在無意中彈出它時忽略 SkipNavigation div
    • 此偵聽器被添加到document ,而不是 SkipNav,但它只響應 SkipNav 內的點擊

我已經為事件偵聽器嘗試了各種選項組合。 目前的選項是: { capture:true, passive:true } ,據我所知,這個偵聽器將首先被調用,並且事件不能被任何冒泡處理程序取消。

這是我的SkipNavigation object 的create方法:

  // creates DOM elements, sets up event listeners
  create()
  {
    this.div = document.createElement('div');
    this.div.setAttribute('id', 'skip_nav_div');
    this.div.setAttribute('role', 'navigation');
    this.div.setAttribute('aria-label', 'skip navigation');
    this.div.setAttribute('tabindex', '-1');
    this.div.className = 'SkipNavigation';

    this.button = document.createElement('button');
    this.button.setAttribute('id', 'skip_nav_button');
    this.button.textContent = 'skip to main content';
    this.button.classList = 'btn btn-light';
    this.button.addEventListener('click', () => { this.skipNav(this) });

    this.div.appendChild(this.button);
    document.body.appendChild(this.div);

    this.current_element = null;

    // This event listener will abort itself after a Tab key is pressed for the
    // first time.
    // It will display a button to skip to main content if a Tab is pressed.
    this.tab_controller = new AbortController();
    document.addEventListener('keydown', (e) =>
    {
      switch (e.key)
      {
        case 'Tab':
          e.preventDefault();
          // save currently focused element
          this.current_element = document.activeElement;
          // check if there's content to skip to
          if (this.getContent())
          {
            // show the SkipNav
            this.show(e);
          }
          // turn off this event listener
          this.tab_controller.abort();
          break;
        default:
          // do nothing
      } 
    }, {signal: this.tab_controller.signal});

    this.abortOnClick = function (e)
    {
      // don't intercept clicks on the button itself
      if (e.target === this.button)
      {
        return;
      }
      this.tab_controller.abort();
      // also hide the SkipNav if currently shown
      if (this.div.classList.contains('is-open'))
      {
        this.hide();
        // and reset focus to where the user was
        if (this.current_element) this.current_element.focus();
      }
      document.removeEventListener('click', this.abortOnClick.bind(this), { capture:true, passive:true });
    }.bind(this);
    document.addEventListener('click', this.abortOnClick.bind(this), { capture:true, passive:true });
  }

在我們的一個內部框架中,我有一個事件偵聽器實現了一個不同的 object 的類似目的,它被添加到document中並且正確響應任何點擊(並且它不使用捕獲)。
我不知道為什么這個abortOnClick處理程序只響應 SkipNav div。

任何幫助是極大的贊賞。

對腳本的依賴越少越好。

如果我理解正確的話,您目前正在嘗試將 state 添加到跳過導航中,使其只能使用一次。 這給界面增加了額外的復雜性並且是出乎意料的。

目前尚不清楚當前的解決方案實際上是如何通過this.hide隱藏導航的,重要的是它不會像display: none那樣從輔助技術中隱藏起來。

我的建議是堅持通過 CSS 在視覺上隱藏跳過按鈕的最佳做法,並依靠自然的 Tab 鍵順序。

以下代碼無效 HTML 並且不適用於 HTML 5 文檔類型 在框架集文檔類型中,不允許使用框架集和框架以外的元素。

 const div = document.createElement('div'); div.setAttribute('id', 'skip_nav_div'); div.setAttribute('role', 'navigation'); div.setAttribute('aria-label', 'skip navigation'); div.className = 'SkipNavigation'; const button = document.createElement('button'); button.setAttribute('id', 'skip_nav_button'); button.textContent = 'skip to main content'; button.classList = 'btn btn-light visually-hidden'; button.addEventListener('click', () => document.querySelector('#main').focus()); div.appendChild(button); document.body.insertBefore(div, document.body.firstChild);
 frame { border: 1px dashed grey; }.SkipNavigation { position: absolute; } /* https://www.scottohara.me/blog/2017/04/14/inclusively-hidden.html#hiding-content-visually */.visually-hidden:not(:focus):not(:active) { clip: rect(0 0 0 0); clip-path: inset(50%); height: 1px; overflow: hidden; position: absolute; white-space: nowrap; width: 1px; }
 <.DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4:01 Frameset//EN" "http.//www.w3.org/TR/html4/frameset,dtd"> <html> <:-- <frameset rows="100."> <frame title="Nav" src="https://example.com/" /> <frame title="Main content" id="main" src="https://example.com/" /> </frameset> --> <div id="main" tabindex="-1">Main for demonstration</div> <p><a href="#">Some link to demonstrate focus order</a></p> </html>

提供適當的地標

據我所知,屏幕閱讀器已經內置了框架導航,因此我們應該通過提供有用的名稱來支持它。

此示例使用屬性選擇器通過其 src 屬性查找框架,以防它們不提供名稱或 ID。

document.querySelector('frame[src*="navigation"]').title = "Navigation";
document.querySelector('frame[src*="index"]').title ="Main content";
…

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM