使用aria-live在vue.js中向屏幕阅读器发布信息

Wil*_* P. 8 javascript accessibility wai-aria nvda vue.js

我正在尝试获取一个vue组件,以便在我的网站上发生不同事件时动态地向屏幕阅读器发布信息.

我有它的工作,点击一个按钮将填充一个aria-live="assertive"role="alert"文本的跨度.这在第一次正常工作,但是,单击具有类似行为的其他按钮会导致NVDA在读取新文本之前两次读取前一个文本.这似乎是在vue中发生的,但是没有使用jquery的类似设置,所以我猜它与vue呈现给DOM的方式有关.

我希望有一些方法可以解决这个问题,或者更好的方法来向用户阅读没有此问题的文本.任何帮助是极大的赞赏.

这是我在工作代码沙箱中设置的一个简单组件,用于显示我遇到的问题(导航到代码的组件/ HelloWorld.vue) - 注意:根据下面的答案,此沙箱已更改.该组件的完整代码如下:

export default {
  name: "HelloWorld",
  data() {
    return {
      ariaText: ""
    };
  },
  methods: {
    button1() {
      this.ariaText = "This is a bunch of cool text to read to screen readers.";
    },
    button2() {
      this.ariaText = "This is more cool text to read to screen readers.";
    },
    button3() {
      this.ariaText = "This text is not cool.";
    }
  }
};
Run Code Online (Sandbox Code Playgroud)
<template>
  <div>
    <button @click="button1">1</button>
    <button @click="button2">2</button>
    <button @click="button3">3</button><br/>
    <span role="alert" aria-live="assertive">{{ariaText}}</span>
  </div>
</template>
Run Code Online (Sandbox Code Playgroud)

Wil*_* P. 3

好的,我发现更一致的工作方式是用要读取的新文本将新元素添加到父容器,而不是用新文本替换元素中的文本。我没有将文本存储为单个字符串,而是将其存储在一个字符串数组中,该数组将v-for显示在容器内的页面上aria-live

我已经构建了一个完整的组件,它将以各种方式执行此操作,作为任何想要执行相同操作的人的示例:

export default {
    props: {
        value: String,
        ariaLive: {
            type: String,
            default: "assertive",
            validator: value => {
                return ['assertive', 'polite', 'off'].indexOf(value) !== -1;
            }
        }
    },
    data() {
        return {
            textToRead: []
        }
    },
    methods: {
        say(text) {
            if(text) {
                this.textToRead.push(text);
            }
        }
    },
    mounted() {
        this.say(this.value);
    },
    watch: {
        value(val) {
            this.say(val);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)
.assistive-text {
    position: absolute;
    margin: -1px;
    border: 0;
    padding: 0;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
}
Run Code Online (Sandbox Code Playgroud)
<template>
    <div class="assistive-text" :aria-live="ariaLive" aria-relevant="additions">
        <slot></slot>
        <div v-for="(text, index) in textToRead" :key="index">{{text}}</div>
    </div>
</template>
Run Code Online (Sandbox Code Playgroud)

可以通过将父容器上的变量设置为v-model组件的变量来使用此功能,并且对该变量的任何更改都将被屏幕阅读器读取一次(以及每当父容器变为以选项卡为中心时)。

它也可以通过以下方式触发this.$refs.component.say(textToSay);- 请注意,如果父容器变得以选项卡为中心,这也将再次触发。通过将元素放入不会接收焦点的容器中可以避免此行为。

它还包括一个插槽,因此可以像这样添加文本:<assistive-text>Text to speak</assistive-text>但是,这不应该是动态/小胡子变量,否则当文本更改时您将遇到原始问题中的问题。

我还使用该组件的工作示例更新了问题中发布的沙箱。