制作多个可访问的模态对话框 [英] Making multiple accessible modal dialogs

查看:50
本文介绍了制作多个可访问的模态对话框的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将多个可访问的模式对话框构建到我正在创建的网站中.我一直在使用在以下链接中找到的代码:https://github.com/ireade/accessible-modal-dialog.这对我的目的很有效.键盘命令完全可以访问该框.但是我需要在站点的不同点有多个对话框,每个对话框中都有不同的信息.有谁知道我可能会如何更改 JS 以使其成为可能?我试过,但我不擅长 JS,也没有运气.作为奖励:你知道我如何动画这个对话框以逐渐滚动/出现在屏幕上吗?感谢您的任何帮助!

解决方案

该库需要稍微重写以使其真正可重用.但是,您可以通过以下方式使用该库:-

  1. 向打开模态的按钮添加一个额外的类(因此我们可以单独引用每个按钮,这也可以是一个 ID)
  2. 向对话框添加一个额外的类(以便我们可以单独引用每个对话框)
  3. 创建一个新的模态并为该新模态添加事件侦听器(也稍微更改旧模态的引用).

我在下面包含了一个小提琴.在 JavaScript 中,我在进行更改的地方添加了注释(滚动到底部以查看包含在 HTML 中的 JavaScript,这是我可以将其用作小提琴的唯一方法,所有顶级 JavaScript 只是库你引用了.)

还要注意在 HTML 中我添加了一个额外的按钮来打开第二个模式并添加第二个模式.密切关注按钮和模态上的类,以及它们与我添加了注释的 JavaScript 的关系.

有任何问题都可以问.

正确的方法.

为了改进这个库,我会在按钮上添加一个 data-target="modalID" 并让它自动连接在一起.

