- 投稿日:2021-03-29T23:05:32+09:00
if文〜JS〜
今回は関数とif文について学習していきます!!
まず、関数の前にif文について学習していきます。if文について
if文とは条件分岐のときに使います。
main.jsif (条件式){ trueだったときの処理 } else if (条件式){ falseだったときの処理 } else { どちらにも当てはまんなかったとき }上記のように流れていきます。
では、実際にプログラムを書いていきましょう。
まず、変数か定数を定義します。
Jsでは、変数はlet,定数はconstを宣言します。前の記事でも学習しましたが、変数は入れ替えができますが定数は変更することができないので注意しましょう、1つのプログラムを書く中では変数ではなく定数を極力使うようにしましょう!!main.jsconst score = 10; if (score >= 80) { document.write("よくできました"); } else if (score >= 60) { document.write("半分取れました!!更に頑張りましょう!!"); } else { document.write("頑張れよ"); }定数constに10点を代入します。基準10点になります。
ここで、if文で条件式をかきます。
①scoreが80点以上だったら
②scoreが60点以上だったら
③全てに当てはまらなかった場合
の条件式をかきます。console.logではなく、今回はdocument.writeでブラウザに表示するようにしました。
ただ、この、if分でもいいのですが、長いので省略しちゃいましょう?main.jsscore >= 80 ? document.write("よくできました") : document.write("半分取れました!!更に頑張りましょう!!")となります!!
- 投稿日:2021-03-29T22:40:35+09:00
結局Webpackってなんのためにあるの?
はじめに
JavaScript(フロントエンド)を始めてぶち当たるのがWebpack, Babelだと思います。(僕はぶち当たりました)
この記事ではWebpackの使い方ではなく、「Webpackって結局なんのためにあって、あるとなんで嬉しいのか」についてを書きます。
もし、間違っている、追記すべきことがあれば編集リクエストなどで教えていただけると幸いです。Webpackの役割
Webpackは下の記事にもある通り、モジュールバンドラーと呼ばれるものです。
Webpackについて全く知らないよって人はこの記事を読んでみると何をするものかはイメージがつくと思います。
簡単に説明すると、Webpackは複数のJavaScriptファイルを1つにまとめてくれるものです。(JavaScriptファイル以外にもCSSとか画像ファイルもできます)
複数の
script
タグじゃだめなの?HTMLには複数の
script
タグを埋め込むことができ、複数のJavaScriptファイルを読み込むことができます。例えば、以下のようなコードがあるとします。
index.html<!DOCTYPE html> <html> <head> <title>Sample Page</title> </head> <body> <script src="greets.js"></script> <script src="output.js"></script> </body> </html>greets.jsconst japanese = 'こんにちは';output.jsconsole.log(japanese);この場合、ブラウザのコンソールには
こんにちは
と出力されます。
greets.js
が先に読み込まれ、その後にoutput.js
が読み込まれており、output.js
内のjapanese
変数にはこんにちは
が入っているためです。しかし、
index.html
が以下のような場合はどうでしょうか。index.html(変更後)<!DOCTYPE html> <html> <head> <title>Sample Page</title> </head> <body> <script src="output.js"></script> <script src="greets.js"></script> </body> </html>
output.js
とgreets.js
の順番が逆になっています。
この場合、outputs.js
のjapanese
変数はまだ定義されていないため、コンソールにundefined
が出力されます。次に、それぞれのファイルで同じ変数名を定義した場合を見てみましょう。
index.html<!DOCTYPE html> <html> <head> <title>Sample Page</title> </head> <body> <script src="greets1.js"></script> <script src="greets2.js"></script> <script src="output.js"></script> </body> </html>greets1.jsvar japanese = 'こんにちは';greets2.jsvar japanese = 'Konnichiwa';output.jsconsole.log(japanese);この場合、コンソールには
Konnichiwa
が出力されます。
これは、ブラウザにはネームスペースが1つしかないため、greets1.js
が読み込まれ、定義されたjapanese
をgreets2.js
が読み込まれたときに代入(上書き)されてしまうためです。(大人の事情により、const
じゃなくてvar
を使ってます。気になる方はJavaScriptのvar
の性質を調べてみると、あ〜となります。)なにが言いたいのかというと、複数のJavaScriptファイルをロードする際には、読み込む順番や同じ変数名を使っていないかを確認する必要があるということです。
これを数十、数百ファイルで行うのは人間には不可能だと思います。そこで出てくるのがWebpackです。
Webpack
を使うとどうなるの?Webpackを使うことで、複数のscriptタグでJavaScriptファイルをロードするときに気をつけなければならないことを気にする必要がなくなります。
実際にWebpackを使った場合を見てみましょう。
greets.jsconst japanese = 'こんにちは'; export default japanese;index.jsimport japanese from './greets'; console.log(japanese);簡単に説明すると、
index.js
でgreets.js
のjapanese
変数をインポートして、それをコンソールに出力しています。
このgreets.js
とindex.js
をWebpack
で1つのファイルにまとめるとこのようになります。main.js(()=>{"use strict";console.log("こんにちは")})();見やすくすると、
main.js(見やすくしたもの)(() => { "use strict"; console.log("こんにちは") })();
console.log("こんにちは")
となっていることがわかります。
Webpackがimport / export
を解析し、必要なもの(今回の場合はjapanese
)を見つけ出し、コードを生成してくれているおかげで、JavaScriptファイルを読み込む順番を考える必要がなくなりました。違うファイルで同じ変数名がある場合はどうでしょうか。
牛丼のテイクアウトの料金を出す
takeout.js
とイートインの料金を出すeatin.js
を例にしたコードを考えます。takeout.js
とeatin.js
のコードは以下のようになりました。takeout.jsconst gyudon = 350; const tax = 1.08 export default gyudon * tax;eatin.jsconst gyudon = 350; const tax = 1.1 export default gyudon * tax;index.jsimport takeout from './takeout'; import eatin from './eatin'; console.log('takeout', takeout); console.log('eatin', eatin);
script
タグで読み込んだ場合、変数名(gyudon
,tax
)が同じなため、上書き or エラーになりますが、Webpackだとどうでしょうか。
実際に、Webpackでまとめたコードは以下です。main.js(()=>{"use strict";console.log("takeout",378),console.log("eatin",385.00000000000006)})();例のごとく、見やすくします。
main.js(見やすくしたもの)(() => { "use strict"; console.log("takeout", 378), console.log("eatin", 385.00000000000006) })();ちゃんとテイクアウト、イートインでの料金が計算されていることがわかります。
これは、Webpackがファイルごとにネームスペースを区切っているため、異なるファイルで同じ変数名を使っても混ざることなくコードが生成されます。気をつけなければならないことがなくなったので、複数の
script
タグを使ってJavaScriptファイルをロードするときに比べ、開発がしやすくなったのではないでしょうか。まとめ
Webpackを使う前は、ブラウザのネームスペースが1つしかなく、複数の
script
タグを使うとロードの順序や変数名を気にして開発しなければなりませんでした。しかし、Webpackを使うことによってネームスペースの問題や、ロードの順序を気にする必要がなくなり、開発がしやすくなります。
規模の小さい場合だと、恩恵をあまり受けることができないかもしれませんが、規模が大きくなってくると確実にWebpackの恩恵を受けることができると思います。今回はWebpackのお話でしたが、モジュールバンドラーにはRollupなどもあるので、そちらも見てみると良いかもしれません。
また、WebpackはJavaScriptだけでなく、CSSや画像などもまとめることができるので、それに挑戦してみたりすると、よりWebpackについて知れると思います。おまけ
最近のブラウザだと以下のようにモジュールに対応しているものがあります。
(「ESModule ブラウザ」とかで調べると出てきます)実際にコードを書くと以下のようになります。
index.html<!DOCTYPE html> <html> <head> <title>Sample Page</title> </head> <body> <script src="index.js" type="module"></script> </body> </html>index.jsimport japanese from './greets.js'; console.log(japanese);greets.jsconst japanese = 'こんにちは'; export default japanese;ただ、現段階ではWebpackなどのモジュールバンドラーを使ってバンドルするのが無難だと僕は思います。
リンク
- 投稿日:2021-03-29T22:20:20+09:00
konva.js で地図を描く (2)
前回の続き
次はkonvaのいろんな図形を使って、簡易的な地図を描いていきますグループの生成
画像や図形たちをグループ化します
sample.jsvar group = new Konva.Group({ x: 10, y: 10 });作った要素をこのグループに追加していく
軌跡の描画
line のオブジェクトを使って描画
lineは[x0, y0, x1, y1, x2, y2 .....] という座標を指定して、そのポイントを結ぶ線を描きますconvasの座標は
左上が(0,0)右下が(200, 200) (例:canvasのサイズが200pxの時)
なので、左上を始点にして
- x(正の方向)→ 右側にlineが描かれる (負の時は逆)
- y(正の方向)→ 下側にlineが描かれる (負の時は逆)
lineを描く例
今回は各lineのポイントごとにクリックイベントなど拾えるように、各区間ごとに線を描いていきますsample.js// [x,y]の座標が詰まった配列 var table = [[3,10],[5,20],[10,50],[30,60],[50,80],[80,100],[100,100],[110,120],[120,150],[150,170]]; for (let i = 1; i < table.length; i++) { var prevX = table[i-1][0]; var prevY = table[i-1][1]; var currentX = table[i][0]; var currentY = table[i][1]; console.log(i, px, py, cx, cy); var line = new Konva.Line({ points: [prevX, prevY, currentX, currentY], stroke: '#696969', strokeWidth: 3, lineCap: 'round', lineJoin: 'round', id: `line_${i}` //lineごとにidをふれる }) line.on('mouseup', (e) => { console.log(e.currentTarget.attrs.id); //クリックした時にid取得できる }); group.add(line); }スタート地点とゴール地点を用意
今回はスタート地点を○、ゴール地点を☆で生成
sample.jslet start = new Konva.Circle({ x: table[0][0], //配置場所 y: table[0][1], //配置場所 radius: 10, fill: 'red', stroke: 'black' }); group.add(start) //作った要素はgroupに追加 let goal = new Konva.Star({ x: table[table.length-1][0], //配置場所 y: table[table.length-1][1], //配置場所 numPoints: 5, innerRadius: 7, outerRadius: 15, fill: 'yellow', stroke: 'black' }); group.add(goal) //作った要素はgroupに追加最後描画する
sample.jslayer.add(group); // 最後groupをlayerにaddする stage.add(layer); // layerをstageにaddする layer.draw(); // 描画結果
こんな感じのmapができる
さらにアニメーションをつけたり、各要素にクリックイベントつけたりなど、簡単にできるので便利でした!
注意点
groupにaddする時は、addする順番で描画されるため、順番が重要(後から追加されたものが上にくる)
layerを分けて、zIndexを設定することで上にくる要素を変更できる
- 投稿日:2021-03-29T22:18:53+09:00
konva.js で地図を描く (1)
konva.jsとは
- konva.js
- デスクトップやモバイルアプリケーション向けの2Dキャンバスライブラリ
- 図形や画像を描画したり、アニメーションしたり、イベントリスナーをつけたりなどが簡単にできる
今回はこのkonva.jsを使って簡易的な地図を描いた内容をまとめます
html側
samle.html<html> <head> <meta charset="utf-8" /> </head> <body> <div id="canvas-container"></div> </body> </html>html側はdivを用意するだけ
ライブラリ読み込み
スクリプトタグに以下埋め込み
<script src="https://unpkg.com/konva@7.0.3/konva.min.js"></script>
or
npm install konva
or
公式サイトからダウンロード
js側の実装
konva.jsの構造
公式サイトより引用
Stage <--- (1)divのidを取得してstageを用意 | +------+------+ | | Layer Layer <--- (2)layerを用意 | | +-----+-----+ Shape <--- (3)要素を用意。複数ある場合はグループ化できる | | Group Group | | + +---+---+ | | | Shape Group Shape | + | Shapesample.js// (1) divのidを取得してstageを用意 const stage = new Konva.Stage({ container: 'canvas-container', //親要素のdivタグのidを指定 width: 200, //キャンバスの横幅 height: 200 //キャンバスの高さ }); // (2)layerを用意 const layer = new Konva.Layer(); // (3)要素を用意。まずはマップの枠(四角)を用意 const box = new Konva.Rect({ x: 0, //配置場所 y: 0, //配置場所 width: 200, //横幅 height: 200, //高さ fill: "#ffffff", //塗り潰しの色 stroke: "#000", //枠線の色 strokeWidth: 1, //枠線の太さ opacity: 1, //透過率 cornerRadius: [3, 3, 3, 3] //四角の角を丸める }); layer.add(box); //作った四角をlayerにadd stage.add(layer); //layerをstageにadd (階層の上に順番に追加していく) layer.draw(); //これで描画結果
まずこれで四角がcanvasに描かれる
(内部的にはこんな感じでdivの中にcanvasが生成されている)result.html<div id="canvas-container"> <div class="konvajs-content" role="presentation" style="position: relative; user-select: none; width: 200px; height: 200px;"> <canvas width="400" height="400" style="padding: 0px; margin: 0px; border: 0px; background: transparent; position: absolute; top: 0px; left: 0px; width: 200px; height: 200px; display: block;"> </canvas> </div> </div>
- 投稿日:2021-03-29T22:17:29+09:00
Jest mockClear(), mockReset(), mockRestore() の違い
Jest の
mockClear()
,mockReset()
,mockRestore()
の違いが分かりづらいのでまとめておく。
またjest.clearAllMocks()
,jest.resetAllMocks()
,jest.restoreAllMocks()
もすべてのモックが対象になるだけで挙動としては同じ。
mockClear()
mockFn.mock.calls
,mockFn.mock.instances
を初期化する。const now = () => Date.now(); describe('mock example', () => { const mockedDateNow = jest.spyOn(Date, 'now').mockReturnValue(0); it('mockClear', () => { now(); mockedDateNow.mockClear(); // calls, instances はすべて初期化されている expect(mockedDateNow.mock.calls.length).toBe(0); expect(mockedDateNow.mock.instances.length).toBe(0); // mockReturnValue の設定は初期化されていない expect(now()).toBe(0); }); });
mockReset()
mockFn.mock
,mockFn.mock.calls
,mockFn.mock.instances
を初期化する。
またmockImplementation
,mockReturnValue
等で設定した実装、戻り値もすべてリセットされる。const now = () => Date.now(); describe('mock example', () => { const mockedDateNow = jest.spyOn(Date, 'now').mockReturnValue(0); it('mockReset', () => { now(); mockedDateNow.mockReset(); // calls, instances はすべて初期化されている expect(mockedDateNow.mock.calls.length).toBe(0); expect(mockedDateNow.mock.instances.length).toBe(0); // mockReturnValue の設定も初期化されている expect(now()).not.toBe(0); }); });
mockRestore()
jest.spyOn
によって作成されたモックをオリジナルのものへ戻す。const now = () => Date.now(); describe('mock example', () => { const mockedDateNow = jest.spyOn(Date, 'now').mockReturnValue(0); it('mockRestore', () => { now(); mockedDateNow.mockRestore(); // mockRestore() により Date.now がモックでなくなっている expect((Date.now as any).mock).toBe(undefined); }); });
- 投稿日:2021-03-29T22:03:22+09:00
Deno Deployをやってみた
ツイッター見てたら流れてきたのでやってみた
Deno Deployとは?
Deno Deploy is a distributed system that runs JavaScript, TypeScript, and WebAssembly at the edge, worldwide. The service deeply integrates the V8 JavaScript runtime with a high performance asynchronous web server to provide optimal performance without unnecessary intermediate abstractions.
https://deno.com/deploygoogle翻訳
Deno Deployは、 JavaScript、TypeScript、およびWebAssembly を世界中のエッジで実行する 分散システム です。このサービスは、 V8 JavaScriptランタイムを高性能非同期Webサーバーと緊密に 統合して、不要な中間抽象化なしで最適なパフォーマンスを提供します。
どうやら今日発表されたDeno用の公式ホスティングサービス(?)のようです!
githubに限らず、web上にあるJavaScriptとTypeScriptのコードからサーバーが建てられると。
公式ドキュメントはこちらに。まだベータ版のようですが、さっそく試しに使ってみたいと思います。
① プロジェクト名を決める
ここで入力した名前が初期ドメインになります。(後から変更可能)
② githubでリポジトリを作成
今回は試すだけなので、リクエストヘッダをそのままJSONで返すサーバーを建ててみたいと思います。
新しいリポジトリを作成して、公式ドキュメントを参考にコードを書きます。③ githubのURLをコピペ
「githubからデプロイ」と「URLからデプロイ」の2種類あるみたいですが、ここではgithubからデプロイを選んで、URLをコピペしてきます。
③ githubと連携させる
githubアプリと連携しますか?みたいなダイアログが出てくるので、許可します。
④ デプロイ完了
デプロイしたプロジェクトには、「Visit」というリンクから飛べます。
ここまで10分弱ですが、無事デプロイできました!
こちらで公開中です。料金は…?
こちらのページにある通り、ベータ期間中は無料で使用でき、ベータ期間が終わると、詳細な価格が発表されるとのこと。
最後に、公式ドキュメントからDeno Deployの特色を引用して終わります。(google翻訳)
- Web上に構築:ブラウザーと同じように、fetch、WebSocket、またはURLを使用します
- TypeScriptおよびJSXの組み込みサポート:タイプセーフコード、およびビルド手順なしの直感的なサーバー側レンダリング
- Web互換のESモジュール:明示的なインストールを必要とせずに、ブラウザーと同じように依存関係をインポートします
- GitHubの直接統合:ブランチにpushし、デプロイされたプレビューを確認し、margeして本番環境にリリースします
- 非常に高速:1秒未満で展開し、ユーザーの近くでグローバルにサービスを提供
- URLからデプロイ:URLだけでコードをデプロイします
- CloudflareWorkers®と互換性のあるAPI:既存の大規模なエコシステムの恩恵を受けられます
- 投稿日:2021-03-29T21:36:50+09:00
Ajaxを簡単に実装するための覚え書き
Ajaxで何か送信するときのための覚え書き
var req = new XMLHttpRequest(); req.onreadystatechange = function() { if (req.readyState == 4) { // 通信の完了時 if (req.status == 200) { // 通信の成功時 } }else{ // 通信中の処理 } } req.open('POST', '送信先URL', true); req.setRequestHeader('content-type','application/x-www-form-urlencoded;charset=UTF-8'); req.send('hoge=&example=');
- 投稿日:2021-03-29T21:30:56+09:00
通話機能 OverconstrainedError Deviceidの解決方法
はじめまして、プログラミング初心者のコージです。今回はデバイス選択通話機能を実装するうえで苦労したOverconstrainedError Deviceidの解決方法を忘備録として残しておきます。
苦労したとはいってもコードの改変はたった1行です笑call.jslet audioId = $('#audioSource').val(); let videoId = $('#videoSource').val(); let constraints = { audio: {deviceId: {exact: audioSource}}, <-ここの記述を変更 video: {deviceId: {exact: videoSource}}call.jslet audioId = $('#audioSource').val(); let videoId = $('#videoSource').val(); let constraints = { audio: { deviceId: audioId <-exactを削除 }, video: { deviceId: videoId <-exactを削除 }まさかこれだけで3日苦しんだエラーが解決するとは、、、?
Chromeでこの形式で指定できるようになったのはごく最近らしいです。上が以前の指定形式らしい。
古いから制約に引っ掛かるのかな?全てのコードを見たい方はgithubのapp->javascriptからどうぞ
ビデオ通話機能を実装したwebアプリケーションのコード: circlefriends以上
twitter: @siron_www 日常のこともつぶやいてるので友達感覚でフォローしてください?
- 投稿日:2021-03-29T21:04:51+09:00
kintone上でWebSpeechAPIを利用して音声認識して文字起こしする【改良編】
本記事を読むにあたっての注意点
本記事は前回のkintone上でWebSpeechAPIを利用して音声認識して文字起こしする【動作確認編】で作ったものを実装するために改良した部分の紹介と、Web Speech APIの感想をまとめたものです。
まだ読んでいらっしゃらない方はそちらを先に読んでいただければ幸いです。コード全文
※紹介しきれなかったコードも含まれます。
全文表示する
(function () { "use strict"; kintone.events.on(["app.record.edit.show", "app.record.create.show"], function (event) { // start,stop ボタン生成 const startButton = document.createElement("button"); startButton.innerText = "録音開始"; startButton.id = "start-btn"; startButton.className = "recognition-buttons"; const stopButton = document.createElement("button"); stopButton.innerText = "録音終了"; stopButton.id = "start-btn"; stopButton.className = "recognition-buttons"; // 文字起こし用<textarea>作成 const tempForm = document.createElement("textarea"); tempForm.id = "temp_input"; //tempForm.type = "text"; tempForm.cols = "150"; tempForm.rows = "10"; tempForm.innerText = "(録音開始ボタンをクリックで音声受付を開始します)"; //tempForm.style.resize = "none"; kintone.app.record.getSpaceElement('form_space').appendChild(tempForm); // // cautionフィールドにメッセージを追加 const cautionElem = document.createElement("p"); cautionElem.innerHTML = `・録音受付中はブラウザのタブに赤い丸ボタンが出現し点滅します。録音終了ボタン押下または一分放置すると録音が自動終了します。<br> ・録音終了後に句読点や改行を付けるなどの編集が可能です。<br> ・保存ボタンを押すと、音声受付フィールドの値が清書後フィールドに転記又は上書きされます。` cautionElem.id = "caution-p"; kintone.app.record.getSpaceElement('caution').appendChild(cautionElem); // Web Speech API の設定 (SpeechRecognitionクラス) const SpeechRecognition = webkitSpeechRecognition || SpeechRecognition; const recognition = new SpeechRecognition(); recognition.lang = "ja-JP"; recognition.interimResults = true; recognition.continuous = true; let resultString = ""; recognition.onresult = (event) => { let intermString = ""; for (let i = event.resultIndex; i < event.results.length; i++) { let transcript = event.results[i][0].transcript; if (event.results[i].isFinal) { resultString += transcript + " "; } else { intermString = transcript; } } document.getElementById("temp_input").value = resultString + "<" + intermString; }; // 録音ボタンの処理、ボタンの設置 startButton.onclick = () => { // 録音開始時のみメッセージを表示 tempForm.innerText = "(音声を受け付けています)"; recognition.start(); }; stopButton.onclick = () => { recognition.stop(); }; kintone.app.record.getSpaceElement('buttonSpace').appendChild(startButton); kintone.app.record.getSpaceElement('buttonSpace').appendChild(stopButton); return event; }); // 保存実行前に一時保存から取得してフィールドに移す。 kintone.events.on("app.record.edit.submit", function (event) { // 音声入力しなければbreak let inputVal = document.getElementById("temp_input").value; if (inputVal === "" || inputVal.slice(0, 8) === "(録音開始ボタン") return event; let str = document.getElementById("temp_input").value; str = str.slice(0, -1); event.record.newField.value = str; return event; }); // 一覧画面では<button>と<textarea>のスペースを非表示にする kintone.events.on("app.record.detail.show", function () { document.getElementsByClassName("control-etc-gaia control-spacer-field-gaia ")[0].style.display = "none"; document.getElementsByClassName("control-etc-gaia control-spacer-field-gaia ")[1].style.display = "none"; document.getElementsByClassName("control-etc-gaia control-spacer-field-gaia ")[2].style.display = "none"; }); })();Web Speech API(speech recognition)の感想
良い点:無料で利用可能で認識自体が高性能。学習コストも低い。
悪い点:単語登録が出来ないのと、ブラウザのサポート範囲がまだ狭い。
結論 :マルチな機能にはなれないが、単発で使うのには十分な性能。前回時点での課題点
- 各イベント処理(kintone.events.on)を追加して機能させる
- 音声入力アウトプット用フィールドを一行から複数行にする
- 録音前と録音開始時にメッセージを表示する
- 音声入力をしないで保存した場合に空白("")で上書きされるのを止める
- レコード詳細表示画面で表示される余計なスペースフィールドを非表示にする
改良後イメージ
1.各イベント処理(kintone.events.on)を追加して機能させる
こちらは単純。レコード編集と、追加イベントで処理したいので前回に加えて
"app.record.create.show"を配列で追加。kintone.events.on(["app.record.edit.show", "app.record.create.show"], function (event) {2.音声入力アウトプット用フィールドを一行から複数行にする
前回は音声入力のアウトプットに<input>要素を使っていたが、<textarea>に変更。
innerText で録音開始前のメッセージも追加。// 文字起こし用<textarea>作成 const tempForm = document.createElement("textarea"); tempForm.id = "temp_input"; tempForm.cols = "150"; tempForm.rows = "10"; tempForm.innerText = "(録音開始ボタンをクリックで音声受付を開始します)"; //tempForm.style.resize = "none"; kintone.app.record.getSpaceElement('form_space').appendChild(tempForm);3.録音前と録音開始時にメッセージを表示する
(録音前のメッセージは 2.で実装済。)
録音開始時なので、Button.onclick()時にデフォルト指定。// 録音ボタンの処理、ボタンの設置 startButton.onclick = () => { // 録音開始時のみメッセージを表示 tempForm.innerText = "(音声を受け付けています)"; recognition.start(); };4.音声入力をしないで保存した場合に空白("")で上書きされるのを止める
こちら分かりづらいですが、<textarea>の値が "" 又はデフォルトの"(録音開始ボタン..."だった場合に returnすることで不要な上書きを防ぐことが可能です。
// 保存実行前に一時保存から取得してフィールドに移す。 kintone.events.on("app.record.edit.submit", function (event) { // 音声入力しなければreturn let inputVal = document.getElementById("temp_input").value; if (inputVal === "" || inputVal.slice(0, 8) === "(録音開始ボタン") return event; let str = document.getElementById("temp_input").value; str = str.slice(0, -1); event.record.newField.value = str; return event; });5.レコード詳細表示画面で表示される余計なスペースフィールドを非表示にする
kintone JavaScript APIの標準機能ではスペースは非表示にすることが出来ません。しかし気持ちが悪いのでDOM操作で実現してしまいました。(実装は自己責任で)
【Before】
【After】
// 一覧画面では<button>と<textarea>のスペースを非表示にする kintone.events.on("app.record.detail.show", function () { document.getElementsByClassName("control-etc-gaia control-spacer-field-gaia ")[0].style.display = "none"; // 録音ボタン設置用スペースフィールド document.getElementsByClassName("control-etc-gaia control-spacer-field-gaia ")[1].style.display = "none"; // <textarea>設置用スペースフィールド });
- 投稿日:2021-03-29T19:12:01+09:00
JavaScriptで文字列を逆順にする方法
- 投稿日:2021-03-29T18:07:23+09:00
[JS] Class
classの初期化
constructor関数
constructor( )はclassが初期化されるタイミングで必ず呼ばれる関数です
new演算子
初期化を行います
初期化する作業を「インスタンス化」と言います
このコードだと
class TextAnimation { constructor(el) { alert(el); } } new TextAnimation('hello world');初期化されたタイミングでhello worldをalertします
thisを使ってnew演算子を使って初期化を行なった変数に格納することができます
この場合のthisはtaを表しますclass TextAnimation { constructor(el) { this.el = el; } } const ta = new TextAnimation('hello world'); alert(ta.el);thisというプロパティに値を格納することによって
初期化した後の変数に値を格納したり、メソッドを格納したりすることができます
値を格納して(this.el = el;)、その値をメソッド内で使用することができる(console.log(this.el);)のがclassという演算子の利点です
class TextAnimation { constructor(el) { this.el = el; } log() { console.log(this.el); } } const ta = new TextAnimation('hello world'); ta.log();
classを使ってリファクタリング
document.addEventListener('DOMContentLoaded', function () { const el = document.querySelector('.animate-title'); const el2 = document.querySelector('.animate-title-2'); const str = el.innerHTML.trim().split(""); const str2 = el2.innerHTML.trim().split(""); let concatStr = ''; for(let c of str) { c = c.replace(/\s+/, ' '); concatStr += `<span class="char">${c}</span>`; } el.innerHTML = str.reduce((acc, curr) => { curr = curr.replace(/\s+/, ' '); return `${acc}<span class="char">${curr}</span>`; }, ""); el2.innerHTML = str2.reduce((acc, curr) => { curr = curr.replace(/\s+/, ' '); return `${acc}<span class="char">${curr}</span>`; }, ""); });これを
document.addEventListener('DOMContentLoaded', function () { const ta = new TextAnimation('.animate-title'); const ta2 = new TextAnimation('.animate-title-2'); }); class TextAnimation { constructor(el) { this.el = document.querySelector(el); this.chars = this.el.innerHTML.trim().split(""); this.el.innerHTML = this._splitText(); } _splitText() { return this.chars.reduce((acc, curr) => { curr = curr.replace(/\s+/, ' '); return `${acc}<span class="char">${curr}</span>`; }, ""); } }こう書ける
_splitTextのように、先頭にアンダーバーがついているメソッドをPrivate Methodと呼び、
constructorのように何もついていないメソッドをPublic Methodと呼ぶことがある_splitTextは、classの中以外で使わないでくださいという意味になります
実際はclass外でも使えますが、開発者同士のコミュニケーションの一環ですclassとオブジェクト
classとobjectの記述
const obj = { first_name: 'Shun', last_name: 'Sato', printFullName: function() { console.log('hello'); } } class MyObj { constructor() { this.first_name = 'Shun'; this.last_name = 'Sato'; } printFullName() { console.log('hello'); } } const obj2 = new MyObj(); obj.printFullName(); obj2.printFullName();
obj2にはprintFullNameメソッドが確認されないが
__proto__ というプロパティに格納されています
__proto__はブラウザが独自に設定しているプロパティですobj.printFullName(); obj2.__proto__.printFullName();丁寧にこう書いても結果は同じになりますが、省略できる設定にデフォルトでなっているので書かなくてもOKです。
- 投稿日:2021-03-29T16:51:42+09:00
【Vue.js + TypeScript】autonakaでフリガナを自動的に別フィールドに入力させる
はじめに
- Vue.js + TypeScriptを使い、ユーザー名入力フォームなどで日本語入力をした際に、自動で別フィールドにふりがなorフリガナを入力できるようにしました。
実装コード
<template lang="pug"> label 氏名 input#last_name(name='last_name' type="text" placeholder="山田" @input="handleLastNameInput") input#first_name(name='first_name' type="text" placeholder="一郎" @input="handleFirstNameInput") label フリガナ input#last_name_furigana(name='last_name_furigana' type="text" placeholder="ヤマダ") input#first_name_furigana(name='first_name_furigana' type="text" placeholder="イチロウ") </template> <script lang="ts"> import { Component, Prop, Vue } from 'vue-property-decorator'; import * as AutoKana from 'vanilla-autokana'; let autokanaLastName: any; let autokanaFirstName: any; @Component export default class Hoge extends Vue { @Prop() userInfo!: { first_name: string, last_name: string, first_name_furigana: string, last_name_furigana: string }; mounted() { autokanaLastName = AutoKana.bind('#last_name', '#last_name_furigana', { katakana: true }); autokanaFirstName = AutoKana.bind('#first_name', '#first_name_furigana', { katakana: true }); } handleFirstNameInput() { this.userInfo.first_name_furigana = autokanaFirstName.getFurigana(); }; handleLastNameInput() { this.userInfo.last_name_furigana = autokanaLastName.getFurigana(); }; } </script> <style lang="scss"> </style>
- 投稿日:2021-03-29T14:21:48+09:00
スマホでも100vhを安定させる方法
はじめに
コンテンツの高さを100vhで指定した時に、pcだと問題なくても、スマホだとレイアウトが崩れることがある。
原因は、アドレスバーやキーボードなどがviewportの高さを圧迫してしまうから。
この記事では、スマホでも100vhを維持してレイアウトを崩さない方法をjsを使ってご紹介したいと思います。ウィンドウの高さを取得して、min-heightで指定する
height:100vh;
では、高さが可変してしまいますが、min-heightで指定してあげれば、それ以下のサイズになることはありません。index.jslet sp_height = window.innerHeight; document.documentElement.style.setProperty("--sp_height", `${sp_height}px`);まず、1行目の記述でスマホの画面高を
window.innerHeight
で取得して、変数sp_height
に代入します。取得した高さsp_height
は、2行目の記述で、scssの変数--sp_height
に代入します。index.scss.sp_height{ height: 100vh; min-height: var(--sp_height); }scssで、
var(--sp_height);
とプロパティの値に記述することで、jsとリンクさせることができます。
無事、min-heightが設定できました。まとめ
min-heightを指定することで、アドレスバーやキーボードによってviewportが圧迫されたとしても、ウィンドウの高さ分はコンテンツの最低高として確保されるのでレイアウトが崩れる心配がありません。100vh指定は、スマホだと表示崩れなどが懸念されますが、回避策はいくつかあると思いますので今回記事で紹介した内容も一つの対策として、皆様の参考になれば幸いです。
- 投稿日:2021-03-29T13:56:27+09:00
機能検出、機能推論、UA文字列の利用の違いは何ですか?
Front-end-Developer-Interview-Questionsの内容についてひとつひとつ考えていく。
今回はJS Questionsから、「What's the difference between feature detection, feature inference, and using the UA string?」について。
Feature Detection
機能検出のはなし?(MDNの和訳がそうなっている)
下記MDNより。あるブラウザーがあるコードのブロックに対応しているかどうかを調べ、対応しているか (またはしていないか) に応じて異なるコードを実行することで、ブラウザーが常に動作し、ブラウザーによってクラッシュやエラーが発生しないようにします。
Geolocation API (ブラウザーを実行している端末の位置情報を返します)は、 Navigator オブジェクトに含まれる geolocation プロパティを主なエントリーポイントとして持っています。
そこで、以下のようにしてブラウザーが位置情報機能に対応しているかどうかを検出できます。if ("geolocation" in navigator) { navigator.geolocation.getCurrentPosition(function(position) { // Google Maps API を用いて現在位置をマップ上に表示します }); } else { // 位置情報がなくてもマップを表示できるようにします }ただし、機能検出のためのコードを毎回自分で書くよりも、確立された既存の機能検出ライブラリを使うほうが良いとのこと。
この用途では Modernizr が一般に利用されています。
Feature Inference
機能の推論。
xが存在する場合、yが存在すると見なす機能の推論では、1つの機能を検出したため、他の機能を使用できると想定しています。たとえば、geolocation APIを検出した場合、ユーザーが最新のブラウザーを使用していると想定しているため、LocalStorageが利用可能になります。
if (navigator.geolocation) { // geolocation possible.. do some stuff } if('localStorage' in window){ window.sessionStorage.setItem("this-should-exist-too", 1); }推論はあんまりよくない。
利用したい機能ごとに機能検出を使用し、機能が利用できない場合に備えてフォールバック戦略を立てる方がよい。UA String
MDN曰く
ユーザーエージェントを調べるのが良いことはめったにありません。問題を解決するには、もっと良い、もっと広く互換性のある方法が見つかるはずです。
あまりやらない方がよさそうですね。
var userAgent = window.navigator.userAgent; // 例えばChromeを使ってると // userAgent: Mozilla/5.0 (windows nt 6.3; wow64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36 // 調べ方 var userAgent = window.navigator.userAgent.toLowerCase(); // 基本的にはこれでOKらしい if(userAgent.indexOf('msie') != -1) { console.log('お使いのブラウザはInternet Explorerですね!'); }ただしChromeのユーザエージェント文字列に「safari」が入っていたり、
Edgeのユーザエージェント文字列に「Chrome」も「safari」も入っていたりするらしいので、
Edge→Chrome→safariの順で一致をみないといけなさそう。
参考URL
- 投稿日:2021-03-29T13:31:54+09:00
[JavaScript] いつものタグ入力UIを、少し簡単にするTagify
Tagify
2021年のトレンドになっているらしいのでやってみた。
ドキュメント
公式
GitHub
サンプル
See the Pen Tagify by ハタユウジ@コーポレートエンジニア (@shikumiya_hata) on CodePen.
html<p> <label for='tags'>1. テキストボックス内にタグ</label> <input id="tags" name='tags' value='javascript, ライブラリ' autofocus> </p> <p> <label for='tagsOutside'>2. テキストボックスの外にタグ</label> <input id='tagsOutside' name='tags-outside' class='tagify--outside' value='javascript, ライブラリ' placeholder='タグを書くのもwhitelistから選択もできる'> </p> <p> <label for='tagCustom'>3. 見た目カスタマイズ</label> <input id="tagCustom" class='customLook' value='javascript, ライブラリ'><button type="button">+</button> </p>※CSSは長いので省略
js/* 1. テキストボックス内にタグ */ var inputInside = document.querySelector('input[name=tags]'); var tagifyInside = new Tagify(inputInside); /* 2. テキストボックスの外にタグ */ var inputOutside = document.querySelector('input[name=tags-outside]'); var tagifyOutside = new Tagify(inputOutside, { whitelist: ['javascript', 'js', 'ライブラリ', 'library'], //デフォルトで選択可能なタグ候補 dropdown: { position: "input", enabled : 0 } }); /* 3. 見た目カスタマイズ */ var inputCustomLook = document.querySelector('.customLook'), tagify = new Tagify(inputCustomLook, { dropdown : { position: 'text', enabled: 1 } }), button = inputCustomLook.nextElementSibling; button.addEventListener("click", onAddButtonClick) // +ボタン押下時 function onAddButtonClick(){ tagify.addEmptyTag() // 新しいタグを追加 }ちなみに、valueを取り出すとこんな風になってます。
value[ {"value":"javascript"}, {"value":"ライブラリ"} ]
- 投稿日:2021-03-29T11:25:09+09:00
vuexのgettersでstateをフィルタリングする方法
stateにあるJSONデータ、もしくはactionsで持ってきたデータをフィルタリングする方法。
今回はそもそもバックエンド側でフィルタリングしようねという話になったので、自分の環境では使用しなかった。
でもせっかく組んだし、もったいないので共有します(あんまり使い道は無いだろうけど・・・)export const getters = { getFilteringList: (state) => (query) => { // queryの形式を[{key:'',value:''}...]に変換する let conversion = Object.entries(query).map(([key, value]) => ({'key': key, 'value': value})) // 条件に合致したデータを返す関数を定義(every関数なので、全てに合致する必要がある) function isMatchToAllConditions(data, conditions){ return conditions.every(c => data[c.key] == c.value) } // null以外の要素を取り出す const conditions = conversion.filter(q => q.value && q.key) // フィルターをかける const searched = state.data.filter(list => { return isMatchToAllConditions(list, conditions) }) // 出力 return searched } }getFilteringListにはコンポーネント側でqueryを投げてあげる必要がある。
- 投稿日:2021-03-29T11:13:44+09:00
firebase-admin を用いて最も単純な Firebase Cloud Firestore のデータを取得するコードサンプル
動機
Firestore のデータを取得する単純な事例があまり見当たらず、本家の資料を見てもいまいちピンとこなかったので、
firebase-admin
を使った最も単純なコードを書きたくなったため。実行環境と利用ツール
- Ubuntu 20.04.2.0 LTS (Focal Fossa)
- Node.js
- バージョンは 14.16.0
- Firebase Admin SDK
Cloud Firestore 設定
まずはじめに Firebase コンソール(Web)から
books
コレクションと自動 ID を割り振ったドキュメントを作成します。内容は極めて単純にしたかったので string 型の
title
というフィールドのみ追加します。最後、値は
javascript
としています。完成形の画面のスナップショットを貼っておきます。
コレクション内のドキュメントを取得する最も単純なコード
// Ref : https://www.freecodecamp.org/news/the-firestore-tutorial-for-2020-learn-by-example/ const admin = require('firebase-admin'); const serviceAccount = require('./firestore-data-modeling-96db0-firebase-adminsdk-n3i63-0670471cc1.json'); admin.initializeApp({ credential: admin.credential.cert(serviceAccount) }); const db = admin.firestore(); const booksRef = db.collection('books'); // console.log(booksRef.get()); booksRef .get() .then((snapshot) => { const data = snapshot.docs.map((doc) => ({ id: doc.id, ...doc.data(), })); console.log(data); // [ { id: 'FY7PJJTw7EsS8x2hYphv', title: 'javascript' } ] });実行結果
コード中にも記載がありますが JSON オブジェクトの配列を返します。
$ node books.js [ { id: 'FY7PJJTw7EsS8x2hYphv', title: 'javascript' } ]参考資料
The JavaScript + Firestore Tutorial for 2020: Learn by Example
- 投稿日:2021-03-29T11:09:36+09:00
「;」や「\n」のあるなしで処理が変わるんだと実感した話
この記事で解決できるかもしれないエラー
SyntaxError: Unexpected identifier
JavaScriptだと珍しくないエラーのようです。Blocklyを使っている時にこのエラーが出た際はこの記事が参考になるかもしれません。プログラムの流れ
ブロックを作成するファイル
Blocklyを使ってLOGOのようなビジュアル言語を作成しています。
ブロックの定義はこんな感じ
turtleBlock.jsBlockly.Blocks['turtleforward'] = { init: function() { this.appendDummyInput() .appendField("前に") .appendField(new Blockly.FieldNumber(0, -10, 10), "step") .appendField("進む"); this.setPreviousStatement(true, null); this.setNextStatement(true, null); this.setColour(60); this.setTooltip(""); this.setHelpUrl(""); } };実行されたの動きはこんな感じ
turtleBlock.jsBlockly.JavaScript['turtleforward'] = function(block) { var number_step = block.getFieldValue('step'); var fowardCode = `TurtleForward(${number_step})`; return fowardCode; };
- 引数の数字を読み取る
- 別の場所で定義されている
TurtleForward()
を実行するためにforwardCode
を定義return
で渡す実行するファイル
turtleBlock.js
から値を受け取り、実行します。turtleCommand.jsTurtleForward = (value) => { console.log('実行された'+value); var code = 'TurtleForward(turtle,'+value+')'; ggbApplet.evalCommand(code); }実際の挙動
ブロックを並べて実行すると
画像のような挙動が確認されます。
しかし、ブロックを繋げて実行すると
上述したエラーが出てしまいます。
解決方法
タイトルにもありますが、ブロックの定義の際に
;
や\n
をつけていないことが原因でした。試しにブロックによって作成されるコードを表示させてみるとTurtleForward(1)TurtleForward(1)定義されている
TurtleForward()
を認識することができず、エラーを起こしてしまうようです。turtleBlock.jsBlockly.JavaScript['turtleforward'] = function(block) { var number_step = block.getFieldValue('step'); console.log(number_step+'進む'); var fowardCode = `TurtleForward(${number_step})\n`; //変更点 return fowardCode; };あるいは
turtleBlock.jsBlockly.JavaScript['turtleforward'] = function(block) { var number_step = block.getFieldValue('step'); console.log(number_step+'進む'); var fowardCode = `TurtleForward(${number_step});`; //変更点 return fowardCode; };のように
\n
、;
を定義された関数を文字列として扱ったものを最後に入れることでエラーを解決することができました。;
- 投稿日:2021-03-29T10:55:24+09:00
JavaScriptでDropbox APIから画像を読み込む
とりあえず動いた喜びと感動とメモ帳書きとして
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>Dropbox Test</title> <script src="https://unpkg.com/dropbox/dist/Dropbox-sdk.min.js"></script> </head> <body> <h1>Dropbox Test</h1> <script> let accessToken = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; let dbx = new Dropbox.Dropbox({accessToken: accessToken}); let dir_path = "/Photos" dbx.filesListFolder({path: dir_path}) .then(function (response) { imageLoad(response); }) .catch(function (error) { console.error("error " + error); }); function imageLoad(json) { let n = json.result.entries.length; for(let i = 0;i<n;i++) { let fileData = json.result.entries[i]; dbx.filesGetTemporaryLink({"path": fileData.path_lower}) .then(function(response) { let img = document.createElement('img'); img.src = response.result.link; document.body.appendChild(img); }) .catch(function(error) { console.log("got error:"); console.log(error); }); } } </script> </body> </html>サムネールは画像をBlobで受けとるapiがありますが、
直接画像を取るには、json内のリンクを取るしかないっぽい。参考
知識ゼロだけど、Dropbox APIを使用したい
https://qiita.com/Ella_Engelhardt/items/c33f08b6b427eab8b310dropbox-sdk-jsを使ってフォルダ内アイテムの共有リンクを取得
https://kittagon.hateblo.jp/entry/2018/08/13/000916
- 投稿日:2021-03-29T10:40:28+09:00
Microsoft Graph APIのリフレッシュトークン取得
リフレッシュトークンとは? Microsoft Graph APIを使用するには、アクセストークンを取得する必要があります。ただ1度アクセストークンを取得したとしても有効期限は1時間のため、すぐに使えなくなってしまいます。ここで必要になるのがリフレッシュトークンです。リフレッシュトークンでアクセストークンを更新した際に新しいリフレッシュトークンも発行されます。その度に新しいリフレッシュトークンに乗り換えていくことによってアクセストークンを継続して取得できるようになり、APIを使い続けることが可能になります。 この記事ではリフレッシュトークンを取得する方法をできる限り簡潔に紹介します。 前提条件 まず大前提として、AzureポータルのAzure Active DirectoryからMicrosoft Graphのアプリ登録をする必要があります。登録を終えた後、下記4点が必要になりますのでどこかに記録しておきます。 ・クライアントID ・シークレットID ・リダイレクトURL ・テナントID codeを取得する リフレッシュトークンを取得するためにPOSTリクエストを送るのですが、その際に「code」というものが必要になります。codeを取得するには、以下のURLをブラウザに貼り付けます。 https://login.microsoftonline.com/{テナントID}/oauth2/v2.0/authorize?client_id={クライアントID}&response_type=code&redirect_uri={リダイレクトURL}&response_mode=query&scope=offline_access%20user.read%20mail.read%20calendars.readwrite&state=12345 そうすると、新しいページにリダイレクトされます。 その際に、新しくなったURLの「code=」の部分を確認し控えておきます。 リフレッシュトークンの取得方法 ここでは、node.jsでのコードになります。(axiosを使用しております) const redirect_uri = "リダイレクトURL" const client_id = "クライアントID" const Tenant = "テナントID" const client_secret = "シークレットID" const axios = require("axios"); const qs = require("querystring"); const token_endpoint = "https://login.microsoftonline.com/" + Tenant + "/oauth2/v2.0/token"; let code = "③にて取得したcode" async function main() { let data = { grant_type: "authorization_code", client_id: client_id, client_secret: client_secret, redirect_uri: redirect_uri, code: code, }; let opt = { method: "POST", data: qs.stringify(data), url: token_endpoint, }; let result = await axios(opt) console.log(result.data) } main() 上記のコードにて、リフレッシュトークンを取得することができます。 まとめ リフレッシュトークンを取得できれば、実際にAPIを用いて、カレンダーやメールなどさまざまな情報の取得や更新などができるようになります。 かなりざっくりとした説明になってしまいましたが、最後まで呼んでいただきありがとうございます! (続編に繋ぐ)
- 投稿日:2021-03-29T09:45:59+09:00
Microsoft Graph APIのリフレッシュトークン取得
リフレッシュトークンとは?
Microsoft Graph APIを使用するには、アクセストークンを取得する必要があります。ただ1度アクセストークンを取得したとしても有効期限は1時間のため、すぐに使えなくなってしまいます。ここで必要になるのがリフレッシュトークンです。リフレッシュトークンでアクセストークンを更新した際に新しいリフレッシュトークンも発行されます。その度に新しいリフレッシュトークンに乗り換えていくことによってアクセストークンを継続して取得できるようになり、APIを使い続けることが可能になります。
この記事ではリフレッシュトークンを取得する方法をできる限り簡潔に紹介します。前提条件
まず大前提として、AzureポータルのAzure Active DirectoryからMicrosoft Graphのアプリ登録をする必要があります。登録を終えた後、下記4点が必要になりますのでどこかに記録しておきます。
・クライアントID
・シークレットID
・リダイレクトURL
・テナントIDcodeを取得する
リフレッシュトークンを取得するためにPOSTリクエストを送るのですが、その際に「code」というものが必要になります。codeを取得するには、以下のURLをブラウザに貼り付けます。
https://login.microsoftonline.com/{テナントID}/oauth2/v2.0/authorize?client_id={クライアントID}&response_type=code&redirect_uri={リダイレクトURL}&response_mode=query&scope=offline_access%20user.read%20mail.read%20calendars.readwrite&state=12345そうすると、新しいページにリダイレクトされます。
その際に、新しくなったURLの「code=」の部分を確認し控えておきます。リフレッシュトークンの取得方法
ここでは、node.jsでのコードになります。(axiosを使用しております)
const redirect_uri = "リダイレクトURL" const client_id = "クライアントID" const Tenant = "テナントID" const client_secret = "シークレットID" const axios = require("axios"); const qs = require("querystring"); const token_endpoint = "https://login.microsoftonline.com/" + Tenant + "/oauth2/v2.0/token"; let code = "③にて取得したcode" async function main() { let data = { grant_type: "authorization_code", client_id: client_id, client_secret: client_secret, redirect_uri: redirect_uri, code: code, }; let opt = { method: "POST", data: qs.stringify(data), url: token_endpoint, }; let result = await axios(opt) console.log(result.data) } main()上記のコードにて、リフレッシュトークンを取得することができます。
かなりざっくりとした説明になってしまいましたが、最後まで呼んでいただきありがとうございます!
- 投稿日:2021-03-29T08:11:43+09:00
すごいReactパッケージ5選
本記事は、Varun Chilukuri氏による「Five awesome React packages to check out」(2020年9月8日公開)の和訳を、著者の許可を得て掲載しているものです。
すごいReactパッケージ5選
小さくてもインパクトのある変更で、あなたのアプリを競合他社から引き離します。
1. React Loader Spinner
待つのが好きな人はいません。今やユーザーは最低限の条件として、ウェブサイトが高速であることを求めています。アプリが重いか遅い場合は、コンテンツの読み込み中、この最新のローディングアニメーションを表示しましょう。アプリの美観を向上させるだけでなく、ユーザーを維持するのにも役立ちます。
このパッケージで提供する全ローディングアニメーション
npm
またはyarn
から直接インストールします。npm i react-loader-spinner //or yarn add react-loader-spinner次に、必要なimport文を追加します。
import Loader from 'react-loader-spinner'そして、以下をプロジェクトに追加します。
<Loader type="Puff" color="#00BFFF" height={100} width={100} timeout={3000} //3 secs />詳細については、ドキュメントを参照してください。
react-loader-spinner
react-spinner-loaderは、非同期の待機中の動作を実装できる、単純なReact SVGスピナーコンポーネントです。
www.npmjs.com2. React Animated Burgers
このパッケージは、ナビゲーションバーにアニメーション付きメニューアイコンを追加します。無数のアイコンとアニメーションが用意されています。とても簡単に、カスタマイズとプロジェクトへの追加ができます。私は喜んで何度も使っています。
このパッケージで提供するさまざまなアニメーションの例
他の
npm
/yarn
パッケージと同様に、1行で簡単にインストールできます。npm i react-animated-burgers //or yarn add react-animated-burgers styled-componentsアニメーションアイコンを1つ選択してimportするだけで、プロジェクトに追加できます。
import { HamburgerSpin } from 'react-animated-burgers'そうすると、ヘッダーやナビゲーションバーに簡単に追加できます。
<HamburgerSpin buttonColor="red" //optional barColor="#F5F5F5" //optional {...{ isActive, toggleButton }} />最も正確で新しい情報については、ドキュメントを参照してください。
react-animated-burgers
パッケージのインストールは、npm i -S react-animated-burgers styled-components またはyarn add react-animated-burgers...
www.npmjs.com3. React Responsive Carousel
多くのウェブサイトでは、カルーセルを設置して、商品、チームメンバー、会社に関する一般的な情報を表示しています。サイトにカルーセルを設置したいと思っているなら、おそらく多くの中途半端またはいまいちなパッケージを見たことがあるでしょう。これは、他のパッケージとは違い、インパクトがあり軽量、完全にカスタマイズ可能です。
カルーセルの動作デモ
パッケージをインストールします。
npm i react-responsive-carousel //or yarn add react-responsive-carouselimport文を追加して、プロジェクトに追加します。
import { Carousel } from 'react-responsive-carousel' import "react-responsive-carousel/lib/styles/carousel.min.css";以下をウェブサイトに簡単に追加できます。
<Carousel> <div> <img src="assets/1.jpeg" /> <p className="legend">Legend 1</p> </div> <div> <img src="assets/2.jpeg" /> <p className="legend">Legend 2</p> </div> <div> <img src="assets/3.jpeg" /> <p className="legend">Legend 3</p> </div> </Carousel>このパッケージは、制御方法が多く自由度が高いです。このプロジェクトを十分に活用するには、GitHubリポジトリなどを見てください。
react-responsive-carousel
インパクトがあり軽量、完全にカスタマイズ可能なReactアプリ用カルーセルコンポーネントです。レスポンシブモバイルフレンドリーです...
www.npmjs.com4. React CountUp
企業の統計情報をウェブサイトに表示することは、かつてない程に簡単になりました。このパッケージでは、動的カウンターを使って、印象的な数字を目立たせて強調表示できます(溶け込んでしまう静的テキストとは違います)。
パッケージをインストールします。
npm i react-countup //or yarn add react-countup以下をプロジェクトファイルの先頭に追加して、プロジェクトに追加します。
import CountUp from 'react-countup';以下は、3つの簡単な使用例です。
<CountUp end={100} /> <CountUp delay={2} end={100} /> <CountUp duration={5} end={100} />より高度な機能と自由度については、パッケージのページを参照してください。
react-countup
CountUp.jsのReactコンポーネントラッパーです。
www.npmjs.com5. React Markdown
Markdown言語が提供する効率性とシンプルさが好きな人にとっては朗報です。ReactコードでMarkdownを使う簡単な方法があります。このパッケージを使うだけです!
npm
でインストールします。npm i react-markdown注:残念ながらこのパッケージは、yarnによるインストールをサポートしていません。
必要な文をコードに追加します。
const ReactMarkdown = require('react-markdown')使い始めましょう!
const React = require('react') const ReactDOM = require('react-dom') const ReactMarkdown = require('react-markdown') const input = '# This is a header\n\nAnd this is a paragraph' ReactDOM.render(<ReactMarkdown source={input} />, document.getElementById('container'))最も正確で新しい情報については、公式ページを参照してください。
react-markdown
Markdownを純粋なReactコンポーネントとしてレンダリングします。デモはこちらで見られます。https://rexxars.github.io/react-markdown/ react-markdown...
www.npmjs.comおわりに
この記事が参考になり、アプリに追加したいと思うパッケージが1つでもあったなら幸いです。
この記事などで使われているコードはすべて、私のGitHubレポジトリにあります。
この記事が役に立った場合は、フォローをお願いします!React.jsに関する記事がもっとあります。フィードバックやコメントもお待ちしています。
JavaScriptを分かりやすく解説
私たちが3つのパブリケーションとYouTubeチャンネルを持っていることを知っていますか?すべてのリンクはこちらplainenglish.io!
翻訳協力
この記事は以下の方々のご協力により公開する事ができました。改めて感謝致します。
Original Author: Varun Chilukuri
Original Article: Five awesome React packages to check out
Thank you for letting us share your knowledge!選定担当: @gracen
翻訳担当: @gracen
監査担当: -
公開担当: @gracenご意見・ご感想をお待ちしております
今回の記事はいかがでしたか?
・こういう記事が読みたい
・こういうところが良かった
・こうした方が良いのではないか
などなど、率直なご意見を募集しております。
頂いたお声は、今後の記事の質向上に役立たせて頂きますので、お気軽に
コメント欄にてご投稿ください。Twitterでもご意見を受け付けております。
皆様のメッセージをお待ちしております。
- 投稿日:2021-03-29T08:07:36+09:00
税込から税抜を求めるには切り上げ?切り下げ?→ケースバイケースで要注意な件
4月から税込み表示が義務化され、また世のエンジニアが苦労する中、逆に税込から税抜を求めるの思った以上に苦労した話です。
一般的な小売では税込から税抜を求める状況はないと思いますが、相対取引で定価が無い場合は税込価格から決まることはザラです。具体例として
10096円〜10099円
の間の価格でお話ししますと
10097円は÷1.1して切り捨てた9179円が正解です。
10099円は÷1.1して切り上げた9181円が正解です。なぜなら双方とも誤って切り上げたり、切り下げると共に9180円になり、そこから税込価格を逆算すると10098円一択となってしまい元に値と矛盾するからです。ちなみに
10098円は割り切れる整数なので、切り捨て切り上げ関係なく、9180円の一択になります。
10096円は切り捨てて9178円、切り上げて9179円としてどちらでも良いのですが、それらからの税込み価格の計算は、端数の取扱次第で10095〜10097円まで幅広く解釈することができます。これらを踏まえ実装としては、税抜価格netが最大化する按分になるceilでまず計算してみて、そこから税込の逆算が矛盾を起こす場合のみ、floorを採用する条件分岐が必要になります。
MySQLなら以下の通りです。mysql> SELECT -> taxed, -> case when floor(ceil(taxed/1.1)*1.1)=taxed or ceil(ceil(taxed/1.1)*1.1)=taxed then ceil(taxed/1.1) else floor(taxed/1.1) end as net -> FROM ( -> SELECT 10096 AS taxed UNION -> SELECT 10097 AS taxed UNION -> SELECT 10098 AS taxed UNION -> SELECT 10099 AS taxed -> ) prices; +-------+------+ | taxed | net | +-------+------+ | 10096 | 9179 | | 10097 | 9179 | | 10098 | 9180 | | 10099 | 9181 | +-------+------+ 4 rows in set (0.01 sec)MySQLは問題ありませんでしたが、実装には浮動小数点の問題があり要注意です。
端的に以下に例示すると100円の税込みは110円のはずですが、どちらも111円になります。体感的にはもはやバグです。JavaScriptによる例Math.ceil(100*1.1) // 111pythonによる例import math math.ceil(100*1.1) # 111このリスクに対応するため8桁以降を丸めた処理を挟んで以下のようになりました。
pythonによる例from math import floor, ceil {taxed: ceil(round(taxed / 1.1, 8)) if floor(round(ceil(round(taxed / 1.1, 8)) * 1.1, 8)) == taxed or ceil(round(ceil(round(taxed / 1.1, 8)) * 1.1, 8)) == taxed else floor(round(taxed / 1.1, 8)) for taxed in [10096, 10097, 10098, 10099]} # {10096: 9179, 10097: 9179, 10098: 9180, 10099: 9181}1万円までの全価格を走査して統計とったスクリプトを書いたので、貼っておきます。
価格(整数)の集合全体の8割は割った後に切り上げ切り下げどちらでも良いのですが、残り1割ずつは切り上げ限定か切り下げ限定の困ったちゃん価格なのが分かります。from math import floor, ceil import pprint result = {} for taxed in range(100, 10100): recalc = { "FF": floor(round(floor(round(taxed / 1.1, 8)) * 1.1, 8)), "CF": floor(round(ceil(round(taxed / 1.1, 8)) * 1.1, 8)), "FC": ceil(round(floor(round(taxed / 1.1, 8)) * 1.1, 8)), "CC": ceil(round(ceil(round(taxed / 1.1, 8)) * 1.1, 8)), } key = tuple(k for k, v in recalc.items() if v == taxed) if len(key) == 0: print(taxed) raise result[key] = [*result.get(key, []), taxed] print(taxed, key, recalc) pprint.pprint({k: { "min": min(v), "max": max(v), "len": len(v), } for k, v in result.items()})税抜き価格の計算は税率で割って丸めるだけ、そんなふうに考えていた時期が俺にもありました。。。
- 投稿日:2021-03-29T07:23:44+09:00
JavaScript 文字列を配列に変換する
- 投稿日:2021-03-29T05:30:32+09:00
thisなきJS エラーあり
はじめに
JSでTODOアプリをつくり、そのやり方を教材として書き起こしていた。教材の仕様に沿ってアロー関数をつかったらうまく動作しなくなった。なんだこれは。少しだけ考えた。
問題
問題が発生したのはTODOの内容をクリックして、既存のタスクを編集する箇所。今までのfunctionではOKだったが、アロー関数にするとなんだかおかしい。
コード
問題点を明らかにするためにその箇所だけを抜き出して別にコードを書いた。「テスト」をクリックするとアロー関数のやつが実行されて、「テスト2」だと普通の関数が実行される。
テストをクリックして、入力フォームのカーソルを外すと「Uncaught TypeError: Cannot read property 'classList' of null」
というエラーが出てくる。
test.html<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"/> <link rel ="stylesheet" href="todo.css"> <title>イベントハンドラテスト</title> </head> <body> <header> <h1>TODOテスト</h1> </header> <div class="container"> <div class="todo-container"> <ul class="todo-list"> <li> <span class="todo-content1">テスト</span> </li> <li> <span class="todo-content2">テスト2</span> </li> </ul> </div> </div> <script src = "test.js"></script> </body> </html>const editTodo = (e) => { let itemToEdit = e.target; if(!itemToEdit.classList.contains('on')) { itemToEdit.classList.add('on'); let contentBeforeEdit = itemToEdit.textContent; itemToEdit.innerHTML = '<input type="text" class="editbox1" value="'+contentBeforeEdit+'" />'; const editContent1 = document.querySelector('.editbox1'); const saveTodoContent = (e) => { let itemToSave = e.target; itemToSave.parentNode.classList.remove('on'); let txtvalue = itemToSave.value; if (txtvalue ==''){ txtvalue = itemToSave.defaultValue; } itemToSave.parentNode.innerHTML = txtvalue; } editContent1.addEventListener('blur',saveTodoContent); } } function editTodo2(e) { if(!this.classList.contains("on")) { this.classList.add("on"); let contentBeforeEdit = this.textContent this.innerHTML = '<input type="text" class="editbox2" value="'+contentBeforeEdit+'" />' const editContent2 = document.querySelector(".editbox2") let saveTodoContent = function(){ this.parentNode.classList.remove('on') let txtvalue = this.value if (txtvalue ==""){ txtvalue = this.defaultValue } this.parentNode.innerHTML = txtvalue } editContent2.addEventListener("blur",saveTodoContent) } } //Select DOM const todoContent = document.querySelector('.todo-content1'); todoContent.addEventListener('click', editTodo); const todoContent2 = document.querySelector('.todo-content2'); todoContent2.addEventListener('click', editTodo2);問題を追う
カーソルを外した時に「classListがnullですよ」というエラーが発生する。ちょうどこの行である。
const saveTodoContent = (e) => { // itemToSave.parentNode.classList.remove('on'); //Chromeのデベロッパーモードで少しずつ検証していった。そうするとカーソルを外す時に実行されるイベント
saveTodoContent
が2回実行されていることがわかった。そして2回目の実行時にエラーが発生していた。なぜだ。だいたいはthisが原因だった。
原因
この機能では項目の状態を知る必要がある。つまり「タスクが現在入力モードなのか否か」ということを知りたいのだ。コード上ではclasslistにonというclassを付与したり外したりしてそれを操作している。
今まではその検知にthisを用いていたが、今回アロー関数に書き換えたことによってthisが使えなくなり、別の記法で書き換えた。そこがよくなかったのだ。ここである。
変更前function editTodo2(e) { if(!this.classList.contains("on")) { // .. クリックときに編集モードでなければ以下を実行変更後const editTodo = (e) => { let itemToEdit = e.target; if(!itemToEdit.classList.contains('on')) { // .. クリックときに編集モードでなければ以下を実行this/e.target
thisとe.targetはなにが違うのか。thisは場面によってさまざまに容態を変化させるが、ここでは以下の記事を参考にするならば「関数を呼び出している元のオブジェクト」である。
e.targetとはクリックしたときの物体である。テキスト文字であったり、入力フォームであったりする。
thisの中身はタスクが編集モードか否かでも変わらない。しかしe.targetは中身が変わる。ためしにconsole.logで読んでみよう。
const editTodo = (e) => { let itemToEdit = e.target; console.log(e.target); console.log(this); // function editTodo2(e) { console.log(e.target); console.log(this);上4行はアロー関数のほう。下はいままでの関数だ。たしかになんか違っていた。
どうしたか
アロー関数にはイベントが実行される条件を増やした。
const editTodo = (e) => { let itemToEdit = e.target; if(!itemToEdit.classList.contains('todo-content1')){ return; } if(!itemToEdit.classList.contains('on')) { //....これで問題は解決した。
おわりに
文章がまとまらないままこれを書き出してしまった。それでもどこかに残しておかないと、後々自分が困ってしまう。
もしかしたら追記するかもしれないししないかもしれない。
- 投稿日:2021-03-29T05:28:42+09:00
化物語の予告風デザインのホームページを作った
はじめに
タイトルの通りです。
なんとなく思いついたのでそれっぽいデザインで作ってみました。
モバイル用の実装はしていないのでPCのみです。
コードの書き方とかディレクトリ構成とか色々適当なので分かりにくかったらすみません。
それぞれのページにダミーデータみたいなのを入れてあります。GitHubにありますので良かったら。
ソースコード参考
今回作ったものの中身などは特に解説はしませんので、GitHubを見てください。
ですが、制作過程で参考にしたサイトなどを紹介します。ブログページ関連
- マークダウンファイルをブログ記事として表示する
- ページネーション
- 記事内のコードブロック
CSS
- アニメーション
- 画像の色を変える際filterでの色指定でめちゃ便利だったやつ
- CSS Color Code
その他
- 画像透過
- 使用させていただいた無料画像サイト
- 投稿日:2021-03-29T00:20:36+09:00
Web API DOMとEvent Flowを理解する
はじめに
ふと、DOMとは何か理解したくなったので勉強してまとめたいと思います。
DOM全体だとかなり長くなってしまうので、今回はよくある下記のようなコードがどのような仕組みで動いているのか理解したいと思います。let element = document.getElementById('el'); element.addEventListener('click', function() {})DOM: Document Object Model
DOMは、HTMLやXMLを操作するためのインターフェイスです。
XMLに対してDOM操作って個人的には馴染みのないものですね。Webページを表現するHTMLは、あくまで"文書"です。
DOMは、HTMLをオブジェクトとして操作・変更するためのインターフェイスであり、その操作を行う言語がJavaScriptです。
DOM操作を主に使用される言語がJavaScriptなだけであり、DOM操作は他の言語でも可能です。
例えばPHPには、DOM操作するためのクラスが用意されています。
https://www.php.net/manual/ja/book.dom.php<?php $doc = new DOMDocument(); $doc->loadHTML('<html><body id="test">Test<br></body></html>'); echo $doc->getElementById('test')->tagName; // body ?>DOMインターフェイス
DOMで提供されるインターフェイスは様々なものがありますが、
いくつか取り上げてまとめていきたいと思います。EventTarget
DOMを構成する基底のインターフェースです。
イベントを登録したり、DOM操作の対象になるオブジェクトです。
イベントを追加するaddEventListener()はEventTargetで実装されているメソッドです。Node
DOMを構成するインターフェースの1つです。EventTargetのメソッドとプロパティを継承しています。
DOMのインターフェイスは、基本的にNodeを継承しています。例えば以下のものはNodeに含まれます。
- HTMLElement
- テキスト
- コメント
- 属性
DOMは、HTML内のオブジェクトをNodeとして扱います。
以下のようなHTMLを分類してみるとこのような感じになると思います。
- html -> element node
- body -> element node
- h1 -> element node
- メイン -> テキスト node
- <!-- メイン --> -> コメント node
<html> <body> <h1>タイトル</h1> <!-- メイン --> </body> </html>Document
DOM ツリーであるウェブページのコンテンツへのエントリーポイントとして働きます
https://developer.mozilla.org/ja/docs/Web/API/Document
<html>
から始まるDOMツリーにアクセスするための、エントリポイントです。
Nodeを継承していて、ドキュメント全体の情報を検索したりすることができます。<html> <body> <h1>タイトル</h1> <img src="hoge.jpg" alt=""> </body> </html> <script> let images = document.images; // HTMLCollection[img] </script>DocumentやWindowオブジェクトは、Nodeを継承していて、EventTargetで実装されているaddEventListenerといったメソッドにアクセスすることができます。
Event Flow
インターフェイスを追っていくことで、addEventListenerが実装されている基底のインターフェイスまで学ぶことができました。
次に、イベント処理がどのように行われるのかみてみたいと思います。イベントとは
そもそもイベントとは何か、簡単にまとめたいと思います。
Webページで行われる状態の変化や操作全般を指しています。
マウスカーソルの移動やボタンのクリック、動画の再生もイベントととして扱うことができます。
どんなイベントがあるか、こちらからわかりやすく一覧でみることができます。量は大変多いです。
WebVRに関連したイベントもありますね?
https://developer.mozilla.org/ja/docs/Web/Eventsイベントフロー
処理の流れを整理するためにイベントフローを理解するのが良さそうです。
画像は、本記事の参考文献でもあるW3Cのページからお借りしました。
https://www.w3.org/TR/DOM-Level-3-Events/イベントが発生してからEventListenerの処理が行われるまで3つのフェーズがあります。
capture phase
WindowオブジェクトからターゲットとなるElementをツリー構造を下っていくように捕捉します。target phase (at-target phase)
ターゲットを見つけたフェーズです。 イベントの種類をみてbubble phaseへ移すか判断します。bubble phase
capure phaseとは逆に、イベントが起こったElementから親Nodeを辿ってイベントを伝搬させます。
イベントハンドラは基本的にバブリングフェーズに登録されるので、ユーザーが定義したハンドラの実行もこのフェーズで行われます。伝播ということがどういうことかわかりづらかったので例に以下のようなコードを用意しました。
body
とh1
には同じハンドラを登録しています。
h1
をクリックした時に、consoleに2回以下のようなログが記録されるはずです。
[object HTMLHeadingElement] clicked
これはイベントのバブリングによってbodyに登録されたハンドラが実行されたことによります。
e.target
は、イベントが発生した要素を示すので、body
がクリックされた訳ではなく、h1
で発生したイベントが伝播したことがわかると思います。<html> <body id="body"> <h1 id="h1">タイトル</h1> </body> </html> <script> function handler(e) { console.log(`${e.target} clicked`); } document.getElementById('body').addEventListener('click', handler); document.getElementById('h1').addEventListener('click', handler); </script>なお、イベントの伝播をせずにターゲットのElementだけで処理をさせたいような場合には、
e.stopPropagation()
を書いて上げることで実現可能です。function handler(e) { e.stopPropagation() console.log(`${e.target} clicked`); }まとめ
冒頭に紹介したコードを改めて読んでまとめとします。
let element = document.getElementById('el'); element.addEventListener('click', function() {})
el
がclickされた時の流れ
- クリックイベントが発生する
- イベントは、Windowオブジェクトから子Nodeに伝播する
- ターゲットとなる
el
を見つける- バブリングフェーズに登録された匿名関数を実行する
- (親Nodeへイベントが伝搬する)
参考
DOMの紹介
https://developer.mozilla.org/ja/docs/Web/API/Document_Object_Model/IntroductionDOM EventTarget
https://developer.mozilla.org/ja/docs/Web/API/EventTargetDOM Node
https://developer.mozilla.org/ja/docs/Web/API/Nodeブラウザの仕組み全般
https://www.html5rocks.com/ja/tutorials/internals/howbrowserswork/#The_rendering_engine
- 投稿日:2021-03-29T00:09:54+09:00
【PHP】GET・POST サーバー 作成
今回はphpのget・postサーバーの作成について書きます。
正直、今回の記事は自身のメモとしての意味合いが大きいです。
似たようなことが書かれた記事は多いですし、コードの内容も多くないため簡潔に書いていこうと思います。実装環境
今回はそんなに手間をかけるつもりはないため、xamppを使用します。
VSCodeを使用してコードを書きましたが、コマンドでビルドが必要だとかいうこともないので、テキストエディターは何でも良いです。GET・POST サーバー
index.php<?php if (isset($_POST['post_sample'])) { echo $_POST['post_sample']; } if (isset($_GET['get_sample'])) { echo $_GET['get_sample']; }PHP側のコードはこれだけです。
$_POST['~']
でPOSTで送られてきた値を取得し、$_GET['~']
でGETで送られてきたデータを取得します。クライアント側(html)
動作確認のために次はクライアント側のhtmlのコードを作成します。
index.html<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UFT-8"> <title>get_post_sample</title> </head> <body> <form action="index.php" method="GET"> <input type="text" name="get_sample" value="get_sample_text"> <input type="submit" value="get"> </form> <form action="index.php" method="POST"> <input type="text" name="post_sample" value="post_sample_text"> <input type="submit" value="post"> </form> </body> </html>細かい説明は省きますが、formのinputを使用することでGET・POSTのいずれも送信することができます。(見てわかるかもしれませんが、methodの部分でGETとPOSTを定義してます)
動作確認
xamppを起動してページを呼び出せば下記の様なページになります。
ボタンのget
を押せばGETで送信され、ボタンのpost
を押せばPOSTで送信されます。GET送信時
php側の処理はecho
しているだけなので、画面は送信したget_sample_textだけが表示されます。URLを確認してもらえばわかるかともいますが、GETの挙動としてパラメータがURLに表示されています。POST送信時
php側で設定してる内容はGETとほぼ同じなので、挙動に大きな差は見られません。
POST時の挙動として、GETと違いパラメータがURLには表示されません。クライアント側(JavaScript)
今回は、JavaScriptでもクライアント側を作成してみます。
script.html<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UFT-8"> <title>get_post_sample</title> </head> <body> <script> function do_post() { let xhr = new XMLHttpRequest(); xhr.open('POST', 'index.php', true); xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded;charset=UTF-8'); let request = "post_sample=post_text_by_js"; xhr.send(request); //post送信後のレスポンス xhr.onreadystatechange = function () { alert(xhr.responseText); } } </script> <input type="button" value="post" onclick="do_post()"> </body> </html>処理としては
XMLHttpRequest
オブジェクトを生成してPOSTを送信(.send()
)します。
そのあと、onreadystatechange
に設定された内容の通りに、PHP側から送られてきたPOSTのレスポンスを処理します。動作確認
作成したページを開き、postボタンを押下するとonreadystatechange
で処理を設定した通り、アラートが表示されます。
今回の場合は、アラートで表示される内容はphpのページで表示される内容と同じなので、postで送信した内容がそのまま表示されることになります。(php側のソースで、POSTで送られてきた内容をそのままechoしているだけになっているため)
htmlで作成した場合と違い、画面遷移することはありません。終わりに
今回はGET・POSTのサーバー側と、クライアント側を二種類書きました。
簡潔に書くと言った割に長いような…
PHPはあまり触ってないので、個人的にはもう少し腕を磨きたいと思っています。
あと、GET・POSTというとJavaのサーブレットを仕事でやったことがありましたが、結構前のことで記憶が怪しいので、時間があればまとめようかと思います。