まだjQueryで消耗していますよ?でもVue.jsでAjaxやってみた話
お久しぶりです。きっしーです。
本来であれば3月末にはアップする記事だったのですが、つい先日まで激しいお祭りが開催されていたのでなかなか手が付けられませんでした。
まだまだ日々案件に追われていますが、Google先生の力を借りながらタスクをこなしています。
今回のお題は「技術ネタ」ということで、普段からフル活用しているjQuery.ajax()について書いていこうと思います。
また前々から気になっているVue.jsとaxiosにも少しだけ触れていきます。
まずはjQuery.ajax()の概要
説明:非同期HTTP(Ajax)要求を実行します。
この$.ajax()関数は、jQueryによって送信されるすべてのAjax要求の基礎となります。いくつかのより高いレベルの代替が利用可能であり、より使いやすいので$.get()、.load()多くの場合、この関数を直接呼び出す必要はありません。ただし、あまり一般的でないオプションが必要な場合は、$.ajax()より柔軟に使用できます。
なるほど・・・。よくわからん。
Google Chromeの翻訳機能で日本語にしたものをコピペしましたが、私自身も概要はよくわかっていません。3年後くらいには説明できるように努力します。
とにかくこのメソッドを使うことで、外部APIのエンドポイントにリクエストを送信してデータを取得したり、PHPにデータを送ってサーバーサイドの処理をさせて結果をJSON形式で取得したりなど、フロントだけでは完結できないような処理を実現することが可能です。
ajaxがあれば幸せになれる例
今どきはejsやpugといったテンプレートエンジンやjekyllといった静的サイトジェネレータなどがあるので、手作業でHTMLをコツコツと編集していくことは少ないかもしれませんが、例えばクライアント側でHTMLでページを作ったりする場合は「サイドバーにカテゴリのリンクを追加したらレイアウトが崩れました。」というようなことがよくあると思います。
そのたびにインデントもバラバラでどこかで閉じタグが抜けているがためにやたらにdivタグの羅列が多いソースコードを見返すのはかなりの苦行だと思います。
そこで、JSONファイルをajaxで取得してカテゴリリストを自動化してしまえば、HTMLを編集させることもタグ抜けが頻発することも防ぐことできるかと思います。
HTMLの作成
まずは適当にHTMLを・・・穏やかすぎるくらいのメイン部分と目に突き刺さるようなサブカテゴリー部分の落差が激しいページが出来上がります。
ちなみにですが、vscodeやatomなどのエディタを使っていれば「html:5」と書いてemmetで処理してしまえばHTML5のひな形ができます。
a.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<style>
body, header, main, .mainColumn, .subColumn, footer{ margin: 0 auto; }
header, .mainColumn, .subColumn, footer{ box-sizing: border-box; padding: 20px; }
header{ background: aquamarine; height: 10vh; }
main{ display: flex; height: 80vh; }
.mainColumn, .subColumn{ flex: 1 0 auto; }
.mainColumn{ background: blanchedalmond; max-width: 70%; }
.subColumn{ background: aqua; max-width: 30%; }
footer{ background: cornflowerblue; height: 10vh; }
</style>
<header>HEADER</header>
<main>
<div class="mainColumn">
<h1>MAIN</h1>
<p>cont1</p>
<p>cont2</p>
<p>cont3</p>
</div>
<div class="subColumn">
<h2>SUB</h2>
<h3>CATEGORY LIST</h3>
<ul id="categoryList">
<li><a href=""></a></li>
</ul>
</div>
</main>
<footer>FOOTER</footer>
<script
src="https://code.jquery.com/jquery-3.4.1.min.js"
integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="
crossorigin="anonymous"></script>
<script src="ajax_get_categories.js"></script>
</body>
</html>
ul内は空コードでli>aと入れていますが、JSで要素を複製する際のひな形的に使用します。
個人的にJSファイル内にHTMLを書くのはあまり好きではないのですが、「空タグを入れるのはちょっと」と考える方はうまいことやってください。
後はJSONとJSを書いて出力をするだけです。
JSONとJSの作成
まずはJSONファイルに必要なデータを記述してa.htmlと同階層に配置します。
category_list.json
{
"categories": [
{
"name": "first",
"link": "/first/",
"sub_categories": [
{
"name": "first_sub1",
"link": "/first_sub1/"
},
{
"name": "first_sub2",
"link": "/first_sub2/"
}
]
},
{
"name": "secound",
"link": "/secound/",
"sub_categories": [
{
"name": "secound_sub1",
"link": "/secound_sub1/"
},
{
"name": "secound_sub2",
"link": "/secound_sub2/"
}
]
},
{
"name": "third",
"link": "/third/",
"sub_categories": [
{
"name": "third_sub1",
"link": "/third_sub1/"
},
{
"name": "third_sub2",
"link": "/third_sub2/"
}
]
}
]
}
HTMLでルール化するとタグの記述揺れやstyle属性でルール外の変更がされていたりなどメンテナンスが大変ですが、JSONであれば書くことが決まっているのであれこれ説明がいらず効率的だと思います。
では本題のajax部分について記述します。
パフォーマンスについては何とも言えないですがこんな感じです。
ajax_get_categories.js
$(function(){
var list = $('#categoryList'),
listItemHTML = list.html(),
subListHTML = '<ul class="sublist"><li><a href=""></a></li></ul>',
subListCount = 0;
list.empty();
$.ajax(
{
type: 'GET',
url: './category_list.json',
dataType: 'JSON'
}
).then(
function(data, status, xhr){ //通信成功
$.each(data['categories'], function(i){
var param = data['categories'][i];
list.append(listItemHTML);
list.children('li').eq(i).children('a').attr('href', param['link']).text(param['name']);
if( param['sub_categories'] ){
list.children('li').eq(i).append(subListHTML);
var subList = $('.sublist').eq(subListCount),
subListItemHTML = subList.html();
subList.empty();
$.each(param['sub_categories'], function(j){
var subParam = param['sub_categories'][j];
subList.append(subListItemHTML);
subList.children('li').eq(j).children('a').attr('href', subParam['link']).text(subParam['name']);
});
subListCount++;
}
});
},
function(xhr, status, error){ //通信失敗
console.log(xhr, "\n" + status, "\n" + error);
}
);
});
ポイントとしてはサブカテゴリーが無かったとしても正常にHTMLが出力されるように、var subListのインデックス(何番目の要素か)をvar subListCountで合わせているところです。
なぜかというと「普通に考えれば.eq(i)でいけるやろ」と思ってローカル環境で試していたところ、見事にインデックスがずれて出力できない問題にぶち当たったからです。危うく違う技術ネタで書き直すところでした。
Vue.jsとaxiosで書き直してみる
これで動作も確認できたので終了・・・と言いたいところでしたが、今の時代jQueryの記事だけでは満足できない方も多いとおもうので、まだ触ったこともないVue.jsとaxiosというライブラリをつかって書き直してみます。
先ほど作成したHTMLを「b.html」として別名保存して記述を変更していきます。
b.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<style>
body, header, main, .mainColumn, .subColumn, footer{ margin: 0 auto; }
header, .mainColumn, .subColumn, footer{ box-sizing: border-box; padding: 20px; }
header{ background: aquamarine; height: 10vh; }
main{ display: flex; height: 80vh; }
.mainColumn, .subColumn{ flex: 1 0 auto; }
.mainColumn{ background: blanchedalmond; max-width: 70%; }
.subColumn{ background: aqua; max-width: 30%; }
footer{ background: cornflowerblue; height: 10vh; }
</style>
<header>HEADER</header>
<main id="main">
<div class="mainColumn">
<h1>MAIN</h1>
<p>cont1</p>
<p>cont2</p>
<p>cont3</p>
</div>
<div class="subColumn">
<h2>SUB</h2>
<h3>CATEGORY LIST</h3>
<ul id="categoryList">
<li v-for="list in parameters">
<a v-bind:href="list.link">{{list.name}}</a>
<ul v-if="list.sub_categories" class="sublist">
<li v-for="sublist in list.sub_categories">
<a v-bind:href="sublist.link">{{sublist.name}}</a>
</li>
</ul>
</li>
</ul>
</div>
</main>
<footer>FOOTER</footer>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>←axiosライブラリの読み込み
<script src="https://unpkg.com/vue"></script>←Vue.jsの最新版を読み込み
<script src="axios_get_categories.js"></script>←Vue.js+axiosのロジックを記述
</body>
</html>
次にjQueryで書いていたJSファイルを変更していきます。
新たに「axios_get_categories.js」というファイル名で新規にファイルを作成して、記述を加えていきます。
axios_get_categories.js
new Vue(
{
el: '#main',
data: {
parameters: []
},
mounted: function(){
var v = this;
v.catlist(v);
},
methods: {
catlist: function(v){
axios(
{
method: 'GET',
url: './category_list.json',
responseType: 'json'
}
).then(function(responce){
// responce.data;
v.parameters = responce.data.categories;
console.log(v.parameters);
}).catch(function(responce){
console.log(responce);
});
}
}
}
);
記法はjQueryではあまり触れる機会のないオブジェクト指向な感じの書き方ですが、部分的に見ればあまり難しいものではないので、Google先生に頼れば特に問題ないでしょう。
ハマった部分は、dataで定義しているparametersのところに、本来であればaxios().then()で処理してJSONから取得したデータが入るはずなのですが、普通にチュートリアル通りにthis.parameters=responceとか書いていると値が渡らないという悲劇がおきます。
これ調べても以外と解決法が出てこなくて悲しみが深いです。
Vue使いの皆さんの中では常識なのでしょうか・・・。
とにかく、この記述でb.htmlを確認してみるとjQueryで書いた時と同じようにカテゴリーリストが表示されていると思います。
しかもjQueryでやっていた時のようにインデックスを合わずとも、すべてVueが勝手に処理してくれるので無駄に長い条件分岐などを書く必要がありません。
まとめ
Vue.jsについてはチュートリアルを読んだのは1年ほど前でなおかつ1時間ほどで挫折した記憶がありますが、今読み返して実装してみると「なぜ今まで使わなかったのか」と後悔するくらいに書きやすいし便利です。
smartyやBladeなどのテンプレートの記法に慣れている方であれば、記述もすぐなじむのではないでしょうか。
VueのほかにもReactやAngularなど選択肢は山ほどありますが、少し読んだだけでちょっとしたプログラミングができてしまうVue.jsはかなりおすすめです。
jQueryについて書いていくはずがVue.jsのお話になってしまいました。
「もうjQuery.ajax()とかいらないんじゃね・・・?」と思ったりもしましたが、一番なじんでいるのでまだまだjQueryは活用しそうです。
よきプログラミングライフを。