Просмотр исходного кода

光标移出需要朗读的元素,又移回来,朗读。光标在需要朗读的元素内部各子孙元素间移动,只朗读一次。

任一存 3 лет назад
Родитель
Сommit
e87ade155e
2 измененных файлов с 72 добавлено и 46 удалено
  1. 69 40
      web/src/utils.js
  2. 3 6
      web/src/views/accessibility.vue

+ 69 - 40
web/src/utils.js

@@ -24,59 +24,87 @@ function mapTags(tag) {
   return ret
 }
 
-let lastMeaningfulNode = null
-function extractTextForMagnify(e, allowRepeatd = false) {
+function extractTextForFocus(e) {
   let meaningfulNode = e.target
 
-  if (e.type === 'mouseover') {
-    while (!meaningfulNode.getAttribute || !meaningfulNode.getAttribute('tabindex')) {
-      meaningfulNode = meaningfulNode.parentNode
-      if (!meaningfulNode) {
-        return
-      }
-    }
+  // 如果天然能focus,但没有被加上tabindex属性,比如focus到了第三方组件内部的可focus元素,直接返回。
+  if (
+    ['A', 'AREA', 'BUTTON', 'INPUT', 'SELECT', 'IFRAME'].includes(meaningfulNode.tagName) &&
+    !meaningfulNode.getAttribute('tabindex')
+  ) {
+    return
+  }
 
-    if (meaningfulNode.getAttribute('tabindex') === '-1') {
+  while (!meaningfulNode.getAttribute || !meaningfulNode.getAttribute('tabindex')) {
+    meaningfulNode = meaningfulNode.parentNode
+    if (!meaningfulNode) {
       return
     }
+  }
 
-    // mouseover事件冒泡到有data-aria-xxx-area attribute的区域包裹元素时,不应该提取该区域包裹元素的无障碍辅助信息。
-    if (
-      meaningfulNode.getAttribute('data-aria-navigation-area') !== null ||
-      meaningfulNode.getAttribute('data-aria-viewport-area') !== null ||
-      meaningfulNode.getAttribute('data-aria-interaction-area') !== null
-    ) {
-      return
-    }
-  } else if (e.type === 'focusin') {
-    // 如果天然能focus,但没有被加上tabindex属性,比如focus到了第三方组件内部的可focus元素,直接返回。
-    if (
-      ['A', 'AREA', 'BUTTON', 'INPUT', 'SELECT', 'IFRAME'].includes(meaningfulNode.tagName) &&
-      !meaningfulNode.getAttribute('tabindex')
-    ) {
-      return
-    }
+  // 约定:tabindex属性值为-1的元素只用于在点击有data-aria-xxx-area attribute的区域包裹元素的子孙元素时,避免focus到区域包裹元素。
+  if (meaningfulNode.getAttribute('tabindex') === '-1') {
+    return
+  }
 
-    while (!meaningfulNode.getAttribute || !meaningfulNode.getAttribute('tabindex')) {
-      meaningfulNode = meaningfulNode.parentNode
-      if (!meaningfulNode) {
-        return
-      }
-    }
+  let elemType = ''
+  const ariaLabel = meaningfulNode.getAttribute('aria-label')
+  if (ariaLabel !== null) {
+    elemType = ariaLabel
+  } else {
+    elemType = mapTags(meaningfulNode.tagName)
+  }
 
-    // 约定:tabindex属性值为-1的元素只用于在点击有data-aria-xxx-area attribute的区域包裹元素的子孙元素时,避免focus到区域包裹元素。
-    if (meaningfulNode.getAttribute('tabindex') === '-1') {
-      return
-    }
+  let elemDisc = ''
+  const ariaDescription = meaningfulNode.getAttribute('aria-description')
+  if (ariaDescription !== null) {
+    elemDisc = ariaDescription
+  } else {
+    elemDisc = meaningfulNode.innerText
   }
 
-  if (!allowRepeatd) {
-    if (meaningfulNode === lastMeaningfulNode) {
+  return {
+    elemType,
+    elemDisc,
+    ariaNode: meaningfulNode,
+  }
+}
+
+let lastMeaningfulNode = null
+function extractTextForMouseOver(e) {
+  let meaningfulNode = e.target
+
+  while (!meaningfulNode.getAttribute || !meaningfulNode.getAttribute('tabindex')) {
+    meaningfulNode = meaningfulNode.parentNode
+    if (!meaningfulNode) {
       return
     }
-    lastMeaningfulNode = meaningfulNode
+  }
+
+  if (meaningfulNode.getAttribute('tabindex') === '-1') {
+    return
+  }
+
+  // mouseover事件冒泡到有data-aria-xxx-area attribute的区域包裹元素时,不应该提取该区域包裹元素的无障碍辅助信息。
+  if (
+    meaningfulNode.getAttribute('data-aria-navigation-area') !== null ||
+    meaningfulNode.getAttribute('data-aria-viewport-area') !== null ||
+    meaningfulNode.getAttribute('data-aria-interaction-area') !== null
+  ) {
+    return
+  }
+
+  // 如果只是在需要朗读的子元素之间进进出出,第一次需要朗读,以后就不需要朗读了。
+  let relatedMeaningfulNode = e.relatedTarget
+  while (relatedMeaningfulNode && (!relatedMeaningfulNode.getAttribute || !relatedMeaningfulNode.getAttribute('tabindex'))) {
+    relatedMeaningfulNode = relatedMeaningfulNode.parentNode
+  }
+  if (relatedMeaningfulNode === meaningfulNode && lastMeaningfulNode === meaningfulNode) {
+    return
   }
   
+  lastMeaningfulNode = meaningfulNode
+
   let elemType = ''
   const ariaLabel = meaningfulNode.getAttribute('aria-label')
   if (ariaLabel !== null) {
@@ -332,7 +360,8 @@ class DebounceScheduler {
 
 export default {
   mapTags,
-  extractTextForMagnify,
+  extractTextForFocus,
+  extractTextForMouseOver,
   isSameObject,
   getAndFocusNextNodeWithCustomAttribute,
   iterateOnFocusableNode,

+ 3 - 6
web/src/views/accessibility.vue

@@ -636,9 +636,6 @@ export default {
     document.addEventListener('mousedown', this.onMouseDown, {
       passive: true,
     })
-    document.addEventListener('mouseover', this.onMouseOver, {
-      passive: true,
-    })
     document.addEventListener("visibilitychange", this.onPageVisibilityChange, {
       passive: true
     })
@@ -911,7 +908,7 @@ export default {
         console.log('刚被要求朗读,忽略hover。');
         return
       }
-      const extractedText = utils.extractTextForMagnify(e)
+      const extractedText = utils.extractTextForMouseOver(e)
       if (extractedText) {
         this.elemType = extractedText.elemType
         this.elemDisc = extractedText.elemDisc
@@ -932,7 +929,7 @@ export default {
         console.log('刚被要求朗读,忽略hover。');
         return
       }
-      const extractedText = utils.extractTextForMagnify(e)
+      const extractedText = utils.extractTextForMouseOver(e)
       if (extractedText) {
         this.elemType = extractedText.elemType
         this.elemDisc = extractedText.elemDisc
@@ -988,7 +985,7 @@ export default {
         console.log('刚按下鼠标,忽略focus。');
         return
       }
-      const extractedText = utils.extractTextForMagnify(e, true)
+      const extractedText = utils.extractTextForFocus(e)
       if (extractedText) {
         this.elemType = extractedText.elemType
         this.elemDisc = extractedText.elemDisc