日常开发报错

1.报错

<template>
  <div>
    <!-- 这个div将使用aria-hidden,尽管它包含一个可聚焦的元素 -->
    <div aria-hidden="true" ref="hiddenAncestor">
      <button ref="focusableButton" @focus="onFocus">Focus me!</button>
    </div>
    <button @click="programmaticallyFocus">Programmatically Focus Button</button>
  </div>
</template>

<script>
export default {
  methods: {
    onFocus() {
      console.log('Button received focus, but its ancestor is aria-hidden.');
      // 在这里,你可能想要添加一些逻辑来处理焦点,但重要的是要注意
      // aria-hidden的祖先元素会导致无障碍性问题。
    },
    programmaticallyFocus() {
      // 通过JavaScript程序化地将焦点设置到按钮上
      this.$refs.focusableButton.focus();
    }
  }
};
</script>

点击第一个按钮会报错,
Blocked aria-hidden on an element because its descendant retained focus. The focus must not be hidden from assistive technology users. Avoid using aria-hidden on a focused element or its ancestor. Consider using the inert attribute instead, which will also prevent focus. For more details, see the aria-hidden section of the WAI-ARIA specification at https://w3c.github.io/aria/#aria-hidden.
Element with focus: button
Ancestor with aria-hidden: <div data-v-7ba5bd90 aria-hidden=​"true">​…​​
在这里插入图片描述

这个错误消息提示的是关于无障碍访问性(Accessibility)的问题,特别是在使用aria-hidden属性时需要注意的事项。aria-hidden属性用于隐藏元素及其所有子元素,使其不被屏幕阅读器等辅助技术所访问。然而,当使用aria-hidden隐藏的元素或其祖先元素中包含了当前获得焦点的元素时,就会出现问题,因为这可能使得辅助技术的用户无法得知哪个元素是当前焦点所在。

<template>
  <div class="accessibility-container">
    <!-- 使用 v-show 来控制可见性,而不是 aria-hidden -->
    <div 
      class="focusable-section"
      :class="{ 'is-hidden': isHidden }"
      ref="focusableSection"
    >
      <button 
        ref="focusableButton"
        class="focus-button"
        @focus="onFocus"
        @click="handleButtonClick"
        :tabindex="isHidden ? -1 : 0"
        :aria-hidden="isHidden"
      >
        Focus me!
      </button>
    </div>

    <div class="controls-section">
      <button 
        class="control-button"
        @click="toggleVisibility"
      >
        {{ isHidden ? 'Show' : 'Hide' }} Section
      </button>
      
      <button 
        class="control-button"
        @click="programmaticallyFocus"
        :disabled="isHidden"
      >
        Focus Button
      </button>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue'

const focusableButton = ref(null)
const focusableSection = ref(null)
const isHidden = ref(false)

const onFocus = () => {
  if (!isHidden.value) {
    console.log('Button focused successfully')
  }
}

const handleButtonClick = () => {
  console.log('Button clicked')
}

const toggleVisibility = () => {
  isHidden.value = !isHidden.value
  
  // 如果隐藏时有焦点,将焦点移到其他可访问的元素
  if (isHidden.value && document.activeElement === focusableButton.value) {
    document.querySelector('.control-button')?.focus()
  }
}

const programmaticallyFocus = () => {
  if (!isHidden.value && focusableButton.value) {
    focusableButton.value.focus()
  }
}

// 监听键盘事件以提供更好的无障碍性支持
onMounted(() => {
  const handleKeyDown = (event) => {
    if (event.key === 'Escape' && !isHidden.value) {
      toggleVisibility()
    }
  }
  
  window.addEventListener('keydown', handleKeyDown)
  
  // 清理事件监听
  onUnmounted(() => {
    window.removeEventListener('keydown', handleKeyDown)
  })
})
</script>

<style scoped>
.accessibility-container {
  padding: 20px;
}

.focusable-section {
  margin-bottom: 20px;
  padding: 15px;
  border: 1px solid #ddd;
  border-radius: 4px;
  transition: opacity 0.3s ease;
}

