初心者向け。JavaScriptで自作の自動スライドショーの実装方法

4065 回閲覧されました
みなさんこんにちは、WEB制作のエンジニアのjonioです。
スライドショーをJavaScriptで作る方法を解説します。
理解した方がカスタムも効くので是非理解してください。
コードはそんなに難しくないと思います。
それでは説明します。
目次 [隠す]
デモと実装内容
デモは↓です。
実装内容ですが「次の画像」をクリックすると次の画像に切り替わっていき最後の画像で「次の画像」をクリックすると最初の画像になります。
「前の画像」をクリックすると表示されている画像の1つ前の画像になり一番最初の画像の時に「前の画像」をクリック流すると最後の画像になります。
「自動再生する」をクリックすると自動再生になって「自動再生する」の表示が「停止する」に変わり「停止する」をクリックすると「自動再生する」に表示が変わります。
それではコードの解説ですがHTMLとCSSは簡単なので解説はしません。
コードの解説
HTMLは↓にします。
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"/> | |
<link rel="stylesheet" href="css/style.css"> | |
<title>スライドショー</title> | |
</head> | |
<body> | |
<div id="slideshow"> | |
<span class="arrow leftArrow">前の画像</span> | |
<div id="photo"> | |
<img id="main"> | |
</div> | |
<span class="arrow rightArrow">次の画像</span> | |
</div> | |
<script type="text/javascript" src="js/common.js"></script> | |
</body> | |
</html> |
CSSは↓にします。
/* ここからreset.css */ | |
html, body, div, span, object, iframe, | |
h1, h2, h3, h4, h5, h6, p, blockquote, pre, | |
abbr, address, cite, code, | |
del, dfn, em, img, ins, kbd, q, samp, | |
small, strong, sub, sup, var, | |
b, i, | |
dl, dt, dd, ol, ul, li, | |
fieldset, form, label, legend, | |
table, caption, tbody, tfoot, thead, tr, th, td, | |
article, aside, canvas, details, figcaption, figure, | |
footer, header, hgroup, menu, nav, section, summary, | |
time, mark, audio, video { | |
margin:0; | |
padding:0; | |
border:0; | |
outline:0; | |
font-size:100%; | |
vertical-align:baseline; | |
background:transparent; | |
} | |
body { | |
line-height:1; | |
} | |
article,aside,details,figcaption,figure, | |
footer,header,hgroup,menu,nav,section { | |
display:block; | |
} | |
nav ul { | |
list-style:none; | |
} | |
blockquote, q { | |
quotes:none; | |
} | |
blockquote:before, blockquote:after, | |
q:before, q:after { | |
content:''; | |
content:none; | |
} | |
a { | |
margin:0; | |
padding:0; | |
font-size:100%; | |
vertical-align:baseline; | |
background:transparent; | |
text-decoration:none; | |
} | |
del { | |
text-decoration: line-through; | |
} | |
abbr[title], dfn[title] { | |
border-bottom:1px dotted; | |
cursor:help; | |
} | |
hr { | |
display:block; | |
height:1px; | |
border:0; | |
border-top:1px solid #cccccc; | |
margin:1em 0; | |
padding:0; | |
} | |
input, select { | |
vertical-align:middle; | |
} | |
p,.nav{ | |
margin:0; | |
} | |
/* ここまでreset.css */ | |
.slideshow{ | |
position:relative; | |
} | |
.leftArrow{ | |
position:absolute; | |
top:50%; | |
left:50px; | |
transform:translateY(-50%); | |
color:red; | |
} | |
.rightArrow{ | |
position:absolute; | |
top:50%; | |
right:50px; | |
transform:translateY(-50%); | |
color:red; | |
} | |
img{ | |
height: 500px; | |
display: block; | |
margin-top: 50px; | |
margin-left:auto; | |
margin-right:auto; | |
} | |
.addClass{ | |
text-align: center; | |
margin-top: 20px; | |
} | |
.addClass2{ | |
width:200px; | |
display: block; | |
border:none; | |
margin-top: 20px; | |
margin-left:auto; | |
margin-right:auto; | |
} |
CSSですが今回の内容はサイト作成で実装するのを想定していますがreset.cssが必ず必要なので私が使うreset.css記載しています。
私と同じ内容でなくてもいいので必ず記載してください。
これでとりあえず↓と表示されます。
それではJavaScriptの解説です。
まずは使う画像の設定と「次の画像」・「前の画像」のボタンの設定です。
使う画像の設定と「次の画像」・「前の画像」のボタンの設定
JavaScriptのコードを↓にします。
const list = [ | |
"../images/img1.png", | |
"../images/img2.png", | |
"../images/img3.jpeg", | |
]; | |
const img = document.getElementById('main'); | |
const [leftArrow,rightArrow] = document.getElementsByTagName('span'); |
1行目〜5行目で使う画像を設定しています。
7行目でHTMLのどこにある画像が切り替わるのかの指定をしています。
9行目で画像の切り替えボタンの「前の画像」・「次の画像」の切り替えボタンのセレクタの指定をしています。
次は最初に表示する画像の設定です。
最初に表示する画像の設定
コードを↓にします。
const list = [ | |
"../images/img1.png", | |
"../images/img2.png", | |
"../images/img3.jpeg", | |
]; | |
const img = document.getElementById('main'); | |
const [leftArrow,rightArrow] = document.getElementsByTagName('span'); | |
const div = document.getElementById('photo'); | |
//ここから追加 | |
let imgN = 0; | |
document.addEventListener('DOMContentLoaded',function(){ | |
img.src = list[imgN]; | |
}); | |
//ここまで追加 | |
これで↓の表示になりますがJavaScriptで画像を読み込む時は仮想環境かサーバーに上げた時しかできないのですがターミナルで「cd プロジェクト名」として「php -S localhost:8000」で仮想環境を立ち上げれば画像の表示ができます。
17行目はHTMLの読み込みが終わった後にJavaScriptの処理が始まるという意味で19行目で画像の表示をしています。
次は画像の下に現在何枚目の画像が表示されているかを表示します。
画像の下に現在何枚目の画像が表示されているかを表示します。
コードを↓にします。
const list = [ | |
"../images/img1.png", | |
"../images/img2.png", | |
"../images/img3.jpeg", | |
]; | |
const img = document.getElementById('main'); | |
const [leftArrow,rightArrow] = document.getElementsByTagName('span'); | |
const div = document.getElementById('photo'); | |
let imgN = 0; | |
document.addEventListener('DOMContentLoaded',function(){ | |
img.src = list[imgN]; | |
//ここから追加 | |
const p = document.createElement('p'); | |
p.classList.add('addClass'); | |
div.insertBefore(p,img.nextElementSibling); | |
p.textContent = `${imgN + 1} / ${list.length}`; | |
//ここまで追加 | |
}); |
これで↓の表示になります。
「1/3」は「全ての画像の枚数が3枚でその中の1枚目」という意味です。
HTMLでは画像の下に「1/3」を表示するタグがないのですが21行目〜24行目でpタグの作成をしてどこに表示するかを指定しています。
24行目の「` `」はテンプレートリテラルですがJavaScriptの書き方の中に「/」を混ぜるために使っています。・
次は「前の画像」・「次の画像」をクリックした時に画像が切り替わるようにします。
「前の画像」・「次の画像」をクリックした時の画像の切り替え
コードを↓にします。
const list = [ | |
"../images/img1.png", | |
"../images/img2.png", | |
"../images/img3.jpeg", | |
]; | |
const img = document.getElementById('main'); | |
const [leftArrow,rightArrow] = document.getElementsByTagName('span'); | |
const div = document.getElementById('photo'); | |
let imgN = 0; | |
document.addEventListener('DOMContentLoaded',function(){ | |
img.src = list[imgN]; | |
const p = document.createElement('p'); | |
p.classList.add('addClass'); | |
div.insertBefore(p,img.nextElementSibling); | |
p.textContent = `${imgN + 1} / ${list.length}`; | |
//ここから追加 | |
rightArrow.addEventListener('click',function(){ | |
imgN ++; | |
img.src = list[imgN]; | |
p.textContent = `${imgN + 1} / ${list.length}`; | |
}); | |
leftArrow.addEventListener('click',function(){ | |
imgN --; | |
img.src = list[imgN]; | |
p.textContent = `${imgN + 1} / ${list.length}`; | |
}); | |
//ここまで追加 | |
}); |
これで「次の画像」・「前の画像」をクリックすると画像が切り替わりますが画像は全部で3枚しかないため「次の画像」をクリックして4枚目の画像を見ようとしたり「前の画像」をクリックして1枚目より前の画像を見ようとすると画像がないため表示されません。
4枚目の画像になる時は最初の画像に戻って1枚目の画像の前の画像になる時は3枚目の画像が表示されるようにするためにコードを↓にします。
const list = [ | |
"../images/img1.png", | |
"../images/img2.png", | |
"../images/img3.jpeg", | |
]; | |
const img = document.getElementById('main'); | |
const [leftArrow,rightArrow] = document.getElementsByTagName('span'); | |
const div = document.getElementById('photo'); | |
let imgN = 0; | |
document.addEventListener('DOMContentLoaded',function(){ | |
img.src = list[imgN]; | |
const p = document.createElement('p'); | |
p.classList.add('addClass'); | |
div.insertBefore(p,img.nextElementSibling); | |
p.textContent = `${imgN + 1} / ${list.length}`; | |
rightArrow.addEventListener('click',function(){ | |
imgN ++; | |
//ここから追加 | |
if(imgN >= list.length){ | |
imgN = 0; | |
} | |
//ここまで追加 | |
img.src = list[imgN]; | |
p.textContent = `${imgN + 1} / ${list.length}`; | |
}); | |
leftArrow.addEventListener('click',function(){ | |
imgN --; | |
//ここから追加 | |
if(imgN < 0){ | |
imgN = list.length - 1; | |
} | |
//ここまで追加 | |
img.src = list[imgN]; | |
p.textContent = `${imgN + 1} / ${list.length}`; | |
}); | |
}); |
これで画像が切り替わるのは完成しましたが次はコードを少し見やすくします。
関数化
↓のコードが3回登場しています。
img.src = list[imgN]; | |
p.textContent = `${imgN + 1} / ${list.length}`; |
まとめて1つの関数にした方が可読性が良くなるのと修正がしやすくなるので関数にまとめるためにコードを↓にします。
const list = [ | |
"../images/img1.png", | |
"../images/img2.png", | |
"../images/img3.jpeg", | |
]; | |
const img = document.getElementById('main'); | |
const [leftArrow,rightArrow] = document.getElementsByTagName('span'); | |
const div = document.getElementById('photo'); | |
let imgN = 0; | |
document.addEventListener('DOMContentLoaded',function(){ | |
//ここから追加 | |
function setImage(){ | |
img.src = list[imgN]; | |
p.textContent = `${imgN + 1} / ${list.length}`; | |
} | |
//ここまで追加 | |
const p = document.createElement('p'); | |
p.classList.add('addClass'); | |
div.insertBefore(p,img.nextElementSibling); | |
setImage(); //この行を修正 | |
rightArrow.addEventListener('click',function(){ | |
imgN ++; | |
if(imgN >= list.length){ | |
imgN = 0; | |
} | |
setImage(); //この行を修正 | |
}); | |
leftArrow.addEventListener('click',function(){ | |
imgN --; | |
if(imgN < 0){ | |
imgN = list.length - 1; | |
} | |
setImage(); //この行を修正 | |
}); | |
}); |
次はスライドショーの自動再生です。
スライドショーの自動再生
コードを↓にします。
const list = [ | |
"../images/img1.png", | |
"../images/img2.png", | |
"../images/img3.jpeg", | |
]; | |
const img = document.getElementById('main'); | |
const [leftArrow,rightArrow] = document.getElementsByTagName('span'); | |
const div = document.getElementById('photo'); | |
let imgN = 0; | |
document.addEventListener('DOMContentLoaded',function(){ | |
function setImage(){ | |
img.src = list[imgN]; | |
p.textContent = `${imgN + 1} / ${list.length}`; | |
} | |
const p = document.createElement('p'); | |
p.classList.add('addClass'); | |
div.insertBefore(p,img.nextElementSibling); | |
setImage(); | |
rightArrow.addEventListener('click',function(){ | |
imgN ++; | |
if(imgN >= list.length){ | |
imgN = 0; | |
} | |
setImage(); | |
}); | |
leftArrow.addEventListener('click',function(){ | |
imgN --; | |
if(imgN < 0){ | |
imgN = list.length - 1; | |
} | |
setImage(); | |
}); | |
//ここから追加 | |
const button = document.createElement('button'); | |
button.textContent = '自動再生する'; | |
button.classList.add('addClass2'); | |
div.appendChild(button); | |
button.addEventListener('click',function(){ | |
setInterval(function(){ | |
imgN ++; | |
if(imgN >= list.length){ | |
imgN = 0; | |
} | |
setImage(); | |
},1000); | |
}); | |
//ここまで追加 | |
}); |
これで表示が↓になります。
「自動再生する」と書いてあるボタンをクリックすると自動再生が動きます。
53行目〜62行目の記述で一定間隔で画像が切り替わりますがこの実装には欠点があります。
誤作動の修正
それは「自動再生する」を連打すると画像の切り替わりのスピードが変わって変な動きになります。
原因は一定間隔で動かしている時に同じ動作をさせるからで「自動再生する」を一度押したら同じ事ができないようにすれば大丈夫です。
そこでコードを↓にします。
const list = [ | |
"../images/img1.png", | |
"../images/img2.png", | |
"../images/img3.jpeg", | |
]; | |
const img = document.getElementById('main'); | |
const [leftArrow,rightArrow] = document.getElementsByTagName('span'); | |
const div = document.getElementById('photo'); | |
let imgN = 0; | |
document.addEventListener('DOMContentLoaded',function(){ | |
function setImage(){ | |
img.src = list[imgN]; | |
p.textContent = `${imgN + 1} / ${list.length}`; | |
} | |
const p = document.createElement('p'); | |
p.classList.add('addClass'); | |
div.insertBefore(p,img.nextElementSibling); | |
setImage(); | |
rightArrow.addEventListener('click',function(){ | |
imgN ++; | |
if(imgN >= list.length){ | |
imgN = 0; | |
} | |
setImage(); | |
}); | |
leftArrow.addEventListener('click',function(){ | |
imgN --; | |
if(imgN < 0){ | |
imgN = list.length - 1; | |
} | |
setImage(); | |
}); | |
const button = document.createElement('button'); | |
button.textContent = '自動再生する'; | |
button.classList.add('addClass2'); | |
div.appendChild(button); | |
let autoplay = false; //この行を追加 | |
button.addEventListener('click',function(){ | |
//ここから修正 | |
if(autoplay == false){ | |
button.textContent = '停止する'; | |
autoplay = setInterval(function(){ | |
imgN ++; | |
if(imgN >= list.length){ | |
imgN = 0; | |
} | |
setImage(); | |
},1000); | |
}else{ | |
clearInterval(autoplay); | |
autoplay = false; | |
button.textContent = '自動再生する'; | |
} | |
}); | |
//ここまで修正 | |
}); |
まず49行目でフラグを建てます。
そしてフラグが建っている時に55行目〜66行目で自動再生が動くようにして自動再生を止めることができるように「自動再生する」の文字を「停止する」に変えます。
68行目〜70行目は自動再生を止める時の記述ですが68行目で49行目のフラグ(falseのこと)を取ることで自動再生を止めます。
そしてこの時に69行目でfalseを付けることで「自動再生する」をクリックした時に自動再生がまた動くようにします。
これで完成です。
最後に完成形のJavaScriptのコードを掲載します。
const list = [ | |
"../images/img1.png", | |
"../images/img2.png", | |
"../images/img3.jpeg", | |
]; | |
const img = document.getElementById('main'); | |
const [leftArrow,rightArrow] = document.getElementsByTagName('span'); | |
const div = document.getElementById('photo'); | |
let imgN = 0; | |
document.addEventListener('DOMContentLoaded',function(){ | |
function setImage(){ | |
img.src = list[imgN]; | |
p.textContent = `${imgN + 1} / ${list.length}`; | |
} | |
const p = document.createElement('p'); | |
p.classList.add('addClass'); | |
div.insertBefore(p,img.nextElementSibling); | |
setImage(); | |
rightArrow.addEventListener('click',function(){ | |
imgN ++; | |
if(imgN >= list.length){ | |
imgN = 0; | |
} | |
setImage(); | |
}); | |
leftArrow.addEventListener('click',function(){ | |
imgN --; | |
if(imgN < 0){ | |
imgN = list.length - 1; | |
} | |
setImage(); | |
}); | |
const button = document.createElement('button'); | |
button.textContent = '自動再生する'; | |
button.classList.add('addClass2'); | |
div.appendChild(button); | |
let autoplay = false; | |
button.addEventListener('click',function(){ | |
if(autoplay == false){ | |
button.textContent = '停止する'; | |
autoplay = setInterval(function(){ | |
imgN ++; | |
if(imgN >= list.length){ | |
imgN = 0; | |
} | |
setImage(); | |
},1000); | |
}else{ | |
clearInterval(autoplay); | |
autoplay = false; | |
button.textContent = '自動再生する'; | |
} | |
}); | |
}); |