栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

【无障碍】自动朗读的弹窗和浮层实现

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【无障碍】自动朗读的弹窗和浮层实现

  • 单纯的aria-modal在ios上能不能行,看看aria-modal到底实现了什么(比如tabindex是不是能够不加)——如果不行的话底下的一些android的方法可能得挪出来
  • focus的事件捕获能不能行
  • 为啥外面加了tabindex之后,里面的不加就是一个整体了
  • aria-describedby 和 aria-labelledby为啥会让元素变成一个整体
  • Android的a链接按理说也不需要tabindex——focus需要,tanbindex是-1了才能focus
  • pushState 与 location.hash = 的有个区别会导致问题:pushState的第三个参数url 并不会马上就加载,而是可能在后面,比如页面重载的时候执行,这是导致弹窗没有自动朗读的大问题所在吧
使用Aria-modal属性

在弹窗元素上增加属性:


  • role="dialog"——让浏览器告诉屏幕阅读器一个对话框打开了
  • aria-modal="true"——对话框以外的元素无法被聚焦(android上不生效)
  • tabindex="-1——让对话框可以聚焦但无法被tab访问(android上必须加)。HTML dialog 元素,不能使用tabindex属性
  • aria-label="" 或 aria-labelledby="xx元素id"——指定元素朗读的内容
  • 这里按理说无需加tabindex属性,但实际实验中发现无tabindex不能朗读,可以加上试试
  • 弹窗div加上tabindex属性后,内部需要聚焦的第一个元素也要加上tabindex属性
Android不生效 解决焦点问题

document.activeElement可以获取到当前聚焦的元素

聚焦 使用a链接或直接改hash

原理是用锚点来指定位置。会导致在浏览器会话历史中新增一条记录,需要在关闭弹窗的时候history.back()或者history.go(-1)

	
		打开弹窗按钮
   
   

或者使用js,直接修改hash值

showSelfalert3(){
   this.showMask3 = true;
   this.$nextTick(() => {
		window.location.hash = 'alert-dialog';
		// 或者
		window.history.pushState( window.history.state || {}, document.title, location.href + '#alert-dialog');
	});
}

原理:#代表网页中的一个位置。其右面的字符,就是该位置的标识符
为网页位置指定标识符,有两个方法。一是使用锚点,比如,二是使用id属性,比如
单单改变#后的部分,浏览器只会滚动到相应位置,不会重新加载网页
pushState 与 location.hash = 的有个区别会导致问题:pushState的第三个参数url 并不会马上就加载,而是可能在后面,比如页面重载的时候执行,这是导致弹窗没有自动朗读的大问题所在吧
pushState()方法绝不会导致hashchange 事件被激活

使用focus实现

需要结合aria-live属性

showSelfalert(){ 
   this.showMask3 = true;
   this.$nextTick(() => {
        // 或者在弹窗组件mounted的时候
		document.getElementById('aria-mask-dialog').focus(); 
	});
}
弹窗内容

aria-live属性,默认值为off。变化了之后不会自己读出来。polite是系统会在用户空闲的时候朗读,assertive是立马打断
实验下来是使用polite,屏幕阅读器也会当即就读出来

限制焦点

让弹窗底下的元素无法访问,使用aria-hidden属性

// 在打开和关闭弹窗的位置
// 缺点是页面结构混乱的话会比较难处理
function switchCompAriaHidden(name, val) {
  	  let comp = document.querySelector(name);
	  comp?.setAttribute?.('aria-hidden', val);
}

// 捕获,监听focus事件
// 场景是公共的弹窗组件,希望把焦点管理包含在组件自身
document.addEventListener("focus", function(event) {
    var dialog = document.getElementById("my-dialog");
    if (dialogOpen && !dialog.contains(event.target)) {
        event.stopPropagation(); // 阻止捕获、目标、冒泡
        dialog.focus();
    }
}, true);

使用事件捕获(event capturing)侦听focus事件
事件处理程序的阶段:捕获 - 目标 - 冒泡

focus:当focusable元素获得焦点时,不支持冒泡;
focusin:和focus一样,只是此事件支持冒泡;
blur:当focusable元素失去焦点时,不支持冒泡;
focusout:和blur一样,只是此事件支持冒泡;

恢复焦点

关闭弹窗的时候,应该默认将焦点回退到弹窗显示之前相关的位置
实现:打开弹窗前记录最后一个焦点元素

let lastFocus = document.activeElement;
// 关闭弹窗时
lastFocus.focus()

特殊情况根据场景实现:
非常不希望用户再次唤起这个弹窗;
这个弹窗操作完成之后,需要用户进入到下一个流程

多个浮层/弹窗的管理

历史的h5已经实现了一部分的pushState,return popstateWatcher
在弹窗或浮层出现的时候,在浏览器记录里面push一下当前页面url。并对popstate事件addEventListener,回退时关闭弹窗/浮层
目的是为了解决用户手势操作(左滑)回退浏览器,而这种默认操作可能与用户预期不一致。比如打开弹窗的时候,用户左滑关闭弹窗,结果关闭了整个页面回退到上一个页面

问题点

因为是事件监听,多个弹窗时多个监听,回退一下会关闭多个

优化

使用数组的unshift和pop实现堆栈管理,保证每次监听的事件时最新的

let historyWatcherArr = [];

function stateWatcherStep() {
	if (historyWatcherArr && historyWatcherArr.length) {
		let listennerNow = historyWatcherArr.pop(historyWatcherArr[0]);
		window.removeEventListener('popstate', listennerNow);
	}
	historyWatcherArr.length && window.addEventListener('popstate', historyWatcherArr[0], false);
}

export default function pushHistory(callback, hashVal) {

	let historyState = window.history.state || {};

	historyState.url = location.href;
	if (hashVal) {
		historyState.hash = hashVal;
	}
	window.history.pushState(historyState, document.title, location.href + hashVal ? hashVal : '');

	let popstateWatcher = function (e) {
		popstateWatcher.clean();
		if (typeof callback === 'function') {
			callback();
			callback = null;
		}
	};

	popstateWatcher.remove = function () {
		popstateWatcher.clean();
		history.back();
	};

	popstateWatcher.clean = function () {
		window.removeEventListener('popstate', popstateWatcher);
		stateWatcherStep();
	};

	if (historyWatcherArr.length) {
		window.removeEventListener('popstate', historyWatcherArr[0]);
	}
	window.addEventListener('popstate', popstateWatcher, false);
	historyWatcherArr.unshift(popstateWatcher);
	return popstateWatcher;
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/571746.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号