.focusable-section.is-hidden {
  opacity: 0;
  pointer-events: none;
  visibility: hidden;
}

.focus-button {
  padding: 8px 16px;
  background-color: #4CAF50;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  transition: background-color 0.3s;
}

.focus-button:focus {
  outline: 3px solid #2196F3;
  outline-offset: 2px;
}

.focus-button:hover {
  background-color: #45a049;
}

.controls-section {
  display: flex;
  gap: 10px;
}

.control-button {
  padding: 8px 16px;
  background-color: #2196F3;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  transition: background-color 0.3s;
}

.control-button:disabled {
  background-color: #cccccc;
  cursor: not-allowed;
}

.control-button:hover:not(:disabled) {
  background-color: #1976D2;
}

.control-button:focus {
  outline: 3px solid #FF9800;
  outline-offset: 2px;
}

/* 确保焦点轮廓在高对比度模式下可见 */
@media (forced-colors: active) {
  .focus-button:focus,
  .control-button:focus {
    outline: 3px solid CanvasText;
  }
}
</style>

2.tabindex

tabindex 是一个 HTML 属性,用于指定元素获得焦点的顺序。它对于提高网页的可访问性非常有用,特别是当网页上有多个交互式元素(如按钮、链接和输入框)时。tabindex 的值可以是正整数、零或负整数:

<template>
  <div class="accessibility-container">
    <h1>Vue tabindex Example</h1>
    <button :tabindex="tabIndex1" @click="handleClick1">Button 1 (tabindex={{ tabIndex1 }})</button>
    <button :tabindex="tabIndex2" @click="handleClick2">Button 2 (tabindex={{ tabIndex2 }})</button>
    <button @click="toggleTabIndex">Toggle Tabindex</button>
  </div>
</template>

<script>
export default{
  data: function() {
return {
        tabIndex1: 1, // Button 1 will have tabindex 1 initially
        tabIndex2: 0  // Button 2 will have tabindex 0 initially
      };
},
      methods: {
        handleClick1() {
          alert('Button 1 clicked!');
        },
        handleClick2() {
          alert('Button 2 clicked!');
        },
        toggleTabIndex() {
          // Toggle tabindex values between 1 and -1 for Button 1
          this.tabIndex1 = this.tabIndex1 === 1 ? -1 : 1;
          // Toggle tabindex values between 0 and 2 for Button 2
          this.tabIndex2 = this.tabIndex2 === 0 ? 2 : 0;
        }
      }
}
</script>

<style scoped>
.accessibility-container {
  padding: 20px;
}

.focusable-section {
  margin-bottom: 20px;
  padding: 15px;
  border: 1px solid #ddd;
  border-radius: 4px;
  transition: opacity 0.3s ease;
}

.focusable-section.is-hidden {
  opacity: 0;
  pointer-events: none;
  visibility: hidden;
}

.focus-button {
  padding: 8px 16px;
  background-color: #4CAF50;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  transition: background-color 0.3s;
}

.focus-button:focus {
  outline: 3px solid #2196F3;
  outline-offset: 2px;
}

.focus-button:hover {
  background-color: #45a049;
}

.controls-section {
  display: flex;
  gap: 10px;
}

.control-button {
  padding: 8px 16px;
  background-color: #2196F3;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  transition: background-color 0.3s;
}

.control-button:disabled {
  background-color: #cccccc;
  cursor: not-allowed;
}

.control-button:hover:not(:disabled) {
  background-color: #1976D2;
}

.control-button:focus {
  outline: 3px solid #FF9800;
  outline-offset: 2px;
}

/* 确保焦点轮廓在高对比度模式下可见 */
@media (forced-colors: active) {
  .focus-button:focus,
  .control-button:focus {
    outline: 3px solid CanvasText;
  }
}
</style>

根据键盘序列导航的顺序,值为 0 、非法值、或者没有 tabindex 值的元素应该放置在 tabindex 值为正值的元素后面。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