Создание нескольких доступных модальных диалогов - PullRequest
0 голосов
/ 14 апреля 2020

Я пытаюсь встроить несколько доступных модальных диалоговых окон в сайт, который я создаю. Я использовал код, найденный по следующей ссылке: https://github.com/ireade/accessible-modal-dialog. Это хорошо работает для моих целей. Поле полностью доступно для клавиатурных команд. Но мне нужно иметь несколько диалоговых окон в разных точках сайта, с разной информацией в каждом окне. Кто-нибудь знает, как я могу go изменить JS, чтобы сделать это возможным? Я пытался, но я не очень хорошо разбираюсь с JS и мне не повезло. И в качестве бонуса: знаете ли вы, как я мог бы оживить этот диалог, чтобы прокручиваться / появляться постепенно на экране? Спасибо за любую помощь!

1 Ответ

0 голосов
/ 15 апреля 2020

Библиотеке нужно будет немного переписать, чтобы сделать ее по-настоящему пригодной для повторного использования. Однако вы можете использовать библиотеку в том виде, как она есть: -

  1. добавив дополнительный класс к кнопке, открывающей модальное окно (чтобы мы могли ссылаться на каждую кнопку по отдельности, это также может быть идентификатор)
  2. добавление дополнительного класса в диалог (чтобы мы могли ссылаться на каждый диалог отдельно)
  3. создание нового модала и добавление прослушивателей событий для этого нового модала (также немного измените ссылки для старого модала).

Я включил скрипку ниже. В JavaScript я добавил комментарии, где я внес изменения (прокрутите вниз, чтобы увидеть JavaScript, который был включен в HTML, это был единственный способ, которым я мог сделать эту работу как скрипку, все top JavaScript - это просто библиотека, на которую вы ссылаетесь.).

Также обратите внимание, в HTML я добавил дополнительную кнопку, чтобы открыть второй модал и добавить второй модал. Обратите пристальное внимание на классы кнопок и модалов и их отношение к JavaScript Я добавил комментарии.

Любые вопросы просто задайте.

Правильный путь.

Чтобы улучшить эту библиотеку, я бы добавил data-target="modalID" к кнопкам, и это автоматически связало бы все вместе.

Создание функции (то есть function modalInit()), которая бы выполняла следующие шаги:

  1. искать все кнопки с определенным классом (.open-dialog)
  2. смотреть на его data-target (идентификатор модального)
  3. создавать модальное (new Dialog(IDofModalFromDataTarget, dialogOverlay);)
  4. добавить прослушиватели событий. (DialogYouJustCreated.addEventListeners('buttonThatWeFoundTheDataIdOn', '.close-dialog')

Может показаться страшным, но если разбить его на эти этапы, это будет отличным учебным упражнением, а затем вы сделаете его таким, чтобы вы могли добавлять модалы без дополнительного кода в будущее.

Если вы решите попробовать это, не стесняйтесь отправлять любые скрипки, и я помогу вам.

Рабочий пример для двух диалогов.

//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-->
...