スライダー表示にjQueryプラグインのFlexSliderを使っているのですが、カスタマイズしたのでメモ。
作業した内容は次の通りです!
- [スライド数/総スライド数]を表示させる
- 画面が全て読み込まれるまでローディングアイコンを表示させる
- jsonファイルで画像データを読み込む(←今ここ)
完成したスライダーを確認する(デモ)
こちらが完成したスライダーです。ローディングアイコンを表示させるため、画像の読み込みを故意に遅らせて表示してます。
動作デモ
実際の動作はこちらでご確認ください!(別ウィンドウが開きます)
jsonファイルを確認する
スライダーの画像名と画像の説明(alt)をjsonにまとめたのがこちらです。
このデータを取り出して、HTMLに組み込んでいきます。
slider.json
[
{
"img": "slider_01.jpg",
"alt": "サムネイル01"
},
{
"img": "slider_02.jpg",
"alt": "サムネイル02"
},
{
"img": "slider_03.jpg",
"alt": "サムネイル03"
},
{
"img": "slider_04.jpg",
"alt": "サムネイル04"
},
{
"img": "slider_05.jpg",
"alt": "サムネイル05"
},
{
"img": "slider_06.jpg",
"alt": "サムネイル06"
},
{
"img": "slider_07.jpg",
"alt": "サムネイル07"
},
{
"img": "slider_08.jpg",
"alt": "サムネイル08"
},
{
"img": "slider_09.jpg",
"alt": "サムネイル09"
}
]
ソースコードを確認(全体)
HTML
スライダー部分は<li>で読み込みますが、この部分はjsonデータから要素を生成する為、空にしておきます。
HTML
<div class="flexslider">
<ul class="slides">
</ul>
</div>
javascript
FlexSliderのプラグインは、スライダーの要素を生成してから実行する必要があります。
その為、一旦関数createSlider()に処理をまとめておきます。後ほどPromiseで実行する順番を制御します。
//flexsliderプラグイン
function createSlider() {
$('.flexslider').flexslider({
animation: "slide",
});
}
//jsonデータ取得
async function fetchSliders() {
const response = await fetch('slider.json');
if(response.ok == true) {
const slideData = await response.json();
if(!slideData.length) {
throw new Error('No slide data found');
}
return slideData;
} else {
throw new Error('The data could not be read');
}
}
// 非同期で実行
async function init() {
try {
//slideデータ取得(json)
const slides = await fetchSliders();
//DOM作成
for(const slide of slides) {
const slideEml = document.createElement('li');
const img = document.createElement('img');
img.src = './images/' + slide.img;
img.alt = slide.alt;
slideEml.appendChild(img);
slideWrap.appendChild(slideEml);
}
// 非同期で実行
const sliderElm = createSlider();
} catch(e) {
console.error(e);
}
}
init();
jsonデータを取得する
fetch()メソッドで、取得したいjsonファイルのURLを指定します。
なお、読み込むファイル「slider.json」はjavascriptのファイルと同階層にあります。
fetch('slider.json').then(function(response) {
return response.json();
}).then(function(json) {
console.log(json);
})
上記のコードをコンソールで確認すると、slider.jsonの値が取得できています。
配列の中にオブジェクトが格納されているようです。
1番目のオブジェクトのプロパティ「img」の値を取り出すにはこのように記述します。
console.log(json[0].img); //slider_01.jpg
全ての値を取り出すにはfor文を使います。
for(const slide of json) {
console.log(`img: ${slide.img}、alt: ${slide.alt}`)
}
こちらの値を使ってHTML要素を作成します。
Fetch APIとは
そもそもfetch()メソッドとはなんぞや?ですが、Fetch APIの機能らしいです。
さらにFetch APIとはなんぞや?ですが、外部のデータをやり取りする為の機能がまとまったモノらしいです。平たくいうと非同期でサーバーのデータを取得できる機能です。
fetch(‘slider.json’)の戻り値をコンソールで確認すると、Promiseオブジェクトであることが分かります。戻ってきた値を確認すると、Stateがfulfilled(条件が満たされている)、OKの項目が「true」、statusが「200(正しく表示)」です。データがうまく取れている感じがします!
Promiseオブジェクトとは
fetch()メソッドの戻り値はPromiseオブジェクトですが、このオブジェクトは非同期処理の結果を成功(resolve)か失敗(reject)で返します。
構文はこちらです。変数exampleの値が「true」なので、コンソールログにはsuccessと終了が表示されます。
new Promise(function(resolve,reject) {
const example = true;
if(example) {
resolve('success');
} else {
reject('failure');
}
}).then(function(data) {
console.log(data); //success
}).catch(function(data) {
console.log(data); //failure
}).finally(function() {
console.log('終了');
});
結果が成功ならthen()メソッドで非同期処理を順次実行し、失敗ならcatch()メソッドに処理が移動します。その際、Promiseの戻り値を引数として渡すことができます。
finally()メソッドは、非同期処理の結果に関わらず実行されます。
今回は、jsonの値を引数として次の処理に渡します。
jsonファイルの読み込みが完了してからthen()メソッド(次の処理)が実行されます。
省略して記述する AwaitとAsync
awaitとasyncを使うと、記述を省略できます。
先ほど、then()メソッドで次の処理に引数を渡していましたが、awaitを使うと戻り値を変数に格納できます。
先程のコードをawaitとasyncで書き直しました。
awaitはasyncで宣言された関数の中でしか使えません。
(async function() {
const response = await fetch('slider.json');
const json = await response.json();
for(const slide of json) {
console.log(`img: ${slide.img}、alt: ${slide.alt}`)
}
})();
先程のコードより、スッキリと記述できました。
例外処理とエラー
外部からデータを取得する際、100%成功する訳ではないです。
例えば、ファイル自体が存在しなければエラー(404)になりますし、jsonの記述が間違っていてもエラーになります。
エラーが発生した場合、プログラムが止まってしまうかもしれません。
その為、エラーも含め予期しない例外が発生した時の処理を記述しておきます。
構文は次の通りです。
try {
{例外が想定される処理}
//エラーを故意に発生させる
throw new Error();
} catch(e) {
{例外が発生した時の処理}
console.error(e);
} finally {
{例外発生に関わらず実行される処理}
console.log('finalluy')
}
try{}に例外が想定される処理を記述します。もし例外が発生したらcatch()に処理が移動します。
throwは故意にエラーを発生させます。この場合でもcatchに処理が移動します。
finallyは最終的に実行される処理を記述します。
Promiseオブジェクトにも似たような機能がありますが、今回のエラー処理はこの構文を使用します。
jsonファイルが読み込まれなかった時(エラー)
上記の内容を踏まえて、次のような処理を記述します。
- jsonファイルの読み込みが完了したら
- jsonファイルの中身をとりだし、HTML要素を生成
- FlexSliderプラグインを実行
もし、jsonがうまく読み込めなかったらエラーを発生させ、catch()に処理を移動させます。
catch()ではエラーの内容をコンソールログに表示します。
jsonファイルを読み込む記述は関数fetchSliders()にまとめました。
例外が発生したらthrowでエラーを発生させて、catchに処理を移動しています。
//jsonデータ取得
async function fetchSliders() {
const response = await fetch('slider.json');
if(response.ok == true) {
const slideData = await response.json();
if(!slideData.length) {
throw new Error('No slide data found');
}
return slideData;
} else {
throw new Error('The data could not be read');
}
}
// 非同期で実行
async function init() {
try {
//slideデータ取得(json)
const slides = await fetchSliders();
//DOM作成
for(const slide of slides) {
const slideEml = document.createElement('li');
const img = document.createElement('img');
img.src = './images/' + slide.img;
img.alt = slide.alt;
slideEml.appendChild(img);
slideWrap.appendChild(slideEml);
}
//FlexSliderプラグインを実行
const sliderElm = createSlider();
} catch(e) {
console.error(e);
}
}
init();
最終的には、FlexSliderプラグインを実行しています。
まとめ
今回初めて非同期処理を使いました。外部ファイルの読み込み順を制御できるので、今後も使いそうな機能です。