alertやcomfirm、promptなどを使ってダイアログを表示すると、デザインもコントロールできない上、ブラウザの挙動も止まってしまいます。
ということで、内部モーダルウィンドウで実装するのがオススメです。
そうしたモーダルウィンドウを簡易に取り扱うための簡単なライブラリを作ったので公開します。
ちなみに、過去にも何度かモーダルウィンドウツールを作ってきましたが、今回は、moduleタイプなので、importして使うバージョンです。
ソースコード
export class Modal{
constructor(options){
this.options = options || {}
this.id = 'modal_'+ (+new Date())
this.view_bg()
this.view()
}
get window(){
return document.querySelector(`.modal_window[data-id='${this.id}']`)
}
get windows(){
return document.querySelectorAll(`.modal_window`)
}
get content(){
return this.window.querySelector('.modal_content')
}
get bg(){
return document.querySelector(`.modal_bg`)
}
make_area(){
const div = document.createElement('div')
div.className = 'modal_window'
div.setAttribute('data-active','before')
div.setAttribute('data-id' , this.id)
div.appendChild(this.make_close())
div.appendChild(this.make_title())
div.appendChild(this.make_caption())
div.appendChild(this.make_content())
div.appendChild(this.make_buttons())
return div
}
make_title(){
const div = document.createElement('div')
div.className = 'modal_title'
div.innerHTML = this.options.title || ''
return div
}
make_caption(){
const div = document.createElement('div')
div.className = 'modal_caption'
div.innerHTML = this.options.caption || ''
return div
}
make_content(){
const div = document.createElement('div')
div.className = 'modal_content'
div.insertAdjacentHTML('beforeend' , this.options.content || '')
return div
}
make_close(){
const div = document.createElement('div')
div.className = 'modal_close'
div.addEventListener('click' , this.close.bind(this))
return div
}
make_buttons(){
if(!this.options.buttons || !this.options.buttons.length){return}
const div = document.createElement('div')
div.className = 'modal_buttons'
for(const button_data of this.options.buttons){
const btn = document.createElement('button')
btn.className = 'modal_button_cancel'
btn.textContent = button_data.label || button_data.name || '--'
if(button_data.click){
btn.addEventListener('click' , button_data.click)
}
div.appendChild(btn)
}
return div
}
view(){
this.area = this.make_area()
document.body.appendChild(this.area)
setTimeout(this.view_init.bind(this) , 0)
}
view_init(){
this.area.setAttribute('data-active' , 'true')
}
view_bg(){
if(this.bg){return}
const bg = document.createElement('div')
bg.className = 'modal_bg'
document.body.appendChild(bg)
return true
}
close(){
const elms = this.windows
for(const elm of elms){
elm.parentNode.removeChild(elm)
}
if(this.bg){
this.bg.parentNode.removeChild(this.bg)
}
}
}
.modal_window,
.modal_window::before,
.modal_window::after
.modal_window *,
.modal_window *::before,
.modal_window *::after{
-webkit-box-sizing : border-box;
-moz-box-sizing : border-box;
-ms-box-sizing : border-box;
-o-box-sizing : border-box;
box-sizing : border-box;
}
.modal_window{
--time: 0.3s;
position:absolute;
left: 50%;
top : 50%;
transform:translate(-50%,-50%);
border-radius:10px;
font-size:16px;
width:300px;
padding:10px;
box-shadow: 5px 5px 10px rgba(0,0,0,0.5);
background-color:white;
transition-property:margin opacity;
transition-duration:var(--time);
}
.modal_window[data-active='before']{
margin-top:-50px;
opacity:0;
}
.modal_window[data-active='true']{
margin-top:0px;
opacity:1;
}
.modal_window > *:empty{
display:none;
}
.modal_window .modal_title{
font-size: 0.8em;
padding: 5px;
}
.modal_window .modal_caption{
font-size: 0.8em;
padding: 5px;
}
.modal_window .modal_content{
font-size: 0.8em;
padding: 5px;
margin:20px 0;
}
.modal_window .modal_buttons{
font-size: 0.8em;
padding: 5px;
display:flex;
justify-content: space-around;
gap:10px;
}
.modal_window .modal_buttons > *{
padding:5px 10px;
min-width:25%;
}
.modal_window .modal_buttons button{
cursor:pointer;
}
.modal_window input{
padding:10px;
font-size:16px;
border:1px solid #aaa;
border-radius:5px;
width:100%;
}
.modal_window .modal_close{
position:absolute;
width:20px;
height:20px;
/* border:1px solid black; */
right:5px;
top:5px;
cursor:pointer;
}
.modal_window .modal_close:hover{
opacity:0.5;
}
.modal_window .modal_close::before,
.modal_window .modal_close::after{
content: '';
position:absolute;
width:100%;
height:1px;
top:50%;
left:50%;
background-color: black;
}
.modal_window .modal_close::before{
transform:translate(-50%,-50%) rotate(45deg);
}
.modal_window .modal_close::after{
transform:translate(-50%,-50%) rotate(-45deg);
}
.modal_bg{
position:fixed;
width:100vw;
height:100vh;
top:0;
left:0;
background-color:rgba(0,0,0,0.3);
}
使い方
<!DOCTYPE html>
<html lang='ja'>
<head>
<meta charset='utrf-8'/>
<title>Modal sample</title>
<link rel='stylesheet' href='modal.css'/>
<script type='module' src='include.js'></script>
</head>
<body>
<button id='btn'>Modal view</button>
</body>
</html>
import { Modal } from './modal.js'
switch(document.readyState){
case 'complete':
window.main = new Main()
break
default:
window.addEventListener('load' , (function(){
window.main = new Main()
}))
break
}
export class Main{
constructor(){
this.set_event()
}
get btn(){
return document.getElementById('btn')
}
set_event(){
this.btn.addEventListener('click' , this.click.bind(this))
}
click(e){
this.modal = new Modal({
caption : `モーダル表示テスト`,
buttons : [
{
label : 'cancel',
click : (()=>{
alert('キャンセル')
this.modal.close()
}).bind(this),
},
{
label : 'ok',
click : (()=>{
alert('OK')
this.modal.close()
}).bind(this),
},
],
})
}
}
解説
index.htmlに、ライブラリ読み込み用のinclude.jsをセットすることで、ボタンイベントと連動して、その内部の"new Modal(...)"が実行されて、モーダル表示されます。
Modalクラスに受け渡す引数は次の通りです。
caption : モーダルウィンドウの上部メッセージ(タイトルや説明文などに使います)
buttons : 配列で複数のボタンを実装できます。(それぞれ下記の内容を書き込みます)
label : ボタンに表示する文字列
click : ボタンをクリックした時のイベント
モーダルウィンドウを閉じるために、ボタンイベントの処理後に次の命令を埋め込んでください。
# インスタンスを保持してそこの内部closeメソッドを実行するパターン
this.moddal = new Modal(...)
this.modal.close()
【注意点】
modal.jsと同時に、modal.cssもindex.htmlで読み込んでください。(自動読み込みはしません)
サンプル
ライセンス
MIT License
過去記事
[Javascript] alertやconfirmを見栄え良くデザインできる「Modal-JS」ライブラリ
[ホームページ制作] モーダルウィンドウのサンプルコード
0 件のコメント:
コメントを投稿