- 投稿日:2020-05-15T22:48:58+09:00
【JavaScript】関数、無名関数、即時関数の違い、書き方を覚えるために実施したこと
【JavaScript】【初学者向け学習法】関数、無名関数、即時関数の違い、書き方を覚えるために実施したこと
私と同じようにこれからJavaScriptを学習する/している方向けの記事です。
タイトルの通り、関数、無名関数、即時関数を理解するために実施した学習方法です。
もし同じレベル感でお悩みの方の参考になれば幸いです。背景:
プログラミング学習には、手を動かすのが大切と言われます。
動画を見ながらエディタで手を動かすのですが、動画の速度に追いつかず、タイピングもどきで終わることがありました。タイピングに終始していると理解が追いつきません。
そんな自分の学習効率を改善するために考えた方法です。やったこと:
事前準備:
・事前に解説動画を見る
・一緒に画面の処理をタイピングするが、追いつかない場合は解説の理解に集中する
・正解を複写し、コメントアウトで控えておく①模写した正解を見ながらエディタに式を書く
②Google Chromeのデベロッパーツールで表示させる
③なぜ表示されたのかを自分に説明する。できないうちは①②の複写を繰り返す
④①の内容を変えて書き、以降繰り返し①は手を動かすことで記憶する
③は自分への説明で記憶を定着させる
④は変化を与えることで学習効果を高める
ということをしています。具体例です。
function hello(name){ var Hello = "hello " + name; return Hello; } var result = hello("Tom"); console.log(result);ここで①②を実行し、結果を確かめたうえで、③で自分に説明します。
模写で精いっぱいだと説明できないので①②を繰り返します。模写を見ないでできるようになると、処理内容を考える余裕が生まれます。
そうすると③の自分への説明に進めます。
この場合だと3つに分けて説明しました。・hello関数は関数内でローカル変数Hello変数の処理内容を作り、returnで内容を出力する
・result変数はhello関数から処理のバトンを受けとった
・console.logでresult変数を表示した※声に出した場合は、音声情報として記憶の定着効果が高まります
次に④である変化として無名関数で処理してみました。var hello = function(name){ var Hello = "hello " + name; return Hello; } var result = hello("rachel cook"); console.log(result);①②で模写ができるようになっているので、改変する余裕があります。
こちらも自分に説明できたら、次は変化の幅を変えて、別の処理内容を書きます。
文字列の表示から四則演算に変えました。function add(a,b){ var Add = a + b; return Add; } var result = add(1,2); console.log(result);次の変化は引数の数を増やした無名関数Ver.
ローカル変数名に計算を意味するcalcutlationと命名し、英語学習も兼ねました。var add = function(x,y,z){ var calculation = x + y + z; return calculation; } var result = add(10,11,12); console.log(result);次は関数と即時関数の変化を書きました。
function hello(){ console.log("hello"); }; hello();(function hello(){ console.log("hello there."); })();ここに至るまでに関数の形を手が覚えているので、()で括る箇所も理解して使うことができました。
そして学習フローをこのように記事にすることで、自分の理解度を確認。
関数以外の学習にも応用できるようにと考えた次第です。
こうした方が効率が良い、という知恵がありましたら、コメントをお寄せ頂けますと幸いです。
- 投稿日:2020-05-15T22:08:20+09:00
VSCodeでReact-JSXを保存するとき勝手に改行されちゃう問題
問題
VSCodeで下記のようなDOMを書いて
ReactDOM.render( <React.StrictMode > <App /> </React.StrictMode>, document.getElementById('root') );保存(⌘+S)しようとすると、勝手に改行されてしまう問題。
もちろんエラーになります。ReactDOM.render( < React.StrictMode > < App / > < /React.StrictMode>, document.getElementById('root') );解決策
VSCodeの設定を変更します。
Settings.jsonファイルを開き、下記を追加します。"files.associations": { "*.js": "javascriptreact" }以上です。
- 投稿日:2020-05-15T21:07:06+09:00
Vuetfiy v-dialogのモーダル化が機能しない
Vuetify v-dialogのモーダル化が機能しない
新規で作成もしくはソースコードの内容を大体把握してある個人の方・一人でプロジェクトを回している方には参考にならないかと思います。
Vuetifyの
v-dialog
にはオプションで色々指定できる
モーダル化させるためにpersistent
を指定することでダイアログ外を押しても閉じないようにできるそれが機能しなかったので備忘録的にまとめる
Vuetify
https://vuetifyjs.com/ja/components/dialogs/結論
outside
というオプションが悪さしていました。
このオプションはダイアログ外を押した時に発火するイベントです。
そいつが諸悪の権化なので削除するなりよしなに修正することで回避しましょう。こんなことで時間取られるの辛い…辛い…
ちなみに調べるとVuetify2.1以下だとバグで機能しないらしいですが、
orverlay
と合わせるとバグるみたいなので多分今回の場合は関係ないです。
https://github.com/vuetifyjs/vuetify/issues/8697
- 投稿日:2020-05-15T20:57:19+09:00
Google maps APIでドラゴンボールの場所を検索してみよう!
はじめに
- ピンを快適にする方法
- Geocodingとは
- 実装
ピンを快適にする方法
前回はピンを快適にする方法を記事で紹介しました!前回からの続きとなりますので是非参考にしてください!!
https://qiita.com/Ryunosuke-watanabe/items/958ed12471effc8fd778Goecodingとは
ジオコーディングとは住所や地名から緯度経度の情報を出すことです!
この機能を使えば、具体的な緯度経度がわからなくても、場所の名前だけでピンを刺したり中心を設定することができます。実装
JavaScript,HTML,css全てでで実装します!まずGeocodingをするにはAPIでGeocodingを追加する必要があります。
プラットフォームの方で簡単に追加できるので是非やってみてください。まずhtmlとcssで検索窓を追加します。
maps.html<html> <head> <meta charset="UTF-8"> <title>map</title> <link rel="stylesheet" href="css/style.css"> </head> <body> <div id="floating-panel"> <input id="address" type="textbox" value="東京駅"> <input id="submit" type="button" value="Geocode"> </div> <div id="map"></div> <script src="js/map.js"></script> <script src="data/place.json"></script> <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyBZUNbx_85VM6LurRVIHZcxl-7Vg3O2C9g&callback=initMap" async defer></scriptsrc>></script> </body> </html>style.cssbody { height: 100%; width: 100%; } #map { height: 100%; width: 100%; } .mapsballoon { width: 150px; height: auto; } #floating-panel { display: inline-block; background-color: #fff; padding: 5px; border: 1px solid #999; text-align: center; font-family: 'Roboto','sans-serif'; line-height: 30px; padding-left: 10px; }次はJavaScriptで機能を実装していきます!
map.jsvar map; var marker = []; var infowindow = []; var Center = {lat: 24.4064, lng: 124.1754}; var place_data = [ { "loc": "バンナ公園", "lat": 24.375031, "lng": 124.160795, "balloon": "hogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehoge" }, { "loc": "石垣島鍾乳洞", "lat": 24.361743, "lng": 124.154466, "balloon": "test" }, { "loc": "石垣やいま村", "lat": 24.40489, "lng": 124.144636, "balloon": "test" } ] function initMap() { map = new google.maps.Map(document.getElementById('map'), { center: Center, zoom: 11.5 }); markerset() }; function markerset(){ for(var i=0;i<place_data.length;i++) { marker[i] = new google.maps.Marker({ position: {lat: place_data[i].lat, lng: place_data[i].lng}, map: map, title: place_data[i].loc }); infowindow[i] = new google.maps.InfoWindow({ content: '<div class="mapsballoon"><h2>' + place_data[i].loc + '</h2>' + place_data[i].balloon + '</div>' }); var geocoder = new google.maps.Geocoder(); markerEvents(i) document.getElementById('submit').addEventListener('click', function() { geocodeAddress(geocoder, map); }); } } var opened = place_data.length + 1; function markerEvents(i) { marker[i].addListener('click', function() { if (opened != place_data.length + 1) { infowindow[opened].close(map, marker[opened]); } infowindow[i].open(map, marker[i]); opened = i; }); } function geocodeAddress(geocoder, resultsMap) { var address = document.getElementById('address').value; geocoder.geocode({'address': address}, function(results, status) { if (status === 'OK') { resultsMap.setCenter(results[0].geometry.location); var marker = new google.maps.Marker({ map: resultsMap, position: results[0].geometry.location }); } else { alert('Geocode was not successful for the following reason: ' + status); } }); }今回はgeocodeAddressというファンクションを追加しました!
うまくhtmlのIDと紐付けて検索できるようにしています!!ちゃんと東京駅に飛ぶことができました!
いろいろな場所に飛ぶことができるので是非遊んでみてください!!最後に
いかがだったでしょうか?今回は前回の予告通りgeocodingの機能を実装してみました。いろいろな実装に使えそうな機能ですので是非参考にしてください。
次回はピンにラベルをつけていきたいと思います!
参考文献
https://developers.google.com/maps/documentation/javascript/examples/geocoding-simple
- 投稿日:2020-05-15T20:52:16+09:00
JavaScriptだけでtodoアプリを作る(JS基礎復習)
家にいることが多くなったこのご時世。
比較的自由な時間が増えたので、全然触っていなかったJavaScriptを思い出すため、基礎の復習に最適だと聞くTodoアプリを作ってみました。todoアプリに実装する機能
todoアプリに実装する機能は、以下の通りです。
- テキストボックスに入力した文字を取得する
- addボタンを押した時
- テキストボックスに入力した内容がToDoリストに表示される
- 一項目を削除するボタン、全ての項目を削除するボタンを表示する
- ToDoリストに追加される項目の隣に✅(完了ボタン)を表示
- ✅(完了ボタン)を押した時
- Doneリストにその項目を表示する
- 項目の隣に削除ボタン、✅を押した日時を表示する
こちらが完成図になります。
こんな条件で、todoアプリを作ってみます。Step1.まずは見た目から
まずはHTMLとCSSで、見た目の部分だけ作ります。
HTMLは、todoappforjs<body> <header> <h1>ToDoアプリ</h1> </header> <div class="addli"> <input id="add-area" type="text" placeholder="To Do"> <span class="add-btn">add</span> </div> <div id="todo-app"> <ul class="lists" id="todo"> <p>ToDo</p> </ul> <ul class="lists" id="done"> <p>Done</p> </ul> </div> </body>以上がHTMLです。CSSは割愛します。
Step2.textboxに入力した内容がToDoに表示されるまで
ここからJavaScriptを記述します。
//class 'add-btn' を取得 var e = document.getElementsByClassName('add-btn'); e[0].addEventListener('click', function() { var listText = document.getElementById('add-area'); var text = document.createTextNode('listText.value'); var li = document.createElement('li'); var list = document.getElementById('todo'); //作成したliタグにtextboxに入力した値textを追加 li.appendChild(text); list.appendChild(li); });addボタンをクリックした時に、
input
タグに入力されている値のvalue
を取得し、新たにli
タグをToDoリスト内に作り、そこに先ほどのinput
タグに入力した値を追加するという内容です。step3.削除ボタン、完了ボタンの実装まで
続いて、作成した
li
タグに削除ボタン、完了ボタンを追加します。ちなみに、ゴミ箱のアイコンとチェックマークは、Font Awesomeを使っています。同様にJavaScriptから、e[0].addEventListener('click', function(){ var li = document.createElement('li'); //削除ボタン var trash = document.createElement('span'); trash.classList.add('trash'); trash.innerHTML = '削除 <i class="fas fa-trash-alt"></i>'; li.appendChild(trash); //完了ボタン var check = document.createElement('span'); check.classList.add('check'); check.innerHTML = '完了 <i class="far fa-check-square"></i>'; li.appendChild(check); var list = document.getElementById('todo'); list.appendChild(li) })ここまでのJavaScriptはaddボタンを押した時のイベントを記述しているので、中身を一つの関数にまとめます。
function addElement() { var text = document.createTextNode('listText.value'); var li = document.createElement('li'); var list = document.getElementById('todo'); //作成したliタグにtextboxに入力した値textを追加 li.appendChild(text); list.appendChild(li); //削除ボタン var trash = document.createElement('span'); trash.classList.add('trash'); trash.innerHTML = '削除 <i class="fas fa-trash-alt"></i>'; li.appendChild(trash); //完了ボタン var check = document.createElement('span'); check.classList.add('check'); check.innerHTML = '完了 <i class="far fa-check-square"></i>'; li.appendChild(check); };削除ボタン、完了ボタンにそれぞれクラスを割り当てたのは、判別化を図るためです。
innerHTML
プロパティはそのままHTMLを書くことができるので便利ですね。step4.要素を削除する
続いて、削除ボタンを押した時に要素を削除するイベントを記述します。押した要素を判別するのに
for
文を使います。function trashBox() { var trash = document.getElementsByClassName('trash'); for(var i = 0; i < trash.length; i++) { trash[i].addEventListener('click', function() { this.parentNode.remove(); }); } }削除ボタンを押すことで、その押したリストのみが削除される、といった内容の関数です。
step5.Doneリストに要素を移動する
続いて、完了ボタンを押した時、Doneリスト内に移動する、というイベントを記述します。
こちらも、削除ボタンと同様にfor
文でまわします。function checkBox() { var check = document.getElementsByClassName('check'); var done = document.getElementById('done'); for(var i = 0; i < check.length; i++) { check[i].addEventListener('click', function() { done.appendChild(this.parentNode); }); } }JSのコードまとめ
最後に、まとめとしてこれまでのコードの記述の一覧を載せます。
var e = document.getElementsByClassName('add-btn'); e[0].addEventListener('click', function() { addElement(); trashBox(); checkBox(); }); function addElement() { var listText = document.getElementById('add-area'); var text = document.createTextNode(listText.value); var li = document.createElement('li'); li.appendChild(text); // li要素にボタンを追加 var trash = document.createElement('span'); trash.classList.add('trashPosition'); trash.classList.add('trash'); trash.innerHTML = '削除 <i class="fas fa-trash-alt"></i>' li.appendChild(trash); var check = document.createElement('span'); check.classList.add('checkPosition'); check.classList.add('check'); check.innerHTML = '完了 <i class="far fa-check-square"></i>' li.appendChild(check); var lists = document.getElementById('todo') lists.appendChild(li); }; // todoリスト内の削除ボタン function trashBox() { var trash = document.getElementsByClassName('trash'); // クリックしたliタグの配列数を取得 for (var i = 0; i < trash.length; i++) { trash[i].addEventListener('click', function() { // thisはtrash[i]にあたる var li = this.parentNode; li.remove(); // console.log(i); }); }; }; function checkBox() { var check = document.getElementsByClassName('check'); var done = document.getElementById('done'); for (var i = 0; i < check.length; i++) { check[i].addEventListener('click', function() { var li = this.parentNode; done.appendChild(li); this.remove(); }); }; };終わりに
以上がJavaScriptのみで作るTodoアプリでした。基礎的な部分のみを理解して作ったものなので、どこか間違ってる箇所や、より効率的にかけるところがあれば、ご指摘いただけるとありがたいです。
- 投稿日:2020-05-15T17:22:11+09:00
JavaScriptでディープコピーしたい時
はじめに
モーダルを使うときなど、オブジェクトのディープコピーを作りたくなることがたまにあり、
調べても自分が期待する結果になるような方法がなかったので、備忘録的にまとめておこうと思います。
間違いやもっと良い方法などありましたら、コメントいただけると嬉しいです!実現したいこと
下記のようにArrayの中に複数オブジェクトがあるデータを良い感じにコピーしたい。。
[{'key1': 'value1', 'key2':'value2'},{'key1': 'value3', 'key2': undefined}]なぜディープコピーする必要があるか
上記をコピーしてコピー先のオブジェクトを変更してみると・・
追記(2020/5/16)
@jay-es さんからコメントをいただき、シャローコピーするように修正しました!
コメントありがとうございます!let lists = [{'key1': 'value1', 'key2':'value2'},{'key1': 'value3', 'key2': undefined}] let copyLists = [...lists] copyLists[0].key1 = "hoge" console.log('lists') console.log(lists) console.log('copyLists') console.log(copyLists)実行結果
lists 0: {key1: "hoge", key2: "value2"} 1: {key1: "value3", key2: undefined} copyLists 0: {key1: "hoge", key2: "value2"} 1: {key1: "value3", key2: undefined}
このようにコピー先のオブジェクトを変更したところ、コピー元のオブジェクトまで更新されてしまいました。
上記のようなコピーの仕方の場合、listsとcopyListsがメモリ上の同じデータを参照してしまっているためです。
(細かいところは自分も理解し切れていないのですが、上記の場合はコピーして別のオブジェクトを作ったというより、
同じオブジェクトに対して別名を付けているようなもの?と理解しています)
一方ディープコピーの場合は、オブジェクトとメモリ上のデータの両方をコピーするため、独立したオブジェクトを作ることができます。ディープコピーを試してみた
方法1
ネットで検索するとよく出てくるのが、JSON.parse(JSON.stringify())を使用したやり方。
まずはこのやり方を試してみました。let lists = [{'key1': 'value1', 'key2':'value2'},{'key1': 'value3', 'key2': undefined}] let copyLists = JSON.parse(JSON.stringify(lists)) copyLists[0].key1 = "hoge" console.log('lists') console.log(lists) console.log('copyLists') console.log(copyLists)実行結果
lists 0: {key1: "value1", key2: "value2"} 1: {key1: "value3", key2: undefined} copyLists 0: {key1: "hoge", key2: "value2"} 1: {key1: "value3"}
確かにコピー先のオブジェクトを変更しても、コピー元のオブジェクトは更新されなくなったが、
key2がなくなっていることから、値がundefinedの場合はキーごと消えてしまうよう。。
調べてみたところ、こちらの記事で解説があり、
どうやら特定のオブジェクトのプロパティだった場合、消されてしまうようです。方法2
Array.prototype.map()で新しいオブジェクトを作るパターン
let lists = [{'key1': 'value1', 'key2':'value2'},{'key1': 'value3', 'key2': undefined}] let copyLists = lists.map( list => ({'key1': list.key1, 'key2': list.key2})) copyLists[0].key1 = "hoge" console.log('lists') console.log(lists) console.log('copyLists') console.log(copyLists)実行結果
lists 0: {key1: "value1", key2: "value2"} 1: {key1: "value3", key2: undefined} copyLists 0: {key1: "hoge", key2: "value2"} 1: {key1: "value3", key2: undefined}
コピー先のオブジェクトを変更しても、コピー元のオブジェクトは更新されず、
値がundefinedになっているオブジェクトもディープコピーできました!追記(2020/5/16)
Array.prototype.map()とスプレット構文を使う方法
(@pochopocho13 さんからコメントで教えていただきました!ありがとうございます!)let lists = [{'key1': 'value1', 'key2':'value2'},{'key1': 'value3', 'key2': undefined}] let copyLists = lists.map( list => ({...list})) copyLists[0].key1 = "hoge" console.log('lists') console.log(lists) console.log('copyLists') console.log(copyLists)実行結果
lists 0: {key1: "value1", key2: "value2"} 1: {key1: "value3", key2: undefined} copyLists 0: {key1: "hoge", key2: "value2"} 1: {key1: "value3", key2: undefined}
スプレット構文を使った方法であれば、仮にkeyが変わった場合でも、
修正が不要になるのでこちらの方が良さそうです!まとめ
この辺は地味にハマるところなので、徐々に理解を深めていきたいと思いました。。
参考にさせていただいた記事
・JavaScriptのDeepCopyでJSON.parse/stringifyを使ってはいけない
・[JavaScript]色々なディープコピー
- 投稿日:2020-05-15T17:21:23+09:00
constで宣言した配列の値は変えられるのか(JavaScript)
結論
タイトルの答えは「YES。変えられる。」
理由
「JavaScriptでconstの配列の値が変わる理由」という記事を読んだところ、
constの値は不変ということではなく、変数識別子が再代入できないというだけだからだ。
というのが結論だったが、実際の挙動も確かめたかったので手を動かしてみた。
実行できるパターン
1.インデックスを指定した値の代入
const arr1 = []; arr1[0] = 'a'; console.log(arr1); // 実行結果 // [ 'a' ]2. 要素の追加
const arr2 = []; arr2.push('b'); console.log(arr2); // 実行結果 // ['b']3.要素の削除
const arr3 = [1, 2, 3]; arr3.splice(1, 1); console.log(arr3); // 実行結果 // [ 1, 3 ]4. 参照している配列への要素の追加
const arr4 = [1, 2, 3]; const arr5 = arr4; arr5[0] = 'c'; console.log(arr4); console.log(arr5); // 実行結果 // ['c', 2, 3] // ['c', 2, 3]実行できないパターン
配列自体への再代入
const arr6 = [1, 2, 3]; arr6 = [4, 5, 6]; // 実行結果 // arr6 = [4, 5, 6]; // ^ // TypeError: Assignment to constant variable.まとめ
配列の中身の操作や再代入に関しては、要素を追加しようが消そうが怒られることなく実行できた。
ただし「配列それ自体への再代入」はできなかった。
- 投稿日:2020-05-15T17:21:10+09:00
Vueのカスタムコンポーネントで双方向データバインディングを入れてみた
Vueのカスタムコンポーネントはすごく便利ですね。
HTMLのテンプレートとして使えて、しかも使う側がさらにHTMLを差し込むことができるのは重宝しています。今回は、まずはカスタムコンポーネントを単純なテンプレートとして使う例を示した後、さらに汎用的にするために、カスタムコンポーネントを双方向データバインディングに対応させます。
ちなみに、ここらへんVueの方々が頑張っていただいているようで、仕様が変わる(使いやすくなる)ことがありますので、その際にはまた追従したいと思います。
最後に、自作のswagger定義ファイルエディタを紹介しています。
単純なコンポーネントの例:HTMLテンプレートとして使う
HTMLのテンプレートとして使い、使う側がさらにHTMLを差し込む例です。
期待はこんな感じです。使う側はこんな風に書きます。
<custom-template> 使う側が差し込みたいHTML </custom-template>そして、テンプレート側ではこんな感じで記載しておきます。
<div class="panel panel-default"> <slot></slot> </div>最終的に、こんな感じに合成したいです。
<div class="panel panel-default"> 使う側が差し込みたいHTML </div>実際のテンプレート側は、以下のようなコードとなります。
Vue.component('custom-template-01', { template: ` <div class="panel panel-default"> <slot></slot> </div>`, });そうすると、使う側には以下のように合成されて見えるようになります。
<slot></slot>
が挿し代わっています。<custom-template-01> <div class="panel-body"> Hello World </div> </custom-template-01>ちなみに、使う側が差し込んだHTMLは使う側の制御範囲なので、v-modelなどそのまま使えます。
例えばこんな感じ。(使う側です)<label>data</label> {{data}} <br> <label>custom_template_01_a</label> <custom-template-01> <div class="panel-body"> <input type="text" v-model="data" class="form-control"> </div> </custom-template-01>以降では、使う側を親、使われる側(HTMLテンプレート側)を子と呼ぶようにします。
HTMLテンプレート例でのデータバインディング
さきほどの、HTMLテンプレート例では、子の
<slot></slot>
の内容をすべて親に任せています。一方で、親からのパラメータを使って子が内容を作成したいことが多々あります。そこで、もう一つ例を挙げます。まず子の方です。
Vue.component('custom-template-02', { props: ['header'], template: ` <div class="panel"> <div class="panel-heading"> <h4 class="panel-title">{{header}}</h4> </div> <div class="panel-body"> <slot></slot> </div> <div class="panel-footer"> <slot name="footer"></slot> </div> </div>`, });親の方はこちらです。
<custom-template-02 class="panel-default" header="This is Header"> <template> Hello World </template> <template v-slot:footer> since 2020 </template> </custom-template-02>この例では、最初の例に比較して、追加の仕組みを3つ使っています。
・1つめ:差し込み先のslotに名前を付けました。
テンプレート内のname=footerの属性 が付いたslotエレメントが、v-slot:footer の属性を付けたtemplateエレメントの中身に置き換わります。footerという名前は自由に決められます。名前を付けたことで、差し込む場所を複数作ることができるようになります。
・2つめ:親から子にパラメータを渡しています。
子に、props: [ ‘header’] というプロパティが増えています。
これは、子側は親側からheaderというプロパティを受け取ることを宣言しています。親は、header="This is Header" という感じで、カスタムコンポーネントの要素にheaderを追加していますので、それを子が受け取ることができています。
受け取った値は、<div class="modal-header"> <h4 class="modal-title">{{header}}</h4> </div>のような感じで、HTMLの中に含めているのがわかります。
これにより、すべてを親側に任せるだけでなく、親からパラメータを取得して子側でHTMLに反映することができます。・3つ目:親で指定した属性が子のHTMLに渡されます。
class="panel-default" の部分ですが、headerと異なり、子側で受け取る準備(props指定)をしていません。
その場合、HTMLのテンプレートのルートのエレメントの属性として追加されます。テンプレート上は、
<div class="panel">となっていますが、実際のHTMLに描画されたときには、
<div class="panel panel-default">となります。子側にclassがすでに指定済みですので、子側のclassに親からのclassの属性値が追加された形になっています。当然ながら、propsに指定済みの属性は除きます。
親と子の双方向データバインディング
propsを使って親のデータを子に渡しました。
また、slotを使って子がHTMLを生成する一部を親に任せることができました。
しかしながら、今まで説明してきた方法では子で処理した結果を親が受け取ることはできません。何をいっているわからないかもしれませんが、Vueで必ず使う双方向データバインディングであるv-modelが使えていないということです。
inout_textのエディットボックスで入力した値を初期値とし、カスタムコンポーネント側でダイアログを表示して初期値を表示し、別の値を入力してもらって、その値をinout_textのエディットボックスに表示したい例です。
以下が期待する親のHTMLです。<input type="text" v-model="inout_text" class="form-control"> <custom-template-03 class="panel-default" header="This is Header" v-model="inout_text"> <template> Input Dialog Test </template> </custom-template-03>少し分解すると、Vueとしてv-model=”inout_text”は以下に置き換えられます。
v-bind:value=”input_text” v-on:input=”inout_text”valueという名前で子に渡し、inputというイベントで親に返してもらえればよいわけです。
まず、valueの子への渡し方はすでに説明しました。
propsにvalueを追加すればよいだけです。
残るは、inputイベントです。それには、子で以下を呼べばよいのです。
this.$emit(‘input’, 返したい値)それを反映したのがこちら。
Vue.component('custom-template-03', { props: ['value'], template: ` <div class="panel"> <div class="panel-body"> <slot></slot> </div> <div class="panel-footer"> <button class="btn btn-default" v-on:click="do_input">do_input</button> </div> </div>`, methods:{ do_input: function(){ var ret = window.prompt('入力してください。', this.value); if( ret ) this.$emit('input', ret); } } });親から受け取ったthis.valueを子で書き換えたら、そのまま親にイベントが伝わってほしいかもしれません。ですが、this.valueやemitで、親からの子のデータバインディングと子から親へのイベントを組み合わせて実現しているだけで、それぞれの要素は、片方向でしかないのです。
子と孫の双方向データバインディング
HTMLテンプレート例では、親が子のカスタムコンポーネントを使っていました。
実際には、親が子のカスタムコンポーネントを使って、子がさらに孫のカスタムコンポーネントを使って、というように、階層的につながっていく場合が多々あります。
そうすると、子の中でもv-modelを使いたくなります。まず、孫から。
Vue.component('custom-template-04-a', { props: ['value'], template: ` <div> <button class="btn btn-default" v-on:click="do_input">do_input</button> </div> `, methods:{ do_input: function(){ var ret = window.prompt('入力してください。', this.value); if( ret ) this.$emit('input', ret); } } });さきほど子側で、入力ダイアログを出していた部分を抜き出したものです。
次が子側です。孫に対してv-modelを使っています。Vue.component('custom-template-04', { props: ['value'], template: ` <div class="panel"> <div class="panel-body"> <slot></slot> </div> <div class="panel-footer"> <custom-template-04-a v-model="value_"></custom-template-04-a> </div> </div>`, data: function(){ return { value_: this.value, } }, watch: { value: function(newValue){ this.value_ = newValue; }, value_: function(newValue){ this.$emit('input', newValue); } } });親から受け取ったthis.valueは、親から子への片方向専用であり、子の中での孫との双方向データバインディングには使うことができません。
そこで、親から受け取ったthis.valueをthis.value_にコピーして、それを孫との双方向データバインディングに使っています。data: function(){ return { value_: this.value, } },の部分で、孫とのv-modelに使う変数を宣言し、(コンポーネントの場合、dataは関数で返さないといけないです)
watch: { value: function(newValue){ this.value_ = newValue; },によって、親からvalueの変更通知を受け取ったら、this.value_に再コピーしています。
一方で、以下の孫のカスタムコンポーネント側でthis.value_値の更新通知が来ます。<custom-template-04-a v-model="value_"></custom-template-04-a>そのイベントも、watchでthis.value_を監視することでフックしています。
トリガーされると、親に変更された新しい値を伝えています。watch: { ・・・ value_: function(newValue){ this.$emit('input', newValue); } }まとめると、以下の形を覚えておけば、親-子-孫の間の双方向データバインディングを実現できそうです。
Vue.component('カスタムコンポーネント名', { props: ['value'], template: ` 表示したいHTML `, data: function(){ return { value_: this.value, } }, watch: { value: function(newValue){ this.value_ = newValue; }, value_: function(newValue){ this.$emit('input', newValue); } } });以上でVueコンポーネントの実験は終わりです。
以下に、上記を確認できるページを用意しました。
Vueコンポーネント実験室
https://poruruba.github.io/vuecomp_laboratory/labo_01/サンプルアプリ:Swagger定義ファイルエディタ
さきほど作った双方向データバインディングの定型を使って、Swagger定義ファイルのエディタを作ってみました。
Web上から、エントリポイントを作成したり、メソッドを追加して、複数のパラメータを作ったりしできるようにしました。
(かなり端折っていますし、バグもたくさんあるとは思いますが、自己満足です。。。)画面はこんな感じです。
お決まりの、Petstoreをサンプルとして読み込むボタンを用意したので、なんとなくイメージはできるかもしれません。poruruba/vuecomp_laboratory
https://github.com/poruruba/vuecomp_laboratory/以下からアクセスできます。
https://poruruba.github.io/vuecomp_laboratory/swagger_editor/以上
- 投稿日:2020-05-15T17:20:30+09:00
【Nuxt.js】Modal実践編:QueryでModalを管理する②
前置き
前回の続きです?
https://note.com/aliz/n/n47b0d98be5241つのcomponentsで
複数のModalを表示させましょう✨Step5: 中身をcomponents分けする
Modalの外側と内側で
componentsを切り分けていきましょう。
queryによって切り替えているpタグを
organismsに移動させます??
propsを使わなくて済むので
本当にただ移動させるだけです、楽ちん♪filecomponents/ --| organisms/ ----| modals/ -----| ModalContainer.vue --| templates/ ----| modals/ -----| ModalRoute.vue layouts/ --| default.vueModalContainer.vue<template> <div class="modal-container"> <!-- 切り替える中身 --> <p v-if="$route.query.modal === 'login'" class="text" > {{ $route.query.modal }} </p> <p v-if="$route.query.modal == 'register'" class="text" > {{ $route.query.modal }} </p> </div> </template> <script lang="ts"> import Vue from 'vue' export default Vue.extend({ name: 'Modal', }) </script> <style lang="scss" scoped> .modal-container { .text { font-size: 36px; } } </style>Step6: 中身をFormにする
ついでにformを作りましょう?
password入力のinputも作ると
inputをmoleculesで作る必要が出てくるので
一旦イメージだけできればOKです??ModalContainer.vue<template> <div class="modal-container"> <!-- 切り替える中身 --> <form class="form" v-if="$route.query.modal === 'login'" @submit.prevent > <label class="label"> <span class="label"> {{ $route.query.modal }} </span> <input v-model="form.email" :type="type" placeholder="email" > </label> <button class="button" type="submit" @click="$emit('submit', form)" > {{ $route.query.modal }} </button> </form> <form class="form" v-if="$route.query.modal === 'register'" @submit.prevent > <label class="label"> <span class="label"> {{ $route.query.modal }} </span> <input v-model="form.email" :type="type" placeholder="email" > </label> <button class="button" type="submit" @click="$emit('submit', form)" > {{ $route.query.modal }} </button> </form> </div> </template> <script lang="ts"> import Vue from 'vue' export default Vue.extend({ name: 'Modal', data () { return { form: { email: '', }, } }, props: { type: { type: String, default: 'text', }, }, }) </script> <style lang="scss" scoped> .modal-container { .form { .label { font-size: 24px; .label { display: block; } } .button { display: block; } } } </style>【解説】
・@click="$emit('submit', form)"
inputに入力する値formを$emitで渡します。ModalRoute.vue<template> <div v-if="$route.query.modal" class="modal-route" > <div class="bg" @click="$router.push('/')" /> <div class="modal-wrap"> <button class="button" @click="$router.push('/')" > <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M24 20.188l-8.315-8.209 8.2-8.282-3.697-3.697-8.212 8.318-8.31-8.203-3.666 3.666 8.321 8.24-8.206 8.313 3.666 3.666 8.237-8.318 8.285 8.203z" /></svg> </button> <ModalContainer @submit="submit" /> </div> </div> </template> <script> import Vue from 'vue' export default Vue.extend({ name: 'Modal', components: { ModalContainer: () => import('@/components/organisms/modals/ModalContainer.vue'), }, methods: { submit (form) { console.log(form) // eslint-disable-line }, }, }) </script> <style lang="scss" scoped> .modal-route { position: fixed; top: 0; width: 100%; height: 100%; .bg { width: 100%; height: 100%; background-color: rgba(0,0,0,0.5); } .modal-wrap { border-radius: 8px; background-color: #ffffff; width: 50%; height: 50%; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); padding: 30px; .button { border: none; position: absolute; top: 5%; right: 2%; } } } </style>【解説】
・@submit
$emitでつけたイベント名
・// eslint-disable-line
consoleなど特定の行に書かないと
ESLintでエラーになります。
https://qiita.com/nju33/items/2d0cfea4fffbfdbff87aStep7: Formを分ける
今はformが2種類ですが
もし増えたら管理が面倒なので
分けてしまいましょう?え、1つのコンポーネントを
queryで切り替えるのが
メリットなんじゃないの??
分けたら意味なくない??
と思ったそこのアナタ❗️安心してください?
componentタグを使えば良いのです✨【ディレクトリ 】
modalsというファイルを作り
ModalContainerのform2つを
それぞれに分けましょう。?before?
filecomponents/ --| organisms/ ----| modals/ -----| ModalContainer.vue --| templates/ ----| modals/ -----| ModalRoute.vue layouts/ --| default.vue?after?
filecomponents/ --| templates/ ----| modals/ -----| ModalRoute.vue modals/ --| login.vue --| register.vue layouts/ --| default.vue【modals/login.vue】
・formのregister部分を除きましょう?
・$emitのイベント名を分かりやすく
submitLoginに変更しましょう!login.vue<template> <div class="modal-container"> <!-- 切り替える中身 --> <form v-if="$route.query.modal === 'login'" class="form" @submit.prevent="$emit('submitLogin', form)" > <label class="label"> <span class="label"> {{ $route.query.modal }} </span> <input v-model="form.email" :type="type" placeholder="email" > </label> <button class="button" type="submit" > {{ $route.query.modal }} </button> </form> </div> </template> <script lang="ts"> import Vue from 'vue' export default Vue.extend({ props: { type: { type: String, default: 'text', }, }, data () { return { form: { email: '', }, } }, }) </script> <style lang="scss" scoped> .modal-container { .form { .label { font-size: 24px; .label { display: block; } } .button { display: block; } } } </style>【modals/register.vue】
変更部分はlogin.vueと同じですregister.vue<template> <div class="modal-container"> <!-- 切り替える中身 --> <form v-if="$route.query.modal === 'register'" class="form" @submit.prevent="$emit('submitRegister', form)" > <label class="label"> <span class="label"> {{ $route.query.modal }} </span> <input v-model="form.email" :type="type" placeholder="email" > </label> <button class="button" type="submit" > {{ $route.query.modal }} </button> </form> </div> </template> <script lang="ts"> import Vue from 'vue' export default Vue.extend({ props: { type: { type: String, default: 'text', }, }, data () { return { form: { email: '', }, } }, }) </script> <style lang="scss" scoped> .modal-container { .form { .label { font-size: 24px; .label { display: block; } } .button { display: block; } } } </style>【components/organisms/modals/ModalRoute.vue】
NidakRoute.vue<template> <div v-if="$route.query.modal" class="modal-route" > <div class="bg" @click="$router.push('/')" /> <div class="modal-wrap"> <button class="button" @click="$router.push('/')" > <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M24 20.188l-8.315-8.209 8.2-8.282-3.697-3.697-8.212 8.318-8.31-8.203-3.666 3.666 8.321 8.24-8.206 8.313 3.666 3.666 8.237-8.318 8.285 8.203z" /></svg> </button> <!-- <ModalContainer @submit="submit" /> --> <component :is="$route.query.modal" @submitLogin="submit($event)" @submitRegister="submit($event)" /> </div> </div> </template> <script> import Vue from 'vue' export default Vue.extend({ name: 'Modal', components: { login: () => import('@/modals/login.vue'), register: () => import('@/modals/register.vue'), }, methods: { submit (form) { console.log(form) // eslint-disable-line }, }, }) </script> <style lang="scss" scoped> .modal-route { position: fixed; top: 0; width: 100%; height: 100%; .bg { width: 100%; height: 100%; background-color: rgba(0,0,0,0.5); } .modal-wrap { border-radius: 8px; background-color: #ffffff; width: 50%; height: 50%; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); padding: 30px; .button { border: none; position: absolute; top: 5%; right: 2%; } } } </style>【解説】
・component :is="$route.query.modal"
└:isでcomponentを呼び出します!
コンポーネントの登録が必要なので
中身をそれぞれimportしましょう?
└それぞれを1つのコンポーネントとみなし
queryで切り替えましょう?
・@submitLogin="submit($event)"
└$emitのイベント名を変えたので
どちらも書きましょう✍️
└($event)は省略可能お疲れ様でした?
完成です??次回予告
【Nuxt.js】アプリ開発実践編:
Nuxt + Vuex + firebaseでログイン付きToDoリストこちらのTODOリストに
ログイン機能をつけていきます!✨
https://note.com/aliz/n/n8411db2c9a20公開予定日は5/19(火)です?
- 投稿日:2020-05-15T17:00:18+09:00
Goole maps API でドラゴンボールの情報を快適にみよう!!
はじめに
- ピンに情報を埋め込む方法
- 他のピンをクリックした時
- cssで装飾
- 最後に
ピンに情報を埋め込む方法
ピンに情報を埋め込む方法は私の一個前の記事で紹介しています!
ぜひ参考にしてください!
https://qiita.com/Ryunosuke-watanabe/items/48c8ec80f87283cc0006今回は前回立てたピンをクリックしたあとに、他のピンをクリックしたときの挙動を施します。
複数のピンが乱立していると見えにくいので、2個目のピンをクリックしたときに他のピンは消えるようにしましょう。他のピンをクリックした時
htmlとcssは前回と同じです。
maps.html<html> <head> <meta charset="UTF-8"> <title>map</title> <link rel="stylesheet" href="css/style.css"> </head> <body> <div id="map"></div> <script src="js/map.js"></script> <script src="data/place.json"></script> <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap" async defer></scriptsrc>></script> </body> </html>style.cssbody { height: 100%; width: 100%; } #map { height: 100%; width: 100%; }JavaScriptの方で操作していきます。今回はみやすいようにJSONのデータを配列として記載しておきます。
データのballoonのなかに紹介文を本来は記載しますが、ホゲホゲとしておきます。map.jsvar map; var marker = []; var infowindow = []; var Center = {lat: 24.4064, lng: 124.1754}; var place_data = [ { "loc": "バンナ公園", "lat": 24.375031, "lng": 124.160795, "balloon": "hogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehoge" }, { "loc": "石垣島鍾乳洞", "lat": 24.361743, "lng": 124.154466, "balloon": "test" }, { "loc": "石垣やいま村", "lat": 24.40489, "lng": 124.144636, "balloon": "test" } ] function initMap() { map = new google.maps.Map(document.getElementById('map'), { center: Center, zoom: 11.5 }); markerset() }; function markerset(){ for(var i=0;i<place_data.length;i++) { marker[i] = new google.maps.Marker({ position: {lat: place_data[i].lat, lng: place_data[i].lng}, map: map, title: place_data[i].loc }); infowindow[i] = new google.maps.InfoWindow({ content: '<div class="mapsballoon"><h2>' + place_data[i].loc + '</h2>' + place_data[i].balloon + '</div>' }); markerEvents(i) } } var opened = place_data.length + 1; function markerEvents(i) { marker[i].addListener('click', function() { if (opened != place_data.length + 1) { infowindow[opened].close(map, marker[opened]); } infowindow[i].open(map, marker[i]); opened = i; }); }openedという新しい変数を用意しておきます。そしてif文で2回目以降マーカーをクリックしたときに前回開いたマーカーを消すという作業をしています。これで二つ目のマーカーをクリックしたとき最初のマーカーは消えます。
ですが、紹介文があまりに長いとこのような感じでwindowが横長になってしまいます。なのでcssで変更を施していきたいと思います。
cssで装飾
実はJavaScriptでdivでballoonの中を囲ってあるので、class名のmapsballoonを指定して装飾することができます。
style.cssbody { height: 100%; width: 100%; } #map { height: 100%; width: 100%; } .mapsballoon { width: 150px; height: auto; }横幅を150pxに指定、高さをautoにしておきました。そうすることで、横長くなることがなくなります。
こんな感じになりました!!
最後に
いかがだったでしょうか?前回の予告通りピンを立てる際の工夫を施しました。次回はgeocoding機能を実装したいと思います。
- 投稿日:2020-05-15T15:52:16+09:00
JavaScript の ?? と || でどっちが0の判定どうなるんだっけ
JavaScriptの
??
と||
ってどういう動きするのだっけ? といつも忘れるので書いておきます。あと記号のググラビリティも悪いので名前も記録しておきたい。まとめ: falsyなものを判定するなら
||
でOK、nullまたはundefinedだけを判定するなら??
の方が良い。null合体演算子
??
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator
Null 合体演算子 (??) は論理演算子の一種です。この演算子は左辺が null または undefined の場合に右の値を返し、それ以外の場合に左の値を返します。
左辺が '' や 0 の場合は左の値を評価して返します
論理OR演算子
||
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Logical_Operators
true に変換できる値は、いわゆる truthy です。false に変換できる値は、いわゆる falsy です。
false と見ることができる式の例は、null、0、空文字列 ("")、あるいは、undefined と評価されるものです。
おまけ
ちなみにこういう演算子とかを検索するときに
??
とかで検索してもだいたい出てこないのでどうやって検索しているかという話。
??
の場合は javascript question double とか記号の名前と特徴を英単語で検索すると「これってなんなの?」的な質問サイトに行き当たって正式名称を知ることができます。
- 投稿日:2020-05-15T14:58:32+09:00
華麗なるGatsby.jsの実践(styled-components/headの編集/404ページ/画像の使用)
以前 gatsbyの公式チュートリアルを意訳しつつやったので、今回は、実際に業務で使用するにあたって
使いそうな機能について公式のドキュメント等を調べてみました。この記事のタイトルをつけた後に気づいたんですが、
公式で上記の画像を発見しました。
華麗なるギャツビーがやはり由来なんでしょうか。お品書き
実際業務で使いそうな機能をピックアップしたところ、以下のようになりました。
- styled-componentsを使いたい
- head修正できるようにしたい
- 404ページをカスタマイズしたい
- gatsbyでの画像の扱いを知りたい今回はhttps://www.gatsbyjs.org/starters/gatsbyjs/gatsby-starter-default/
このスターターを使って進めます。スターターを使用するために、以下のコマンドを実行します。
$ gatsby new app https://github.com/gatsbyjs/gatsby-starter-default $ cd app $ gatsby developstyled-componentsを使いたい
必要なプラグインを取得します。
$ npm install --save gatsby-plugin-styled-components styled-components babel-plugin-styled-componentsbabel-plugin-styled-componentsはstyled-componentsをより扱いやすくしてくれるpluginです。
https://github.com/styled-components/babel-plugin-styled-components
gatsby-config.jsに以下を書き加えます。
gatsby-config.jsmodule.exports = { plugins: [`gatsby-plugin-styled-components`], }あとは使うだけ。思ったよりも簡単だった。
index.htmlimport styled from "styled-components" const IndexPage = () => ( <div> <Title>宇宙の日記</Title> </div> ) export default IndexPage const Title = styled.h1` color: blue; `head修正できるようにしたい
公式の参考ページはこちら
実は上記スターターにはすでに組み込まれていますが、念の為最初から実装方法を確認します。gatsbyではreact helmetがサポートされているのでそれを使う。
npm install --save gatsby-plugin-react-helmet react-helmetgatsby-config.jsに下記2つをを加える。
gatsby-config.js{ plugins: [`gatsby-plugin-react-helmet`] }gatsby-config.jsmodule.exports = { siteMetadata: { title: `色々な紙飛行機`, description: `多種多様な紙飛行機。その世界に触れてみませんか?`, author: `@irico`, },下記のようなcomponentを準備して...
src/components/SEOimport React from "react" import { Helmet } from "react-helmet" import { useStaticQuery, graphql } from "gatsby" function SEO() { const { site } = useStaticQuery( graphql` query { site { siteMetadata { title description } } } ` ) return ( <Helmet title={site.siteMetadata.title} meta={[ { name: `description`, content: site.siteMetadata.description, }, ]} /> ) } export default SEOあとはpageで使うだけ!これも簡単。
ページごとにカスタマイズしたいのであれば、SEOのpropsとして渡して分岐させてあげればよし。const IndexPage = () => { <Layout> <SEO /> ... </Layout> }404ページをカスタマイズしたい
^\/?404\/?$ (/404/, /404, 404/ or 404)上記の正規表現に該当するpageを作成すればいいだけ!
gatsby develop
コマンドでは下記の画像のようなページになりますが、 ビルド後はカスタマイズした404ページに飛ぶようになります。実はこれも上記スターターで最初からページが用意されています(至れり尽くせり)
ローカルで404ページを確認したいときは、 Preview custom 404 pageを閲覧すればOK!
gatsbyでの画像の扱いを知りたい
公式の参考サイトはこちら
普通のパス指定での読み方ももちろんできるが、webpackによるimportがオススメです。
ファイルをあたかもJSソースのように取得することができ、以下の恩恵が得られます。
- webpackが圧縮をおこなってくれる
- ユーザーに404エラーを出す前にコンパイルエラーが出る(チェック漏れを防ぐ)
- ファイル名にハッシュが含まれるおかげで、ブラウザのキャッシュを防ぐ。
import kvImg from "../images/kv.jpg" const IndexPage = () => ( <Layout> <IndexWrapper> <img src={kvImg} alt="紙飛行機の画像" /> </IndexWrapper> </Layout> )escape hatchあるよ!
アプリ下に
static
というファイルを作ってこのファイル内に画像などを置くと、public
フォルダー内にコピーされる。
そうすると呼び出さずに画像を使うことができる!staticフォルダーにkv.jpgを配置したのち、
const IndexPage = () => ( <Layout> <IndexWrapper> <img src='/kv.jpg' alt="紙飛行機の画像" /> </IndexWrapper> </Layout> )勝手にコピーしてくれるので呼び出しは不要!
ただ、以下の短所がある。
- ファイルが縮小されない
- ユーザー側に404が表示される
- コンテンツハッシュが含まれないため、キャッシュされてしまう
なので基本的にはJSを介してアセットを使うのがいいです。static folderが役に立つのは以下のような場合になります。
maifestなどの、特定のファイル名でなければならないもの
画像がたくさんあり、パスを動的に参照する必要がある場合
Pace.jsのように、バンドルするコード外部に小規模のスクリプトを読み込みたい場合
webpackと互換性がないもの
etc..
gatsby-image
https://www.gatsbyjs.org/tutorial/gatsby-image-tutorial/#querying-data-for-a-single-image
- Intersection Observer APIを使用した遅延読み込み
- 画像の位置を保持することで、画像を読んだ途端ページ位置がずれることを防ぐ
- 灰色の背景/ぼやけた画像などの設定が簡単にできる。
などなど、モダンな画像処理をしてくれるらしいです。
ただし、 imgタグの完璧な代替ではないので注意。適したものとしては、固定された大きさのイメージやコンテナ全体に大きく広がるイメージなど。
実は上記スターターでは、宇宙飛行士の絵でgatsby-imageが使用されています。(src/component/image.js)
npm install gatsby-transformer-sharp gatsby-plugin-sharp gatsby-imageどのスターターも用いてない場合は、下記もインストールする。スターターを使用している場合は最初から含まれているパッケージです。
npm install gatsby-source-filesystemgatsby-config.jsを下記のように書き直す。
module.exports = { plugins: [ `gatsby-transformer-sharp`, `gatsby-plugin-sharp`, { resolve: `gatsby-source-filesystem`, options: { path: `${__dirname}/src/data/`, }, }, ], }GraphQLで画像データを扱えるようにするために,gatsby-sourcr-filesystemに画像があるフォルダーを教えています。
先にsrc/components/image.js設定部分を示します。
import React from "react" import { useStaticQuery, graphql } from "gatsby" import Img from "gatsby-image" const Image = () => { const data = useStaticQuery(graphql` query { placeholderImage: file(relativePath: { eq: "gatsby-astronaut.png" }) { childImageSharp { fluid(maxWidth: 300) { ...GatsbyImageSharpFluid } } } } `) return <Img fluid={data.placeholderImage.childImageSharp.fluid} /> } export default Imagefileのパスは、先ほどgatsby-source-filesystemのconfigで設定したパスからの相対パスとなります。
まず知るべきなのは、gatsby-imageでは2つのresponsiveタイプがあるということです。
fixed
fluid
fixedは固定幅,fluidはコンテナに合わせて縮小拡大するタイプです。
上記のクエリを用いてサイズを指定します。
GraphQL fragments を使うことでイメージの設定を行うことができます。
GatsbyImageSharpFluid
もそのフラグメントの1つ。
ただしこれは、GraphiQLでは使用できないので注意。フラグメントについてはいまいち使い分け等がわからなかったので今後要調査....。
画像等の扱いについては上記4つの方法がありますが、使い分けについては
- 直接パス指定 ・・・あまり使わなそう
- gatsby-image ・・・基本的にはこれ!最適化等してくれるので楽
- jsでのimport ・・・imgタグで色々カスタマイズして配置したい場合
- static folder ・・・動的な読み込みや制約がある等
と感じました。実際に使っていく中で適宜使い分けたいと思います。
所感
実務で必要そうだな...と思った部分はほとんどスターターに最初から組み込まれていました。
しかも、使用したい機能についてはドキュメントが手厚く説明してくれてることが多かったです。
優秀ですね!
次回はwordpress等のプラグインやフォーム等がどこまで使えるのか?について調べてみたいと思います。
静的サイトジェネレータなので、動的な部分はほどほどがいいのかもしれませんが、その辺のパフォーマンス的な兼ね合いも調査しつつ...
- 投稿日:2020-05-15T12:27:04+09:00
爆速構築!json-serverでMock API
はじめに
フロントエンド開発のためにAPIのモックが必要になったので、json-serverを利用してモックサーバを構築していきます。
基本的な環境構築
初期化
powershell# プロジェクトディレクトリを作成し, 移動する mkdir mock-api cd ./mock-api # 初期化処理 npm init -yjson-server
今回のメインとなる json-server を導入します。
powershellnpm i -D json-servercontents.json
エンドポイントとなる json ファイルを作成します。
powershellmkdir api new-item api/contents.json作成した contents.json を編集します。
ここで編集した内容がAPIのレスポンスとして返されるようになります。contents.json{ "contents": [ { "id": 1, "title": "title - foo", "body": "body - bar", "author-id": 1 }, { "id": 2, "title": "title - foo2", "body": "body - bar", "author-id": 1 }, { "id": 3, "title": "title - bar", "body": "body - bal", "author-id": 2 } ] }package.json
package.json を更新します。
package.json{ "name": "mock-api", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", ### ↓↓↓↓↓ ここから追加 ↓↓↓↓↓ ### "json-server": "json-server --watch ./api/contents.json --port 5000" ### ↑↑↑↑↑ ここまで追加 ↑↑↑↑↑ ### }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "json-server": "^0.16.1" } }実行
npm run
コマンドで実行します。powershellnpm run json-server実行されると、以下にGET通信することで先ほどのcontents.jsonの内容が得られます。
http://localhost:5000/contents応用的な環境構築
エンドポイントを複数用意したい場合
エンドポイントを複数用意したい場合、contents.jsonにもう一つ要素を追加することで解決します。
contents.json{ "contents": [ { "id": 1, "title": "title - foo", "body": "body - bar", "author-id": 1 }, { "id": 2, "title": "title - foo2", "body": "body - bar", "author-id": 1 }, { "id": 3, "title": "title - bar", "body": "body - bal", "author-id": 2 } ], "authors": [ { "id": 1, "name": "hoge" }, { "id": 2, "name": "fuga" } ] }上記のように編集し実行すると、以下のように通信先を切り替えることができます。
http://localhost:5000/contents http://localhost:5000/authorsエンドポイント毎にファイルを分割したい場合
しかし、APIの規模が大きくなってくると単一ファイルではメンテナンスが難しくなってくることは想像に難しくありません。
そうなると「エンドポイント毎にファイルを分割したい」という欲求が生まれてきます。そこで問題となってくるのが json-server の「単一ファイルしか受け付けない」という仕様です。
なので、今回は複数ファイルを一つにマージすることで対応したいと思います。【参考】
- Json-serverでモックAPI(1) まず、マージをするためのスクリプトを用意します
powershellmkdir scripts new-item merge.jsscripts/merge.jsconst path = require("path"); const fs = require("fs"); const root = path.resolve("./", "api"); const update = () => { const api = fs.readdirSync(root).reduce((api, file) => { if (api === undefined) api = {}; if (path.extname(file) == ".json") { const endpoint = path.basename(file, path.extname(file)); if (api[endpoint] === undefined) api[endpoint] = {}; api[endpoint] = JSON.parse(fs.readFileSync(root + "/" + file, "utf-8")); return api; } }, {}); fs.writeFile(root + "/../merged.json", JSON.stringify(api), err => { if (err) throw err; }); } // 初回作成 update(); // jsonファイルを監視し, 監視ファイルに更新があるたびmerged.jsonを更新 fs.watch(root, (e, filename) => update());(2) json-server と merge.js を両方同時に動作させるために npm-run-all を導入します
powershellnpm i -D npm-run-all(3) package.json を更新します
package.json{ "name": "mock-api", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", ### ↓↓↓↓↓ ここから追加・更新 ↓↓↓↓↓ ### "json-server": "json-server --watch merged.json --port 5000", "merge": "node ./scripts/merge.js", "serve": "npm-run-all -p merge json-server" ### ↑↑↑↑↑ ここまで追加・更新 ↑↑↑↑↑ ### }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "json-server": "^0.16.1" } }(4) contents.json を contents.json と authors.json に分割します
powershellnew-item api/authors.jsoncontents.json{ "contents": [ { "id": 1, "title": "title - foo", "body": "body - bar", "author-id": 1 }, { "id": 2, "title": "title - foo2", "body": "body - bar", "author-id": 1 }, { "id": 3, "title": "title - bar", "body": "body - bal", "author-id": 2 } ] }authors.json{ "authors": [ { "id": 1, "name": "hoge" }, { "id": 2, "name": "fuga" } ] }(5) 以下のコマンドで実行します
powershellnpm run serveこれで複数ファイルに分割定義することが可能となります。
POSTやPUTでもレスポンスを受け取りたい場合
json-server は GET以外 のリクエストだと思ったようにレスポンスを返してくれないので、処理をフックして GET通信 に偽装します。
【参考】
- json-server で使い捨てモックサーバを作る
- JSON Serverを使ってGETとPOSTでレスポンスを変えてみた(1) まず、処理をフックするためのスクリプトを追加します
powershellnew-item ./scripts/middleware.jsmiddleware.jsmodule.exports = (req, res, next) => { if(req.method == 'POST') { req.method = 'GET' // GETに偽装 req.query = req.body } next() }(2) package.json を更新します
以下では、--middlewares オプションを追加しています。
package.json{ "name": "mock-api", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", ### ↓↓↓↓↓ ここから更新 ↓↓↓↓↓ ### "json-server": "json-server --watch merged.json --port 5000 --middlewares ./scripts/middleware.js", ### ↑↑↑↑↑ ここまで更新 ↑↑↑↑↑ ### "merge": "node ./scripts/merge.js", "serve": "npm-run-all -p merge json-server" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "json-server": "^0.16.1" } }これでPOST通信でもjsonレスポンスを得ることができます。
APIのrouteをカスタムしたい場合
現状、APIのrouteが http://localhost:5000/{jsonファイル名} となっているため、これを http://localhost:5000/api/v1/{jsonファイル名} となるように変更してみたいと思います。
【参考】
- Json-serverでモックAPI(1) まず、routes.json を追加します
powershellnew-item ./routes.jsonroutes.json{ "/api/v1/*": "/$1" }(2) package.json を更新します
以下では、--routes オプションを追加しています。
package.json{ "name": "mock-api", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", ### ↓↓↓↓↓ ここから更新 ↓↓↓↓↓ ### "json-server": "json-server --watch merged.json --port 5000 --routes ./routes.json --middlewares ./scripts/middleware.js", ### ↑↑↑↑↑ ここまで更新 ↑↑↑↑↑ ### "merge": "node ./scripts/merge.js", "serve": "npm-run-all -p merge json-server" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "json-server": "^0.16.1" } }これでhttp://localhost:5000/api/v1/{jsonファイル名}でアクセスできるようになります。
おわりに
さらに詳しくは 公式サイト をご参照ください。
- 投稿日:2020-05-15T11:59:42+09:00
JavaScript ページ内の文字列をすべて置換するコード
- 投稿日:2020-05-15T11:57:52+09:00
【JavaScript】わたし的「スッキリJS記法」集
はじめに
「こんな書き方もできるんだ!便利!」と感じた記法。
随時更新予定!プロパティを動的に生成する
プロパティ名をブラケットで括ることで、式の値から動的にプロパティ名を生成できる(Computed Propaty Names)。
※普通に書くとなぜか表示されないため、ブラケット部分コメントアウトしてます。sample.jslet i = 0; let todo = { month: new Date().getMonth(), date: new Date().getDate(), //['ToDo'+ ++i]: '買い物', //['ToDo'+ ++i]: '片付け', //['ToDo'+ ++i]: '掃除' }; console.log(todo);オブジェクト内のメゾット定義省略記法
sample.jslet member = { toString: function(){ // //..処理 }, } //省略記法 let member = { toString(){ //..処理 }, }return文の省略
sample.jsconst members = { name: "ハナコ" }; //return文を省略したとき const getName = (key) => members[key]; // 複数行で書いたとき // const getName = (key) => { // return members[key]; // }; const membername = getName('name'); console.log(membername); // 結果:ハナコ
- 投稿日:2020-05-15T11:31:35+09:00
JS初心者道場_ オブジェクトについて①
JavaScriptの
オブジェクト
を案件で使用することはあるのですが「つまりどういう物だ」ということを答えろと言われると困ってしまうし、使ってはいるけれどどのような場面で利用するのが適切なのかが曖昧なので、しっかり利用できるように細部まで調べてみます。オブジェクトを理解するとできるようになる(らしい)こと
- グローバルオブジェクトの意味が理解できるようになる
- メソッドを利用しているということがわかる
まず、オブジェクトとは
オブジェクトとは
「関連のあるデータと機能の集合です」
オブジェクトを使うことによって、データをまとめて扱えるようになります。宣言方法は以下の通り、中括弧{}を使用します。
// 宣言方法 {} // 型の確認 typeof {} // "object" // Objectは変数に格納できる const obj = {} // 例1 const person = {} // 例2プロパティとメソッド
「関連のあるデータと機能の集合です」の機能とは大抵は変数と関数のことです。
オブジェクトのなかでは、変数のことをプロパティ
、関数のことをメソッド
と呼んでいます。■プロパティ
オブジェクトが持つ変数(名前付きのデータ)のことを「プロパティ」と呼びます。
プロパティを設定するには、複数の宣言方法があります。個人的には①を初期値として宣言するときに使ったりしていましたが、
③のやり方でデータをひとまとめにして引数にするみたいな使い方もできそうです。
②は、変数の数が初期で予想できない時に使えるのかな、と予想しかできません。宣言方法①const obj = { name: "taro", gender: "male", age: 20 }宣言方法②const obj = {} obj.name = "taro"; obj.gender = "male"; obj.age = 20;宣言方法③const name = "taro"; const gender = "male"; const age = 20; const obj = { name, gender, age }メソッド
オブジェクトのプロパティには関数をセットすることもできます。
オブジェクトが持つ関数のことをメソッドと呼びます。メソッドの宣言const obj = { hello: function() { console.log('hello world') } } // 関数の実行 obj.hello(); // hello worldオブジェクトのプロパティを取り出す
オブジェクトのプロパティを取り出すには
.
(ドット) を使います。アクセス方法const obj = { name: "taro", gender: "male", age: 20 } console.log(obj.name); // taro console.log(obj.gender); // male console.log(obj.age); // 20
- 投稿日:2020-05-15T10:42:34+09:00
耳年齢判定ボットを改良(LINEで音声ファイルを再生)
概要
普段は耳鼻科の開業医をしています。
以前obnizeのスピーカーからモスキート音を出し加齢性難聴をチェックするLINE Botを作成しました。
耳年齢を判定するLINE Bot×Iotの作成今回、モスキート音をファイルに入れ、LINEで音声ファイルを再生できるようにしました。
作成方法
1.モスキート音を用意する
こちらを利用しました
Sine Tone Generator『File Generator』の
『Hz』をモスキート音の周波数に設定、『duration』は3秒とし『DOWNROAD.WAV FILE』をクリックするとダウンロードできます。
各周波数分用意します。2.publicフォルダを作ってwavファイルを設置
3.コードの追加
const config = { channelSecret: process.env.CHANNEL_SECRET, channelAccessToken: process.env.CHANNEL_ACCESS_TOKEN }; const app = express(); app.use(express.static('public')); //追加3.wavファイルのURLを動的に取得する
app.post('/webhook'......内の処理を書き換えるPromise .all(req.body.events.map(event=>handleEvent(event,req))) .then((result) => res.json(result));function handleEvent(event) { に引数を追加
function handleEvent(event, req) { console.log(req); if (event.type !== 'message' || event.message.type !== 'text') { return Promise.resolve(null); }メッセージ内にURLを入れる
let url; if (hz == 0) { url =""; } else if (hz == 8000) { url ="デプロイしたボットのURL/public/8000.wav"; } else if (hz == 10000) { url ="デプロイしたボットのURL/10000.wav"; } else if (hz == 12000) { url ="デプロイしたボットのURL/12000.wav"; } else if (hz == 14000) { url ="デプロイしたボットのURL/14000.wav"; } else if (hz == 15000) { url ="デプロイしたボットのURL/15000.wav"; } else if (hz == 16000) { url ="デプロイしたボットのURL/16000.wav"; }LINEで複数のメッセージを返信する
replyMessage(event.replyToken, [ { type: "text", text: "第一のメッセージ" }, { type: "text", text: '第二のメッセージ' } ])完成
- 投稿日:2020-05-15T09:59:29+09:00
Discord.jsでBotを作る【いろんな機能編その1】
この記事は、前回、前々回の記事の内容に準する記事になっています
前回、前々回の記事でBotの作り方、起動方法などを紹介しました。
今回は前々回の記事にもあった通り、Botにいろんな機能を作る方法、コードなどについて紹介しますまずは...
今度いろんなことに役立つjsonファイルについて紹介します。
jsonとは...
様々な言語で使える、テキストデータ保存に使えるファイルです(筆者何となくのイメージです。詳しくはググって())
まーつまり簡単なものの情報を保存しておけるもの、的な感じで覚えておけばいいと思います。
これはMySQLなどのデータベースを使ったデータ保存などの超絶初歩的な感じにもなるので、初心者にはお勧めです。はい。話長いですね。じゃあさっそく使っていこー
Botにプレフィックスを追加する
プレフィックスがわからない人へ
Botで機能を実行する際、基本的に特定のメッセージを送信するという感じになりますが、たとえばただpingだけだと、他のBotなど被ってしまったり、日常会話などをしている最中に実行してしまったりと、いろいろと不便が生じます。
そこで、プレフィックスを言うものをつくり、!!ping
(この!!の部分がプレフィックス)のようにすることで、他のBotとの干渉や誤動作を防げます。(肝心のプレフィックスがかぶってしまうと意味がないんですがね)では、index.jsがあるフォルダに
config.json
というファイルを作りましょう。
中のコードはconfig.json{ "prefix":"!!" }これは、
prefix
という名前で!!
という内容の文字列を作った、という感じです。
ほかのことにも使えるので、覚えておくといいかもそうしたらここに書いた内容をindex.jsで読み取れるようにしましょう。
index.js
のconst discord ・・・
と書いてあるところの近くにindexjsconst config = require('./config.json')これを追記しましょう。
これはconfig
というのはconfig.json
ファイルの内容のことだよ、と定義してる感じです。
これでさきほど追加したprefix
が使えるようになりました。
では使いましょう(?)
client.on('message', message =>{
の中にindex.jsif(message.content.indexOf(config.prefix) !== 0) return; const args = message.content.slice(config.prefix.length).trim().split(/ +/g); const command = args.shift().toLowerCase();を追加しましょう。
ここで注意なのが、前々回の記事に書いたような単語に単語する機能のコードの上にこれを書いてしまうと、動かなくなってしまします。前々回の記事の記事で言うとinde.jsif(message.content === "こんにちは"){ message.reply("こんにちは!") }この部分です。
なぜなら追加した分の一行目が、メッセージの中にプレフィックスがないのならばリターンする
というものだからです。
なのでこれを書く際には単語に反応するコードの下に書くようにしましょう続いて二行目の解説です。二行目は引数を取得するコマンドです。
(例)!!help a b c
これのa、b、cの部分がそれぞれ引数
これは今後引数を代入するコマンドなどに使います。
三行目は、プレフィックスの後にあるメッセージ
つまり
コマンド名を取得するところです。これでもしcommandが○○だったら
という分が書けるようになりますこれでやっとプレフィックスの追加は終わり。いえー
実際に機能、コマンドを追加する
今回は
ping
コマンドとsay
コマンドを追加します。
pingコマンドとは、Botの速度、つまり軽さをだすコマンドです。
sayコマンドは、Botに任意の文章を喋らせるコマンドです。
では作っていきましょう。さっき書いたところの下に
index.jsif(command === "ping"){ message.channel.send(` Ping を確認しています...`) .then((pingcheck) => pingcheck.edit(`botの速度|${pingcheck.createdTimestamp - message.createdTimestamp} ms`)) }これをコピペしましょう。
多少の誤差は出ますが、これでBotの速さを測定できます。
見ためはのようになっています
これでもうpingコマンドは完成です。次はsayコマンドを作ります
先ほどのpingコマンドの下にindex.jsif(command === "say"){ const say_message = args.join(" "); message.delete().catch(msg=>{}) message.channel.send(say_message); }これを追加しましょう
これでsayコマンドの実装は終わりです!
使い方は<prefix>say (喋らせたい物)
です
実際に使ってみるとこんな感じ
おわり
前々回の記事の内容と今回の記事の内容のコード全体はこのようになります
index.jsconst discord = require('discord.js'); const client = new discord.Client(); const config = require('./config.json') client.on('ready', () => { console.log('bot ready!'); }); client.on('message', async message =>{ if(message.content === "こんにちは"){ message.reply("こんにちは!") } if(message.content.indexOf(config.prefix) !== 0) return; const args = message.content.slice(config.prefix.length).trim().split(/ +/g); const command = args.shift().toLowerCase(); if(command === "ping"){ message.channel.send(` Ping を確認しています...`) .then((pingcheck) => pingcheck.edit(`botの速度|${pingcheck.createdTimestamp - message.createdTimestamp} ms`)) } if(command === "say"){ const say_message = args.join(" "); message.delete().catch(msg=>{}) message.channel.send(say_message); } }) client.login('TOKEN');config.json{ "prefix":"!!" }この記事を読んでくださいましてありがとうございました!
次はさらにいろんな機能を追加させる方法を書いておこうと思います!(もしかしたら抜けてるところとか間違えてるところがあるかもしれません。もしも間違えがあったらコメントなどで指摘してください)
- 投稿日:2020-05-15T09:32:00+09:00
誰でもわかるJavascript - bind編
Javascriptのbindの記事を読んでも、さっぱりわからないという人(自分)のために解説してみる。
bindの基本
以下のオブジェクトが定義されているとする。
const person = { age: 20, displayAge: function() { console.log(this.age); } };
person
オブジェクトを通してdisplayAge
関数を実行すると「20」が表示される。person.displayAge(); // 20
displayAge
関数を変数に代入して、実行すると何故か「undefined」が表示されてしまう。const newDisplayAge = person.displayAge; newDisplayAge(); // undefined
newDisplayAge
の中身を見てみると当然displayAge
関数が代入されている。
しかし、this
が何であるかわからない状態になっている。1this?console.log(newDisplayAge); // function() { console.log(this.age); }そこで
bind
関数を使うとthis
が何であるかを教えてあげることで正常に動作する。const bindDisplayAge = person.displayAge.bind(person); bindDisplayAge(); // 20bindの応用
bind
の第1引数にはthis
、それ以降の引数には関数に渡す引数が定義できる。
以下のコードではgreet
関数にthis
が使用されていない。
そのため、第1引数にはnull
渡し、第2引数でgreet
関数のname
引数に'taro'
を渡している。2const person = { greet: function(name) { console.log('hello ' + name); } }; const greetPerson = person.greet.bind(null, 'taro'); greetPerson(); // hello taroどういう時に使うのか
関数を実行したくないが、呼び出すだけで実行できる状態にしておきたいときに使う。
具体的な例としてボタンが押された時のイベントハンドラーにthis
や引数が使用されている場合、bind
が必要になる。const person = { age: 20, displayAge: function() { console.log(this.age); } }; const button = document.querySelector('button'); // 以下は想定の動作とは異なる。 button.addEventListener('click', person.displayAge()); // ページ読み込み後に'20'が表示 button.addEventListener('click', person.displayAge); // ボタンクリック時に'undefined'が表示 // 正常に動作する。 button.addEventListener('click', person.displayAge.bind(person)); // ボタンクリック時に'20'が表示
- 投稿日:2020-05-15T08:38:00+09:00
Deno 1.0.0 と Servest 1.0.0 で HelloWorld
Deno
- V8 を使用した Rust 製の JavaScript & TypeScript ランタイム
- ウェブブラウザの外で JS/TS を実行できるようにするもの
- Node.js みたいなもの
- Node.js の作者が作り直したもの (Node.js 設計の失敗 - Ryan Dahl)
asdf
インストール
git で
~/.asdf
に落としてきて最新化git clone https://github.com/asdf-vm/asdf.git ~/.asdf cd ~/.asdf git checkout "$(git describe --abbrev=0 --tags)"
.bash_profile
か.zshrc
に以下を追加してシェルを再起動. $HOME/.asdf/asdf.shDeno のパッケージを入れる
asdf plugin-add deno https://github.com/asdf-community/asdf-deno.git asdf install deno 1.0.0 asdf global deno 1.0.0
Deno Helloworld
公式サンプルそのままで、見た目普通の js に見えるけど、①
package.json
とか作らなくていいし、②npm
は使わないし (標準ライブラリを https で読んでる)、③await
もasync
で囲わなくていいみたいなのが読み取れる。index.jsimport { serve } from "https://deno.land/std@0.50.0/http/server.ts"; for await (const req of serve({ port: 8000 })) { req.respond({ body: "Hello World\n" }); }実行は
deno run hoge
。今時のセキュリティも考慮しているのでネットワークアクセスにはフラグが必要。deno run --allow-net index.js
interpreter
インタープリタもあるよ
% deno Deno 1.0.0 exit using ctrl+d or close() > console.log('Yo') Yo undefined > const yo = 'Yo' undefined > yo Yo >Servest で動かす (React/tsx)
Servest は Deno 向けの http サーバー。
https://servestjs.org/
作者:https://keroxp.me/
Deno 1.0.0 に追従するように Servest も 1.0.0 に対応した。?これも Servest の公式サンプルそのままですみません。
React/tsx が普通に動く。
パッケージは https 経由で指定できるので npm install 不要 (node_modules が作られない)。
Router とかも実装されているので実践で使えてしまえそう。index.tsx// @deno-types="https://servestjs.org/@v1.0.0/types/react/index.d.ts" import React from "https://dev.jspm.io/react/index.js"; // @deno-types="https://servestjs.org/@v1.0.0/types/react-dom/server/index.d.ts" import ReactDOMServer from "https://dev.jspm.io/react-dom/server.js"; import { createApp } from "https://servestjs.org/@v1.0.0/mod.ts"; const app = createApp(); app.handle("/", async (req) => { await req.respond({ status: 200, headers: new Headers({ "content-type": "text/html; charset=UTF-8", }), body: ReactDOMServer.renderToString( <html> <head> <meta charSet="utf-8" /> <title>servest</title> </head> <body>Hello Servest!</body> </html>, ), }); }); app.listen({ port: 8899 });そのまま実行
deno run --allow-net index.tsx
かんそう
- JS/TS エンジニアは Node.js からドンドコ移行しそう
- マスコットかわいいので流行りそう
- チンアナゴかと思ってた
- 投稿日:2020-05-15T08:18:33+09:00
お絵かきできるSNSを作りたい!7
線の太さを実装していきたいと思います。
前回同様、今度は[type="range"]の値を取得し、lineWidthに入れるだけです。
<input type="range" value="1" min="1" max="10" step="1" oninput="LineWidth(this)"> <output id="LineWidthValue">1</output>pixel//線の太さ用変数(デフォルトは1px) var strLineWidth="1"; function LineWidth(obj){ document.getElementById('LineWidthValue').value=obj.value; strLineWidth=obj.value; }最後に
ct.lineWidth=strLineWidth;↑ここだけだと伝わらないと思うので↓のgithubの差分をを参照ください。
- 投稿日:2020-05-15T08:04:55+09:00
お絵かきできるSNSを作りたい!6
カラーパレッドを実装していきたいと思います。
このままでも良いのですが、好きな色を追加出来る用にもした方がいい気がしてきたのでその他というパレットも用意します。
その他:<input type="color" id="color_other" name="color" onChange="Color(this);">onchageイベントを付与しました。
JavaScriptやjQueryでバインドしても良いのですが、それだと後からどの要素にイベントが入っていたか分かりにくいので直接書く派です。前回作った色の四角形を選択した時に枠線を付けているColorという関数があったので、それを改造します。
//カラー設定用変数(デフォルトは黒) var strStrokeStyle="#000000"; //カラー選択関数 function Color(obj){ for ( i = 1; i <= 15; i++ ) { id_name = "color_" + i; if (id_name == obj.id){ id_name2 = "#" + id_name; document.getElementById(id_name).classList.add('active'); } else { document.getElementById(id_name).classList.remove('active'); } } if (obj.id == "color_other"){ strStrokeStyle = $("#color_other").val(); } else { strStrokeStyle = "#" + $(id_name2).css("background-color").match(/\d+/g).map(function(a){return ("0" + parseInt(a).toString(16)).slice(-2)}).join(""); } }追加したのはid_name2変数の追加と↓以下の部分です。
if (obj.id == "color_other"){ strStrokeStyle = $("#color_other").val(); } else { strStrokeStyle = "#" + $(id_name2).css("background-color").match(/\d+/g).map(function(a){return ("0" + parseInt(a).toString(16)).slice(-2)}).join(""); }その他を押した時は、タグのidが”color_other”なので[type="color"]の値を取得・それ以外の場合は選択した四角形の背景色を取得しています。
type="color"は、そのままだと10進数のRGB表記だったので、上と揃えようと思い16進数表記への変換も行っています。
ここに来てjQueryが無い事に気が付き追加しました。
3系で問題無いのですが、古参なのでIEも考慮し1系で。
color関数の上のfor文はjQueryなら数行で収まるはずですが、この程度のループなら速度的にも影響ないかなそのままにしました。そして、最後にグローバルなstrStrokeStyle変数に格納した情報をcanvasのgetContextでstrokeStyleが取得出来る用にします。
ct.strokeStyle=strStrokeStyle;
- 投稿日:2020-05-15T05:20:40+09:00
ページ遷移はどうするの?
ページ遷移ってどうするの?
あれ?ルーターがなくない?
今までReactを書いていてそろそろサーバーサイドレンダリングに手を出した私、よしポートフォリオサイトを作ってやろ!と考えたわけですよ!ここである問題が発生!あれ、Reactのときはページ切り替えはruterを使ってたけど...NextってRuterないやんけどうするんや〜!
いや安心してくださいませ〜
別にないわけではないです。
NextではRuterを使わなくてもページ繊維なんてちょちょいのちょいで行えるのです!
(あ!ReactでRuterを使うときはnpm install ruter
でルーターが使えるようにしてimportしてからでないと 使えませんので〜)npmとかのコマンドはまたどこかで説明するとして、話が逸れてしまったので本題に行ってみましょう!じゃあ実際にどうすればいいの?
話は意外と簡単です!
Nextのアプリケーションは基本的にpageディレクトリ内に様々なファイルを記述しますが、そこにある.jsファイル、つまりページコンポーネントにimport Link form 'next/link'
と記述しましょう。これでNextで作成した各ページのjsファイルを遷移できるようになりました。あとはリンクを配置します。ページコンポーネントに以下のように記述します。~.jsexport default () => ( <Layout header ="Top page" title ="Top page."> <p>Welcome to Next.js</p> <Link href ="./other"> <button>Go to Other >></button> </Link> </Layout> );とりあえず現在のページタイトルとかはtoppageとかにしといて遷移先のページのjsファイルの名前をother.jsとすると
<Link href = "./other"> </Link>
と言うように記述することでハイパーリンクが完成し、画面に表示されるようになります。つまり...<Link href = " 遷移先のjsファイルの名前(.jsはいらない) "> ここにボタンやテキストを入力する (ex)<p>,<h3>,<button>,もしくは生テキスト.... </Link>以上!これでNextにおける画面遷移はご理解いただけたでしょうか?
あ!忘れていました!今回のトップページはindex.jsとしていますが、もし遷移先にother.jsから戻るための画面遷移がしたいと思えばohter.jsの方でが上記のようなもの書きます。しかし、この時に遷移先がトップページであれば、href = "./index"
と記述せずhref = "/"
で行うことができます!覚えておきましょう!
- 投稿日:2020-05-15T02:13:29+09:00
Google maps APIでピンにドラゴンボールの情報を埋め込んでみよう!
はじめに
- 複数のピンの立て方のおさらい
- 情報を付け加える方法1
- 情報を付け加える方法2
- 最後に
複数のピンの立て方のおさらい
私の一個前の記事に複数のピンの立て方が掲載されていますので、そちらを参照してください。
Google maps APIで複数のドラゴンボールの場所にピンを立てよう! - Qiita今回は立てたピンに情報を付け加えていきたいと思います。前回同様、複数のピンを目標としますのでfor文をうまく活用していきたいと思います。
Htmlは前回のままです。
maps.html<html> <head> <meta charset=“UTF-8”> <title>map</title> <link rel=“stylesheet” href=“css/style.css”> </head> <body> <div id=“map”></div> <script src=“js/map.js”></script> <script src=“data/place.json”></script> <script src=“https://maps.googleapis.com/maps/api/js?key=AIzaSyBZUNbx_85VM6LurRVIHZcxl-7Vg3O2C9g&callback=initMap” async defer></scriptsrc>></script> </body> </html>Cssも前回と同様です。
style.cssbody { height: 100%; width: 100%; } #map { height: 100%; width: 100%; }情報を付け加える方法1
ここまでは前回と同じですが、JSONの方から改善していきたいと思います。JSONにその場所の紹介文を載せておきたいと思います。今回は全てtestとしておきます。
place.jsonvar place_data = [ { “Loc”: “バンナ公園”, “lat”: 24.375031, “lng”: 124.160795, “balloon”: “test” }, { “Loc”: “石垣島鍾乳洞”, “lat”: 24.361743, “lng”: 124.154466, “balloon”: “test” }, { “Loc”: “石垣やいま村”, “lat”: 24.40489, “lng”: 124.144636, “balloon”: “test” } ]情報を付け加える方法2
次にJavaScriptの変更です、前回とは異なりmarkerの情報を保存するリストとウィンドウの情報を保存するリスト二つを用意します。
map.jsvar map; var marker = []; var infowindow = []; var Center = {lat: 24.4064, lng: 124.1754}; function initMap() { map = new google.maps.Map(document.getElementById(‘map’), { center: Center, zoom: 11.5 }); markerset() }; function markerset(){ for(var i=0;i<place_data.length;i++) { marker[I] = new google.maps.Marker({ position: {lat: place_data[I].lat, lng: place_data[I].lng}, map: map, title: place_data[I].loc }); infowindow[I] = new google.maps.InfoWindow({ content: ‘<div class=“mapsballoon”><h2>’ + place_data[I].loc + ‘</h2>’ + place_data[I].balloon + ‘</div>’ }); markerEvents(i) } } function markerEvents(i) { marker[I].addListener(‘click’, function() { infowindow[I].open(map, marker[I]); }); }このように書くことで、for文でmarker・infowindowにそれぞれ値を格納していくことができます。addListenerメソッドをしようすることで、クリックしたときにinfowindowが表示されるようにすることができます。
最後に
いかがだったでしょうか?前回の予告通りピンに情報を付け加える方法を紹介しました。次回はピンを表示する際の工夫を施していこうと思います。
参考文献
https://developers.google.com/maps/documentation/javascript/examples/event-simple
- 投稿日:2020-05-15T01:30:58+09:00
Google maps APIで複数のドラゴンボールの場所にピンを立てよう!
はじめに
- ピンの立て方のおさらい
- for文で回してピンを立てる
- JSONからデータを取得する
- 最後に
ピンの立て方のおさらい
私の一個前の記事にピンの立て方までが乗っていますので、そちらを参照してください!
Google maps APIでドラゴンボールのある場所にピンを立てよう!! - Qiita今回は複数のピンの立て方について解説していきます。複数のピンを立てる際に、一個ずつ立てるのもいいですがそれだと効率が悪いです。ですのでfor文をしようして効率よくピンを立てていきたいと思います。
HTMLは前回のままです。
maps.html<html> <head> <meta charset=“UTF-8”> <title>map</title> <link rel=“stylesheet” href=“css/style.css”> </head> <body> <div id=“map”></div> <script src=“js/map.js”></script> <script src=“https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap” async defer></scriptsrc>></script> </body> </html>Cssも前回と同じです。
style.cssbody { height: 100%; width: 100%; } #map { height: 100%; width: 100%; }for文で回してピンを立てる
今回はJavaScriptでピンを複数立てる操作をしていきます。
map.jsvar map; var marker; var place_data = [ { “Loc”: “バンナ公園”, “lat”: 24.375031, “lng”: 124.160795, }, { “Loc”: “石垣島鍾乳洞”, “lat”: 24.361743, “lng”: 124.154466, }, { “Loc”: “石垣やいま村”, “lat”: 24.40489, “lng”: 124.144636, } ] var Center = {lat: 24.4064, lng: 124.1754}; function initMap() { map = new google.maps.Map(document.getElementById(‘map’), { center: Center, zoom: 11.5 }); marker() }; function marker(){ for(var I=0;i<place_data.length;i++) { marker = new google.maps.Marker({ position: {lat: place_data[I].lat, lng: place_data[I].lng}, map: map, title: place_data[I].loc }); } }Markerというファンクションを作成しその中でfor文で回します。place_dataという配列を作成しその中に位置情報・場所の名前を記入しておきます。あとはfor文でmarkerを立てていくだけです。
JSONからデータを取得する
先ほどはJavaScriptの配列の中に位置情報や場所の名前を入れていましたが、今後のことを考えてjson の方にデータを移してJavaScriptとつなげたいと思います。
place.jsonvar place_data = [ { “Loc”: “バンナ公園”, “lat”: 24.375031, “lng”: 124.160795, }, { “Loc”: “石垣島鍾乳洞”, “lat”: 24.361743, “lng”: 124.154466, }, { “Loc”: “石垣やいま村”, “lat”: 24.40489, “lng”: 124.144636, } ]JSONの方でこのように書き込むとJavaScriptでスムーズにJSONと接続することができます。あとはhtmlでscriptを追加するだけです。
maps.html<html> <head> <meta charset=“UTF-8”> <title>map</title> <link rel=“stylesheet” href=“css/style.css”> </head> <body> <div id=“map”></div> <script src=“js/map.js”></script> <script src=“data/place.json”></script> <script src=“https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEYg&callback=initMap” async defer></scriptsrc>></script> </body> </html>これだけで簡単にJSONと接続することができます。これからたくさんのピンを立てたいと考えたときは、やはりJSONでデータを分けた方がいいと思いますのでこちらで書いたほうがいいでしょう。
最後に
いかがだったでしょうか?前回の予告通り複数のピンを立てる方法を紹介しました!次回はこのピンに情報を埋め込む方法を紹介したいと思います!
- 投稿日:2020-05-15T00:57:46+09:00
JavaScriptで空の配列を判別する方法
個人的にすごく詰まったので、メモとして残しておく。
JavaScriptでは条件式の中に比較演算子がない場合、要素によって真偽判定が行われるが、文字列などとは異なり、配列では空の場合でもTrueと判定されてしまう。
scriptconst name_string = "" //空の文字列 console.log(Boolean(name_string)) //False const name_list_1 = [] //空の配列 const name_list_2 = [1] //要素のある配列 //配列の要素の有無にかかわらずTrueを返してしまう console.log(Boolean(name_list_1)) // True console.log(Boolean(name_list_2)) // Trueそのため、配列に要素が入っているか判定する場合には、配列の長さを求める.lengthを用いて行う。
scriptconst name_list_1 = [] //空の配列 const name_list_2 = [1] //要素のある配列 //配列が空のときFalseを返すようになった console.log(Boolean(name_list_1.length)) // False console.log(Boolean(name_list_2.length)) // True
- 投稿日:2020-05-15T00:46:31+09:00
javascriptとjqueryって何が違うの?
javascriptとjquery
プログラミングスクールで学んだ事を思い返しているとふと疑問が起こった。
「javascriptとjqueryって何が違うんだ?」
学んだ当初はよく理解出来ていないまま、がむしゃらにコードを書いていたのもあって僕の中で
jquery = javascriptのもう1つの名称
という何ともいい加減な式を頭に思い浮かべたまま卒業まで行ってしまった。
さすがに知識を曖昧なままにしてはいけないと思ったので簡単に説明していく。
まだ未熟なので説明が間違っているかもしれないがご容赦願いたい。
jquery = javascriptのライブラリ
そもそもライブラリって何だという話だが
ライブラリとは汎用性の高い複数のプログラムを再利用可能な形でひとまとまりにしたものであり
簡単に言うと「jqueryとはjavascriptで開発を行うのを簡単にするものである」
もっと簡単に言えば「jqueryとはjavascriptでよく使う機能や効果のあるコードを簡潔に再編成したものである」
どういうことかと言えばjavascriptで10行くらいコードを記述しなければいけない時に
jqueryを使えば1,2行に短縮できたりする。
つまりとても簡単で便利にjavascriptを使えるのである。
注意点
いくら便利だと言ってもjqueryにも弱点はある
1.読み込みが遅くなることがある
jqueryは複数のブラウザで使えるものだが、それゆえいくつものブラウザ判定や分岐が行われている。
つまり本来必要のない処理まで実行してしまっているのでその分動作が重くなってしまうのである。
2.jquery独自の書き方がある
javascriptを簡潔に書き直している形なのでjquery独自の命令文があり
javascriptを使うときにjqueryの記述を行うとエラーが出てしまう事がある。
それでも便利なjquery
とはいえjqueryは記述が簡単になるのでコードを書くときも見直すときも負担が少なくなり大変便利でなものである。
最初からjqueryを勉強するのもいいがjavascriptを勉強してからの方がもっと体系的に理解できるそうだ。
好きな勉強方法でjqueryを使いこなせるようになろう!
- 投稿日:2020-05-15T00:35:32+09:00
Google maps APIでドラゴンボールのある場所にピンを立てよう!!
はじめに目次
- Google maps APIの取得
- まずは地図を表示しよう!!
- ピンを立ててみよう!
- 最後に
Google maps APIの取得
まず取得するには、Googleアカウントとクレジットカードが必要になります。
詳しくはここをご覧になってください。
https://qiita.com/Haruka-Ogawa/items/997401a2edcd20e61037まずは地図を表示してみよう!!
APIを取得したら、早速地図を表示してみましょう!
地図を表示するには、HTML,CSS,JavaScriptが必要になります。一応全てをHTMLで書くことができますが、
今後のことを考えて分けて書くようにします。まずはHTMLです。map.html<html> <head> <meta charset="UTF-8"> <title>map</title> <link rel="stylesheet" href="css/style.css"> </head> <body> <div id="map"></div> <script src="js/map.js"></script> <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap" async defer></script> </body> </html>YOUR_API_KEYのところをあなたが取得したAPIに置き換えましょう!次はJavaScriptです。
今回は私が石垣島出身なので地図の中心の座標は石垣島にしたいと思います。map.jsvar map; var Center = {lat: 24.4064, lng: 124.1754}; function initMap() { map = new google.maps.Map(document.getElementById('map'), { center: Center, zoom: 11.5 }); }JavaScriptで表示するマップの中心座標や拡大サイズなどを変更します。今回はその二つのみ指定していますが、それ以外にもピンを立てる場所やピンに記載する情報、経路の表示などを設定することができます。
次は、cssでmapのサイズを決めていきます。style.cssbody { height: 100%; width: 100%; } #map { height: 100%; width: 100%; }今回は画面全体をマップにするので縦・横共に100%ととしています。
これでマップを表示する準備が整いました。早速htmlを開いてみましょう!
このような感じで表示することができます!
ピンを立ててみよう!
地図が表示できましたがこれではまだ面白くないので、手始めにピンを立ててみましょう。
map.jsvar map; var marker; var Center = {lat: 24.4064, lng: 124.1754}; function initMap() { map = new google.maps.Map(document.getElementById('map'), { center: Center, zoom: 11.5 }); marker = new google.maps.Marker({ position: Center, map: map, title: "石垣島" }); };ピンを立てるにはMarkerメソッドを使います。position,地図を表示する場所,markerのタイトルを決めます。今回は中心と同じ座標を使っています。表示してみるとこんな感じです。
無事ピンを立てることができました!
最後に
いかがだったでしょうか?私自身初めて地図を表示するときは何度もうまくいかず、あきらめかけたものです。そう言った人が少しでも減るようにこの記事を書きました。また、複数のピンを立てたり、経路の表示の仕方は追々書いていきたいと思います。
参考文献
https://developers.google.com/maps/documentation/javascript/examples/event-simple
- 投稿日:2020-05-15T00:31:09+09:00
洋数字が1桁の時は全角、2桁以上の時は半角にするツール
初めに
会社の文章のポリシーで洋数字が1桁の時は全角、2桁以上の時は半角にするというルールがありました。
いちいち手作業で直していると時間の無駄なのでツールを作りました。簡単な仕様
- 洋数字が1桁の時は全角、2桁以上の時は半角
- 数字に挟まれた
,
.
:
/
は半角に変換- 数字の間に
,
.
:
/
があって2桁以上なら半角
- (例)1,000、5/5、1:30 などは半角
簡単な設計
- 最初に数字を全て半角にする
- 1桁の数字を全角に変換
- 前後の数字だけでなく
,
.
:
/
にも注意する- 文頭は改行前の値を気にしない
- 文末も次の段落の頭の文字を気にしない
- etc...
ソースコード(javaScript)
初めに変数、hanに半角洋数字を、zenに全角洋数字を代入
var han = "0123456789";
var zen = "0123456789";フォームから送られてきた値を変数textに挿入
var text = document.henkan.mytext.value;全ての数字を一度半角に変換
for文で、変数textの文字数処理を行う
text.charAt(i)
で文字を取得- 上で取得した文字を、indexOfで変数
zen
に格納されている全角数字があるか探す。- あれば
n = zen.indexOf(c,0);
で変数zen
の何番目の文字に該当するか調べ変数n
に代入、なければ0
を代入if (n >= 0)
で検索しても、あれば、han.charAt(n);
で変数han
の何番目かを調べ、それに変換し、変数c
に代入。- 変数
c
の値を変数str
に入れていくvar str = ""; for (i=0; i<text.length; i++){ c = text.charAt(i); n = zen.indexOf(c,0); if (n >= 0){ c = han.charAt(n); str += c; }else{ str += c; } }数字に挟まれた
,
.
:
/
は半角に変換※以下の
(\d+?)●(\d+?)
の●の部分は全角ですstr = str .replace(/(\d+?)/(\d+?)/g, "$1"+"/"+"$2") .replace(/(\d+?).(\d+?)/g, "$1"+"."+"$2") .replace(/(\d+?),(\d+?)/g, "$1"+","+"$2") .replace(/(\d+?):(\d+?)/g, "$1"+":"+"$2");1桁の数字は全角に
※以下の
var CONV_TABLE = ["0","1","2","3","4","5","6","7","8","9"];
の洋数字は全角str = str.replace(/(^|(?:[^0-9.,:/]))([0-9])((?![0-9.,:/])|$)/g, function(m) { var CONV_TABLE = ["0","1","2","3","4","5","6","7","8","9"]; var s, n; if (m.length == 1) { s = ""; n = CONV_TABLE[parseInt(m)]; } else { s = m.charAt(0); n = CONV_TABLE[parseInt(m.charAt(1))]; } return s + n; });ユーザーが視覚的に数字の全角半角を確認できるようにする
- 変数
str_chk
を作り、ユーザーが確認できるように一桁洋数字には赤、2桁(記号含む)以上には青色で画面に返す※以下の2行目の
str_chk = str_chk.replace(/([0-9]{1})/g, "<span class=\"bkred\">"+"$1"+"</span>");
の洋数字は全角ですstr_chk = str str_chk = str_chk.replace(/([0-9]{1})/g, "<span class=\"bkred\">"+"$1"+"</span>"); str_chk = str_chk.replace(/([0-9]+)([.,:/]{1})([0-9]+)([.,:/]{1})([0-9]+)/g, "<span class=\"bkblue\">"+"$1$2$3$4$5"+"</span>"); str_chk = str_chk.replace(/([0-9]+)([.,:/]{1})([0-9]+)/g, "<span class=\"bkblue\">"+"$1$2$3"+"</span>"); str_chk = str_chk.replace(/(\d{2,})/g, "<span class=\"bkblue\">"+"$1"+"</span>"); var text = new String; text = '<div style="font-weight:bold;">■<span style="color:red;">1桁</span>の洋数字は<span style="color:red;">赤</span> <span style="color:blue;">2桁以上</span>は<span style="color:blue;">青</span>で表示されます。</div>'; document.henkan.mytext.value = str; str_chk = str_chk.replace(/\r\n|\n/g, '<br>'); document.getElementById('preview').innerHTML = str_chk; document.getElementById('kome').innerHTML = "↓ココをコピーして使って下さい" ;
- 投稿日:2020-05-15T00:27:55+09:00
json api形式のスネークケースのレスポンスをキャメルケースにする[jsona]
スネークケースのレスポンスをキャメルケースにしたい
背景
フロントエンド側でapiつなぎこみ作業していて、
サーバーからのレスポンスがスネークケースで、
そのままフロント側で使うとeslintエラーになる。。。
そこでスネークケースをキャメルケースに手動で変換する。。。 ← これがめんどい、なんとかしたい対処
こんな感じのレスポンスが来たとする
{ "data": { "id": "1", "type": "movie", "attributes": { "name": "test movie", "year": null, "is_released": true, "director_name": "hoge" } } }まず、jsonaというライブラリを使って、扱いやすい形にする
import axios from 'axios' import Jsona from 'jsona' const dataFormatter = new Jsona() const getData = async () => { try { const response = await axios.get('/data') console.log(dataFormatter.deserialize(response)) } catch (error) { console.log(error) } } // console.logの結果 { type: 'movie', id: '1', name: 'test movie', year: null, is_released: true, // ここと director_name: 'hoge' // ここをキャメルケースにしたい }jsonaのオプションにいい感じのがある
jsonaの初期化時にオプションとして、SwitchCaseJsonMapperを下のように渡せば良いimport Jsona, { SwitchCaseJsonMapper } from 'jsona const dataFormatter = new Jsona({ jsonPropertiesMapper: new SwitchCaseJsonMapper({ switchChar: '_' }) })こうすることで先ほどのconsole.logの結果が、下のようにキャメルケースになる
{ type: 'movie', id: '1', name: 'test movie', year: null, isReleased: true, directorName: 'hoge' }