MST

星途 面试题库

面试题:Vue组件可访问性设计中的键盘导航实现

在Vue组件里,实现良好的键盘导航对于可访问性至关重要。假设你正在开发一个包含多个交互元素(如按钮、输入框、下拉菜单等)的复杂组件,描述你将如何通过Vue的指令、事件绑定等技术,确保该组件能够使用键盘进行流畅且符合可访问性标准的导航。
13.9万 热度难度
前端开发Vue

知识考点

AI 面试

面试题答案

一键面试
  1. 使用tabindex属性
    • 对于那些默认不参与键盘导航的元素(如自定义的下拉菜单触发按钮等非标准可聚焦元素),可以通过v - bind:tabindex指令为其设置合适的tabindex值。例如,对于一个自定义的下拉菜单触发按钮,设置tabindex="0"使其可以通过Tab键获得焦点。在模板中可以这样写:
    <button v - bind:tabindex="0" @click="toggleDropdown">Toggle Dropdown</button>
    
  2. 键盘事件绑定
    • keydown事件
      • 在组件内,可以使用v - on:keydown(简写为@keydown)来监听键盘按下事件。例如,对于一个具有多个输入框的表单组件,当用户在一个输入框中按下Tab键时,我们可以控制焦点的转移,避免焦点跳出组件范围(如果需要的话)。
      <template>
        <div>
          <input type="text" @keydown="handleKeydown">
          <input type="text" @keydown="handleKeydown">
        </div>
      </template>
      <script>
      export default {
        methods: {
          handleKeydown(event) {
            if (event.key === 'Tab') {
              // 这里可以实现自定义的焦点转移逻辑
              // 例如:阻止默认的焦点转移,手动将焦点设置到下一个元素
              event.preventDefault();
              const currentIndex = Array.from(this.$el.querySelectorAll('input')).indexOf(event.target);
              const nextInput = this.$el.querySelectorAll('input')[currentIndex + 1];
              if (nextInput) {
                nextInput.focus();
              }
            }
          }
        }
      };
      </script>
      
    • keyup事件
      • 有时候也需要监听keyup事件,例如在处理输入框内容的同时,用户可能按下Enter键提交表单。可以通过@keyup.enter来监听Enter键释放事件。
      <input type="text" @keyup.enter="submitForm">
      
  3. 可访问性语义化标签
    • 使用正确的HTML语义化标签,如button标签用于按钮,input标签用于输入框等。Vue组件模板应遵循这些语义,这样浏览器和屏幕阅读器等辅助技术能够正确识别组件内的交互元素。例如:
    <template>
      <div>
        <button>Click Me</button>
        <input type="text" placeholder="Enter text">
      </div>
    </template>
    
  4. 管理焦点状态
    • 在组件的data中定义变量来跟踪当前焦点的元素。例如:
    <template>
      <div>
        <button @focus="setFocus('button1')" @blur="removeFocus('button1')">Button 1</button>
        <input @focus="setFocus('input1')" @blur="removeFocus('input1')" type="text">
      </div>
    </template>
    <script>
    export default {
      data() {
        return {
          focusedElement: null
        };
      },
      methods: {
        setFocus(elementId) {
          this.focusedElement = elementId;
        },
        removeFocus(elementId) {
          if (this.focusedElement === elementId) {
            this.focusedElement = null;
          }
        }
      }
    };
    </script>
    
    • 然后可以根据focusedElement的值来应用一些样式,如添加一个is - focused类,以便为获得焦点的元素提供视觉反馈,符合可访问性要求。

.is - focused { outline: 2px solid blue; }

5. **处理下拉菜单等复杂组件**:
- 对于下拉菜单,当使用键盘打开(例如通过`Enter`或`Space`键)后,需要能够使用箭头键在菜单项之间导航。
- 监听`keydown`事件,当按下箭头键时,判断当前菜单项的索引并移动焦点到相应的下一个或上一个菜单项。
```html
<template>
  <div>
    <button @click="toggleDropdown" @keydown.enter="toggleDropdown" @keydown.space="toggleDropdown">Toggle Dropdown</button>
    <div v - if="isDropdownOpen" @keydown="handleDropdownKeydown">
      <a href="#" v - for="(item, index) in dropdownItems" :key="index" @keydown.enter="selectItem(index)" @focus="setDropdownFocus(index)">{{item}}</a>
    </div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      isDropdownOpen: false,
      dropdownItems: ['Item 1', 'Item 2', 'Item 3'],
      dropdownFocusIndex: 0
    };
  },
  methods: {
    toggleDropdown() {
      this.isDropdownOpen =!this.isDropdownOpen;
    },
    handleDropdownKeydown(event) {
      if (event.key === 'ArrowUp') {
        if (this.dropdownFocusIndex > 0) {
          this.dropdownFocusIndex--;
          this.$el.querySelectorAll('a')[this.dropdownFocusIndex].focus();
        }
      } else if (event.key === 'ArrowDown') {
        if (this.dropdownFocusIndex < this.dropdownItems.length - 1) {
          this.dropdownFocusIndex++;
          this.$el.querySelectorAll('a')[this.dropdownFocusIndex].focus();
        }
      }
    },
    selectItem(index) {
      // 处理菜单项选择逻辑
      console.log('Selected item:', this.dropdownItems[index]);
      this.isDropdownOpen = false;
    },
    setDropdownFocus(index) {
      this.dropdownFocusIndex = index;
    }
  }
};
</script>