创建一个函数(即function modalInit()),它将遵循以下步骤:

  1. 查找具有特定类的所有按钮 (.open-dialog)
  2. 查看它的data-target(模态ID)
  3. 创建模态 (new Dialog(IDofModalFromDataTarget, dialogOverlay);)
  4. 添加事件监听器.(DialogYouJustCreated.addEventListeners('buttonThatWeFoundTheDataIdOn', '.close-dialog')

可能看起来很吓人,但如果你把它分解成这些步骤,这将是一个很好的学习练习,然后你就可以做到这一点,这样你就可以在未来添加模态,而无需任何额外的代码.

如果你决定尝试这个,请随时发布任何小提琴,我会帮助你.

两个对话框的工作示例.

//忽略上面这部分,向下滚动到'This is the page HTML'功能对话(dialogEl,overlayEl){this.dialogEl = dialogEl;this.overlayEl = overlayEl;this.focusedElBeforeOpen;var focusableEls = this.dialogEl.querySelectorAll('a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([禁用]), [tabindex="0"]');this.focusableEls = Array.prototype.slice.call(focusableEls);this.firstFocusableEl = this.focusableEls[0];this.lastFocusableEl = this.focusableEls[ this.focusableEls.length - 1 ];this.close();//重启}Dialog.prototype.open = function() {var Dialog = this;this.dialogEl.removeAttribute('aria-hidden');this.overlayEl.removeAttribute('aria-hidden');this.focusedElBeforeOpen = document.activeElement;this.dialogEl.addEventListener('keydown', function(e) {Dialog._handleKeyDown(e);});this.overlayEl.addEventListener('click', function() {Dialog.close();});this.firstFocusableEl.focus();};Dialog.prototype.close = function() {this.dialogEl.setAttribute('aria-hidden', true);this.overlayEl.setAttribute('aria-hidden', true);如果(this.focusedElBeforeOpen){this.focusedElBeforeOpen.focus();}};Dialog.prototype._handleKeyDown = function(e) {var Dialog = this;var KEY_TAB = 9;var KEY_ESC = 27;函数 handleBackwardTab() {如果(document.activeElement === Dialog.firstFocusableEl){e.preventDefault();Dialog.lastFocusableEl.focus();}}函数 handleForwardTab() {如果(document.activeElement === Dialog.lastFocusableEl){e.preventDefault();Dialog.firstFocusableEl.focus();}}开关(e.keyCode){案例 KEY_TAB:如果(Dialog.focusableEls.length === 1){e.preventDefault();休息;}if ( e.shiftKey ) {handleBackwardTab();} 别的 {handleForwardTab();}休息;案例 KEY_ESC:Dialog.close();休息;默认:休息;}};Dialog.prototype.addEventListeners = function(openDialogSel, closeDialogSel) {var Dialog = this;var openDialogEls = document.querySelectorAll(openDialogSel);for ( var i = 0; i < openDialogEls.length; i++ ) {openDialogEls[i].addEventListener('click', function() {Dialog.open();});}var closeDialogEls = document.querySelectorAll(closeDialogSel);for ( var i = 0; i < closeDialogEls.length; i++ ) {closeDialogEls[i].addEventListener('click', function() {Dialog.close();});}};//********************这是HTML页面************************//var dialogOverlay = document.querySelector('.dialog-overlay');//对话框覆盖被两者使用,所以我们在这里只需要一个引用.var navDialogEl1 = document.querySelector('.dialog1');//抓取第一个对话框元素var myDialog1 = new Dialog(navDialogEl1, dialogOverlay);//从元素'navDialogEl1'创建一个新对话框.myDialog1.addEventListeners('.open-dialog1', '.close-dialog');//注意我如何更改打开的对话框类 - 我还向与此对话框相关的按钮添加了一个额外的类,具有相同的名称var navDialogEl2 = document.querySelector('.dialog2');//获取第二个对话框元素var myDialog2 = new Dialog(navDialogEl2, dialogOverlay);//为第二个对话框元素创建一个新对话框,注意我如何使用相同的背景(dialogOverlay).myDialog2.addEventListeners('.open-dialog2', '.close-dialog');//添加一个事件监听器来打开这个对话框.再次检查 HTML 我向第二个按钮open-dialog2"添加了一个额外的类.请注意,我还使用了相同的关闭对话框",因为任何带有此类的按钮都应该关闭所有对话框.

.dialog-overlay {z-索引:2;位置:固定;顶部:0;左:0;宽度:100%;高度:100%;背景颜色:RGBA(0,0,0,0.7);}.dialog {z-索引:3;背景色:#fff;填充:20px;文本对齐:居中;宽度:90%;最大宽度:400px;位置:固定;顶部:50%;左:50%;变换:翻译(-50%,-50%);}.dialog-overlay[aria-hidden="true"],.dialog[aria-hidden="true"] {显示:无;}.dialog-overlay:not([aria-hidden="true"]),.dialog:not([aria-hidden="true"]) {显示:块;}.sr-only {不透明度:0;位置:绝对;剪辑:矩形(1px 1px 1px 1px);剪辑:矩形(1px,1px,1px,1px);}

<div class="wrapper"><h1><a href="https://iread.github.io/accessible-modal-dialog/">无障碍对话框</a></h1><button type="button" aria-label="Open Navigation" class="open-dialog1">open 1</button><button type="button" aria-label="Open Navigation" class="open-dialog2">open 2</button>

</标题><div class="dialog dialog1" role="dialog" aria-labelledby="dialog-title" aria-descriptionby="dialog-description"><h1 id="dialog-title">对话框 1</h1><button type="button" aria-label="关闭导航" class="close-dialog">关闭</button>

<div class="dialog dialog2" role="dialog" aria-labelledby="dialog-title" aria-descriptionby="dialog-description"><h1 id="dialog-title">对话框 2</h1><button type="button" aria-label="关闭导航" class="close-dialog">关闭

<div class="wrapper body-wrapper"><p><a href="https://github.com/ireade/accessible-modal-dialog">查看源码</a>|<a href="=https://bitsofco.de/accessible-modal-dialog">博客帖子</a><p>Venmo 炸玉米饼ennui 连帽衫lomo 凌乱.Meh 讽刺蓝瓶布鲁克林古.后讽刺 PBR&B 蓝瓶,iPhone meh ennui 草料 Salvia normcore neutra Chicharrones gentrify.Banjo Jean 短裤自拍,在 8 位无麸质 pinterest 可持续斜挎包售罄之前尝试一下 venmo,您可能没有听说过它们.Scenester 从农场到餐桌的精酿啤酒,knausgaard 紧身裤凸版早午餐不对称.布鲁克林你可能没有听说过他们打字机法兰绒.Etsy austin venmo、knausgaard 绿汁鱿鱼屠夫康普茶字面意思是胡须牛仔短裤 VHS 手提袋.</p><p>Artisan Bushwick 快闪店,生物柴油病毒符号学陈词滥调 pinterest Fingerstache Godard lo-fi franzen 草料.吊床独角鲸伦理,kogi 在它上面放了一只鸟五花肉布什维克照相亭 +1 大师清洁 pinterest 直接贸易素食豆腐.小批量冷压古狼,滑板不对称信誉纯素腌制 pinterest freegan.男人发髻波特兰男人辫子,雷猫赃物 keffiyeh Scenester 符号学把一只鸟放在上面,钥匙塔四个 loko 胡须倾泻而出.Meh VHS 生物柴油实际上是 poutine,normcore 中性胡须独角鲸连帽衫.Synth 可持续信誉冥想健康乱七八糟.不管是后讽刺的玉米洞场景,正宗的布什维克 keffiyeh venmo kinfolk chia.</p><p>Sriracha XOXO 大师洁面lomo 蓝瓶,banh mi 时尚斧头男编织弹性主义者.Meggings pug ennui,青年布 8 位腹腔绅士化.苦味直接贸易奇亚符号学.Synth fixie mixtape,健康哥特四美元吐司乙烯基 3 狼月亮 VHS schlitz.喝醋凸版 VHS poutine,venmo cronut 酿酒厂工匠.每天随身携带精酿啤酒屠夫DIY.Normcore affogato chillwave、thundercats banh mi 指尖键盘弹出四个 loko 4 美元吐司.</p>

<div class="dialog-overlay" tabindex="-1"></div><!--JavaScript 从这里移到 JavaScript 部分的底部-->

I'm trying to build multiple accessible modal dialog boxes into a website I'm creating. I've been using the code found at the following link: https://github.com/ireade/accessible-modal-dialog. This works well for my purposes. The box is fully accessible to keyboard commands. But I need to have multiple dialog boxes at different points on the site, with different information in each box. Does anyone know how I might go about altering the JS to make this possible? I've tried, but I'm not great with JS and haven't had any luck. And as a bonus: do you know how I might animate this dialog to scroll/appear gradually on the screen? Thank you for any and all help!

解决方案

The library would need a slight rewrite to make it truly reusable. However you can use the library as it is by:-

  1. adding an extra class to the button that opens the modal (so we can reference each button individually, this could also be an ID)
  2. adding an extra class to the dialog (so we can reference each dialog seperately)
  3. creating a new modal and adding event listeners for that new modal (also change the references slightly for the old modal).

I have included a fiddle below. In the JavaScript I have added comments where I have made changes (scroll to the bottom to see the JavaScript that was included within the HTML, it was the only way I could make this work as a fiddle, all the top JavaScript is just the library you referenced.).

Also notice in the HTML I added an extra button to open the second modal and add a second modal. Pay close attention to the classes on the buttons and the modals and how they relate to the JavaScript I have added comments to.

Any questions just ask.

The proper way.

To improve this library I would add a data-target="modalID" to the buttons and have this automatically wire things together.

Create a function (i.e. function modalInit()) that would follow the following steps:

  1. look for all buttons with a certain class (.open-dialog)
  2. look at its data-target (ID of the modal)
  3. create the modal (new Dialog(IDofModalFromDataTarget, dialogOverlay);)
  4. add the event listeners. (DialogYouJustCreated.addEventListeners('buttonThatWeFoundTheDataIdOn', '.close-dialog')

Might look scary but if you break it down into those steps it would be a great learning exercise and you would then make it so that you could add modals without any extra code in the future.

If you do decide to try this feel free to post any fiddles and I will help you.

Working Example for Two Dialogs.

//Ignore this top part, scroll down to 'This is the page HTML' 

function Dialog(dialogEl, overlayEl) {

	this.dialogEl = dialogEl;
	this.overlayEl = overlayEl;
	this.focusedElBeforeOpen;

	var focusableEls = this.dialogEl.querySelectorAll('a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), [tabindex="0"]');
	this.focusableEls = Array.prototype.slice.call(focusableEls);

	this.firstFocusableEl = this.focusableEls[0];
	this.lastFocusableEl = this.focusableEls[ this.focusableEls.length - 1 ];

	this.close(); // Reset
}


Dialog.prototype.open = function() {

	var Dialog = this;

	this.dialogEl.removeAttribute('aria-hidden');
	this.overlayEl.removeAttribute('aria-hidden');

	this.focusedElBeforeOpen = document.activeElement;

	this.dialogEl.addEventListener('keydown', function(e) {
		Dialog._handleKeyDown(e);
	});

	this.overlayEl.addEventListener('click', function() {
		Dialog.close();
	});

	this.firstFocusableEl.focus();
};

Dialog.prototype.close = function() {

	this.dialogEl.setAttribute('aria-hidden', true);
	this.overlayEl.setAttribute('aria-hidden', true);

	if ( this.focusedElBeforeOpen ) {
		this.focusedElBeforeOpen.focus();
	}
};


Dialog.prototype._handleKeyDown = function(e) {

	var Dialog = this;
	var KEY_TAB = 9;
	var KEY_ESC = 27;

	function handleBackwardTab() {
		if ( document.activeElement === Dialog.firstFocusableEl ) {
			e.preventDefault();
			Dialog.lastFocusableEl.focus();
		}
	}
	function handleForwardTab() {
		if ( document.activeElement === Dialog.lastFocusableEl ) {
			e.preventDefault();
			Dialog.firstFocusableEl.focus();
		}
	}

	switch(e.keyCode) {
	case KEY_TAB:
		if ( Dialog.focusableEls.length === 1 ) {
			e.preventDefault();
			break;
		} 
		if ( e.shiftKey ) {
			handleBackwardTab();
		} else {
			handleForwardTab();
		}
		break;
	case KEY_ESC:
		Dialog.close();
		break;
	default:
		break;
	}


};


Dialog.prototype.addEventListeners = function(openDialogSel, closeDialogSel) {

	var Dialog = this;

	var openDialogEls = document.querySelectorAll(openDialogSel);
	for ( var i = 0; i < openDialogEls.length; i++ ) {
		openDialogEls[i].addEventListener('click', function() { 
			Dialog.open();
		});
	}

	var closeDialogEls = document.querySelectorAll(closeDialogSel);
	for ( var i = 0; i < closeDialogEls.length; i++ ) {
		closeDialogEls[i].addEventListener('click', function() {
			Dialog.close();
		});
	}

};


//*****************This is the page HTML*********************//

var dialogOverlay = document.querySelector('.dialog-overlay'); //dialog overlay is used by both so we only need one reference to it here.

var navDialogEl1 = document.querySelector('.dialog1');//grab the first dialog element
		
		
		var myDialog1 = new Dialog(navDialogEl1, dialogOverlay); //create a new dialog from the element 'navDialogEl1'.
		myDialog1.addEventListeners('.open-dialog1', '.close-dialog'); //notice how I changed the open dialog class - I also added an extra class to the button that is related to this dialog with the same name
    
    
    var navDialogEl2 = document.querySelector('.dialog2'); //grab the second dialog element
		
		var myDialog2 = new Dialog(navDialogEl2, dialogOverlay); //create a new dialog for the second dialog element, notice how I use the same background (dialogOverlay).
		myDialog2.addEventListeners('.open-dialog2', '.close-dialog'); //add an event listener to open this dialog. Yet again check the HTML I added an extra class to the second button 'open-dialog2'. Notice how I also used the same 'close-dialog' as any button with this calss should close all dialogs anyway.

.dialog-overlay {
	z-index: 2;
	position: fixed;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
	background-color: rgba(0,0,0,0.7);
}

.dialog {
	z-index: 3;
	background-color: #fff;
	padding: 20px;
	text-align: center;
	width: 90%;
	max-width: 400px;
	position: fixed;
	top: 50%;
	left: 50%;
	transform: translate(-50%,-50%);
}

.dialog-overlay[aria-hidden="true"],
.dialog[aria-hidden="true"] {
	display: none;
}

.dialog-overlay:not([aria-hidden="true"]),
.dialog:not([aria-hidden="true"]) {
	display: block;
}

.sr-only {
	opacity: 0;
	position: absolute;
	clip: rect(1px 1px 1px 1px);
	clip: rect(1px, 1px, 1px, 1px);
}

<header>
		<div class="wrapper">
			<h1><a href="https://ireade.github.io/accessible-modal-dialog/">Accessible Dialog</a></h1>
			<button type="button" aria-label="Open Navigation" class="open-dialog1">open 1</button>
      <button type="button" aria-label="Open Navigation" class="open-dialog2">open 2</button>
		</div>
	</header>
  
  
	<div class="dialog dialog1" role="dialog" aria-labelledby="dialog-title" aria-describedby="dialog-description">
		<h1 id="dialog-title">Dialog 1</h1>
		
		<button type="button" aria-label="Close Navigation" class="close-dialog"> Close </button>
	</div>
  
  <div class="dialog dialog2" role="dialog" aria-labelledby="dialog-title" aria-describedby="dialog-description">
		<h1 id="dialog-title">Dialog 2</h1>
		
		<button type="button" aria-label="Close Navigation" class="close-dialog"> Close</button>
	</div>
  
	
	<div class="wrapper body-wrapper">

		<p><a href="https://github.com/ireade/accessible-modal-dialog">View Source</a> | <a href="=https://bitsofco.de/accessible-modal-dialog">Blog Post</a> 

		<p>Venmo tacos ennui hoodie lomo tousled. Meh irony blue bottle brooklyn paleo. Post-ironic PBR&B blue bottle, iPhone meh ennui forage salvia normcore neutra chicharrones gentrify. Banjo jean shorts selfies, try-hard venmo before they sold out 8-bit gluten-free pinterest sustainable messenger bag you probably haven't heard of them poutine. Scenester farm-to-table craft beer, knausgaard leggings letterpress brunch asymmetrical. Brooklyn you probably haven't heard of them typewriter flannel. Etsy austin venmo, knausgaard green juice squid butcher kombucha literally beard jean shorts VHS tote bag.</p>

		<p>Artisan bushwick pop-up, biodiesel viral semiotics cliche pinterest fingerstache godard lo-fi franzen forage. Hammock narwhal ethical, kogi put a bird on it pork belly bushwick photo booth +1 master cleanse pinterest direct trade vegan tofu. Small batch cold-pressed paleo wolf, skateboard asymmetrical cred vegan pickled pinterest freegan. Man bun portland man braid, thundercats swag keffiyeh scenester semiotics put a bird on it keytar four loko beard pour-over. Meh VHS biodiesel actually poutine, normcore neutra beard narwhal hoodie. Synth sustainable cred meditation health goth tousled. Post-ironic cornhole scenester whatever, authentic bushwick keffiyeh venmo kinfolk chia.</p>

		<p>Sriracha XOXO master cleanse lomo blue bottle, banh mi fashion axe man braid flexitarian. Meggings pug ennui, chambray 8-bit celiac gentrify. Bitters direct trade chia semiotics. Synth fixie mixtape, health goth four dollar toast vinyl 3 wolf moon VHS schlitz. Drinking vinegar letterpress VHS poutine, venmo cronut distillery artisan. Everyday carry craft beer butcher DIY. Normcore affogato chillwave, thundercats banh mi fingerstache keytar pop-up four loko four dollar toast.</p>

	</div>
	
	

	<div class="dialog-overlay" tabindex="-1"></div>
  
  <!--JavaScript moved from here to the bottom of the JavaScript section-->

这篇关于制作多个可访问的模态对话框的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
前端开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