- 投稿日:2020-08-04T23:33:45+09:00
toJSONを用いて、JSONデータの返り値を制御する
JSONデータの返り値を制御する
例)petというJSONデータの場合
const pet = { name: 'Doggy' } console.log(JSON.stringify(pet))↓
{'name':'Doggy'}
というJSONデータが返ってくる。★返り値となるJSONデータを、toJSONを使って制御することができる
const pet = { name: 'Doggy' } pet.toJSON = function(){ return {} } console.log(JSON.stringify(pet))↓
{}
というJSONデータが返ってくる。つまり
toJSONで上書きされた値が、pet定数のJSONデータとして認識される
データベースのセキュリティ向上に利用
//mongooseを利用して、データベース型を設定 const mongoose = require('mongoose') const userSchema = new mongoose.Schema({ name: { type: String, //データ型の設定 required: true, trim: true }, password:{ type: String, required: true, }, tokens: [{ token: { type: String, require: true } }], }) //toJSONを用いて、外からuserObjectにアクセスした時に、返すメソッドと返さないメソッドを決める userSchema.methods.toJSON = function(){ const user = this const userObject = user.toObject() delete userObject.password delete userObject.tokens return userObject }↓
これで、userObjectは、toJSONで指定されている、passwordとtoken以外のデータを返すようになる。
- 投稿日:2020-08-04T23:22:51+09:00
【SNS顔出しNGの方も安心】顔に目隠しを付けてくれるアプリを機械学習APIで作ったよ
作ったもの
SNS顔出しNGの方のために、
顔に目隠しを付けてくれるアプリを作りました。ウェブアプリなので、PC、スマホの機種は問いません。
こちらのリンクからどうぞ。
https://hardcore-ritchie-cca31e.netlify.app/使用例
写真をアップロードすると、いい感じに目隠しを付けてくれます。
複数人でも大丈夫。
(普通の飲み会が、なにやら悪巧みしてそうな会合に変貌)
※コロナ禍より前の飲み会です。
秘密のデートも目隠しを入れれば、誰にもバレません。
これで、プライバシーもバッチリ!
(写真はフリー写真サイト「ぱくたそ」 さんより)これで、みなさんも安心してSNSに投稿できますね。
番外編
なんと、私の3Dモデル(リアルアバター)にも反応しました。
つまり、私のアバターは人間と見分けがつかない?
ちなみに、このアバターは浅草にあるリアルアバターさんで作ってもらいました。
猫はダメでした。
「人間じゃないよ」ってアラートを出します。
使用技術
言語:
Javascript
CSSフレームワーク
bootstrap
レスポンシブデザインを気持ち程度に使用ライブラリ
- face-api.js
顔認証、目の位置をこれで取得- humane.js
アラートを表示face-api.js について
顔認識の機械学習モデルが使えるAPIです。
tinyFaceDetector というモデルで顔を検出し、
faceLandmark68Net というモデルで顔のランドマークを検出します。
この写真のように68個の顔のポイント1つ1つの画像上での座標が取得できます。参考サイト
以下のサイトに大変お世話になりました。
ありがとうございました。
face-api.js - ブラウザでの顔認識を行うJavaScript API
顔のランドマークを抽出する方法やコードは、ほとんどこちらのサイト記載のものを使用しました。File APIとCanvasでローカルの画像をアップロード→加工→ダウンロードする
ファイルをアップロードしてCanvas上に表示するコードは、ほとんどこちらのサイト記載のものを使用しました。コード
index.html<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <!-- Bootstrap --> <!-- CSS only --> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous" /> <!-- JS, Popper.js, and jQuery --> <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous" ></script> <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous" ></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous" ></script> <style> .container { padding-top: 50px; } </style> <!-- face-api.jsの読み込み --> <script src="face-api.js"></script> <!-- humaneライブラリの読み込み --> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/humane-js/3.2.2/themes/boldlight.css"/> <script src="https://cdnjs.cloudflare.com/ajax/libs/humane-js/3.2.2/humane.min.js"></script> </head> <body> <div class="container"> <div class="upload"><input type="file" name="file" id="file"></div> <div id="result"></div> <canvas id="canvas"></canvas> </div> </body> <script> const MODEL_URL = 'models/' let file = document.getElementById('file') let canvas = document.getElementById('canvas') let canvasWidth = 350 let canvasHeight = 350 let uploadImgSrc //ファイルをアップロードしてCanvas上に表示するのは、ほぼこのサイトどおり //https://www.tam-tam.co.jp/tipsnote/javascript/post13538.html // Canvasの準備 canvas.width = canvasWidth canvas.height = canvasHeight var ctx = canvas.getContext('2d') function loadLocalImage(e) { // ファイル情報を取得 let fileData = e.target.files[0] console.log("filedata",fileData) // 画像ファイル以外は処理を止める if(!fileData.type.match('image.*')) { humane.log("画像ファイルでお願いします") } // FileReaderオブジェクトを使ってファイル読み込み let reader = new FileReader() // ファイル読み込みに成功したときの処理 reader.onload = function() { // Canvas上に表示する uploadImgSrc = reader.result; canvasDraw(fileData) } // ファイル読み込みを実行 reader.readAsDataURL(fileData) } // ファイルが指定された時にloadLocalImage()を実行 file.addEventListener('change', loadLocalImage, false) // Canvas上に画像を表示する function canvasDraw() { // canvas内の要素をクリアする ctx.clearRect(0, 0, canvasWidth, canvasHeight) // Canvas上に画像を表示 let img = new Image() img.src = uploadImgSrc img.onload = function() { ctx.drawImage(img, 0, 0, canvasWidth, this.height * (canvasWidth / this.width)) let canvasRate = canvasWidth / this.width //顔の情報を取得 getFaceData(img,canvasRate) } } async function getFaceData(img,canvasRate) { await faceapi.nets.tinyFaceDetector.load('models/') //モデル読み込み await faceapi.nets.faceLandmark68Net.load("models/") //モデル読み込み // 顔検出の実行 const detectionsWithLandmarks = await faceapi.detectAllFaces(img, new faceapi.TinyFaceDetectorOptions()).withFaceLandmarks() if (detectionsWithLandmarks.length == 0){ humane.log('人間じゃないよ') }else{ for (let n = 0; n < detectionsWithLandmarks.length ; n++ ) { let x0 = detectionsWithLandmarks[n].landmarks._positions[0].x * canvasRate let y0 = detectionsWithLandmarks[n].landmarks._positions[37].y * canvasRate let x1 = detectionsWithLandmarks[n].landmarks._positions[16].x * canvasRate let y1 = detectionsWithLandmarks[n].landmarks._positions[46].y * canvasRate let line_thickness = (x1-x0) * .2 //線の太さを長さの20%とした drawLine(x0,y0,x1,y1,line_thickness) //目隠し線を引く関数 } } } //目隠し線を引く function drawLine(x0,y0,x1,y1,line_thickness){ ctx.strokeStyle = '#000000' ctx.lineWidth = line_thickness ctx.beginPath() ctx.moveTo(x0, y0) ctx.lineTo(x1,y1) ctx.closePath() ctx.stroke() } </script> </html>
- 投稿日:2020-08-04T22:53:06+09:00
bcryptでプレーンテキストをハッシュ化させる
ハッシュ化のメリット
・パスワードなどをデータベースに保存する時、プレーンテキストのまま保存すると脆弱性に繋がる。
・ハッシュ化したメッセージダイジェストから、元のメッセージを復元することは困難
→「インクリプション」…元のメッセージをとっておいて、それをハッシュ化したら同じハッシュ値になるかチェックすることで、同一性を確認する仕組みbcryptパッケージ
bcryptというnpmパッケージを利用すると、プレーンテキストをハッシュ化することができる。
・bcryptパッケージの使い方
const bcrypt = require('bcryptjs') const myFunction = async() => { const password = "password1234" const hadhedPassword = await bcrypt.hash(password, 8) //第一引数:ハッシュ化したい値、第二引数:roundをかける回数。公式推奨は8回 console.log(password) //元のパスワードを表示 console.log(hassedPassword) //ハッシュ化されたパスワードを表示 //元のパスワードとハッシュ化されたパスワードを比較し、同じものであるか確認 const isMarch = await bcrypt.compare('password', hashedPassword) } myFunction()値をハッシュ化させてからデータベースに組み込む
●Middlewareを利用してMongooseの振る舞い方をカスタマイズできる
Mongoose公式ドキュメント
「Middleware > Save/Validate」の項目
・validateする前、または後にイベントを設定できる。
・saveする前、または後にイベントを設定できる。→save()する前に、データベースに保存したい値をハッシュ化させることができる。
●例)
データベースに格納する前にpasswordをハッシュ化const mongoose = require('mongoose') const bcrypt = require('bcryptjs') const userSchema = new mongoose.Schema({ name: { type: String, //データ型の設定 required: true, trim: true }, password:{ type: String, required: true, } }) //middlewareを記述。saveする前にプレーンテキストをハッシュする userSchema.pre('save', async function(next){ //アローファンクションは使わない。このbindingは大事な役割を果たすものだから const user = this console.log('Middleware is working')//ミドルウェアが動いているか確認するためのテストコード if(user.isModified('password')){ //ハッシュ化されていないパスワードがある時 user.password = await bcrypt.hash(user.password, 8) }//ここで値がハッシュされる next() })
- 投稿日:2020-08-04T22:15:03+09:00
aibo Web API と YouTube Player API を連携して、YouTube 動画の再生秒数に合わせて aibo にふるまいをしてもらう
aibo 界隈ではオフ会というものが定期的に開催されています。
内容は様々ですが、大体は aibo を室内で自由にお散歩させつつ
オーナーは aibo たちを見てニヤニヤしながらお話したり
aibo の名刺や情報を交換したりして交流を深める会です。最近はコロナの影響あって、開催するのもなかなか難しい状況なってしまいましたが。。
とあるオフ会で aibo をアイドルに見立ててダンスをしてもらおうという企画がありました。
当然のことながら、aibo はアイドルのように自ら曲に合わせてダンスするということができません。なのでどうしたかというと、オーナー皆さんの力を合わせて aibo の配置をシーン毎で変え
企画主の方に写真をとっていただいてダンスしてる風の動画を作っていただきました。その時 aibo にダンスの振り付けができたらそれはもう素敵なのになぁと思ったわけです。
その後 aibo Web API が 2019/11/11 に実装され可能性が広がりました。前回の「aibo Events API を使って aibo に音声コマンドを実行してもらう」では PHP を使いましたが、今回は HTML + JavaScript で実装します。
完成図
まずは完成図から。
イントロが終わったら、ルンルンし始めるおチャコさんです。事前準備
素材となる YouTube 動画をあらかじめ探しておきます。
今回はこちらを使用しています。となりのトトロのさんぽですね。
aibo がこの曲を聞いて、ノリノリでダンスをやり始めたらかわいいじゃないですか。アクセストークン取得
ディベロッパーサイトにアクセスして、サインインします。
ボタン「生成する」をクリックすると、アクセストークンが生成されます。
アクセストークンは「実装」で必要なので、あらかじめコピーしておきましょう。実装
今回は aibo Web API と YouTube Player API を連携する形で実装します。
まずはでき上がりのソースをペタッと貼り付けておきます。<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>aibo Web API | aibo Web API と YouTube Player API を連携して、YouTube 動画の再生秒数に合わせて aibo にふるまいをしてもらう</title> </head> <body> <!-- 1. iframe 置き換え --> <div id="player"></div> <script> const ACCESS_TOKEN = ${ACCESS_TOKEN}; const BASE_PATH = 'https://public.api.aibo.com/v1'; let deviceId = ${deviceId}; // ふるまいを実行 function executeAction (deviceId, eventId) { callActionApi(deviceId, 'play_motion', '{"Category": "' + eventId + '", "Mode": "NONE"}'); } // Action API 呼び出し function callActionApi (deviceId, apiName, arguments) { postUrl = BASE_PATH + '/devices/' + deviceId + '/capabilities/' + apiName + '/execute'; data = '{"arguments":' + arguments + '}'; // POST API postApi(postUrl, data); } // POST API function postApi (url, argary) { url = url ? url : ''; fetch(url, { method: 'POST', mode: 'cors', headers: { Authorization: 'Bearer ' + ACCESS_TOKEN }, body: argary }) .then(function (response) { return response.json(); }) .then(function (data) { outputResult(data.executionId); }) } // API 実行結果 出力 function outputResult (id) { const url = BASE_PATH + '/executions/' + id; fetch(url, { method: 'GET', mode: 'cors', headers: { Authorization: 'Bearer ' + ACCESS_TOKEN } }) .then(function (response) { return response.json(); }) .then(function (data) { // API 実行結果 出力 console.log(data); }) } // 2. IFrame Player APIコード 非同期読み込み var tag = document.createElement('script'); tag.src = "https://www.youtube.com/iframe_api"; var firstScriptTag = document.getElementsByTagName('script')[0]; firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); // 3. API をダウンロード後に iframe 作成 var player; function onYouTubeIframeAPIReady() { player = new YT.Player('player', { height: '390', width: '640', videoId: 'KjqNqm23Ti0', events: { 'onReady': onPlayerReady, // 4. ビデオレイヤーの準備できたら実行 'onStateChange': onPlayerStateChange // 5.プレイヤーの状態が変化すると実行 } }); } // 4. ビデオレイヤーの準備できたら実行 function onPlayerReady(event) { event.target.pauseVideo(); } // 5.プレイヤーの状態が変化すると実行 var done = false; function onPlayerStateChange(event) { // 再生 if (event.data == YT.PlayerState.PLAYING && !done) { // 左右に体を揺らす setTimeout(executeAction, 8000, deviceId, 'swing'); done = true; } } </script> </body> </html>それぞれ見ていきます。
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>aibo Web API | aibo Web API と YouTube Player API を連携して、YouTube 動画の再生秒数に合わせて aibo にふるまいをしてもらう</title> </head> <body> </body> </html>HTML の雛形です。
今回の実装に必要な最低限のものしか記述していません。<!-- 1. iframe 置き換え --> <div id="player"></div>YouTube Player API のサンプルにあった記述です。
この部分が iframe に置き換わります。<script> </script>実装を JavaScript で行うため、script タグを
</body>
直前に追加します。const ACCESS_TOKEN = ${ACCESS_TOKEN}; const BASE_PATH = 'https://public.api.aibo.com/v1'; let deviceId = ${deviceId};以降は JavaScript の実装です。
${ACCESS_TOKEN}
には、項目「アクセストークン取得」でコピーしておいたアクセストークンを入れます。
${deviceId}
には、ふるまいをやってもらう aibo のデバイス ID をいれます。// 2. IFrame Player APIコード 非同期読み込み var tag = document.createElement('script'); tag.src = "https://www.youtube.com/iframe_api"; var firstScriptTag = document.getElementsByTagName('script')[0]; firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);YouTube Player API のサンプルにあった記述です。
IFrame Player APIコード を非同期で読み込みます。// 3. API をダウンロード後に iframe 作成 var player; function onYouTubeIframeAPIReady() { player = new YT.Player('player', { height: '390', width: '640', videoId: 'KjqNqm23Ti0', events: { 'onReady': onPlayerReady, // 4. ビデオレイヤーの準備できたら実行 'onStateChange': onPlayerStateChange // 5.プレイヤーの状態が変化すると実行 } }); }YouTube Player API のサンプルにあった記述です。
API をダウンロード後に iframe 作成します。
events プロパティは動画の状態によって着火する関数を指定します。// 4. ビデオレイヤーの準備できたら実行 function onPlayerReady(event) { event.target.pauseVideo(); }YouTube Player API のサンプルにあった記述です。
3のonReady
で指定した関数で、ビデオレイヤーの準備できたら動画を一時停止させています。// 5.プレイヤーの状態が変化すると実行 var done = false; function onPlayerStateChange(event) { // 再生 if (event.data == YT.PlayerState.PLAYING && !done) { // 左右に体を揺らす setTimeout(executeAction, 8000, deviceId, 'swing'); done = true; } }YouTube Player API のサンプルにあった記述です。
3のonStateChange
で指定した関数で、プレイヤーの状態が変化すると実行されます。
setTimeout
で動画が再生されてから8秒後にexecuteAction
関数を実行します。// ふるまいを実行 function executeAction (deviceId, eventId) { callActionApi(deviceId, 'play_motion', '{"Category": "' + eventId + '", "Mode": "NONE"}'); }
executeAction
関数では、 Action API にある PlayMotion の POST リクエストで必要な情報をcallActionApi
関数の引数に渡して実行しています。// Action API 呼び出し function callActionApi (deviceId, apiName, arguments) { postUrl = BASE_PATH + '/devices/' + deviceId + '/capabilities/' + apiName + '/execute'; data = '{"arguments":' + arguments + '}'; // POST API postApi(postUrl, data); }
callActionApi
関数では、POST する URL とコンテンツの生成を行い
postApi
関数の引数に渡して、実行しています。// POST API function postApi (url, argary) { url = url ? url : ''; fetch(url, { method: 'POST', mode: 'cors', headers: { Authorization: 'Bearer ' + ACCESS_TOKEN }, body: argary }) .then(function (response) { return response.json(); }) .then(function (data) { outputResult(data.executionId); }) }ヘッダーに
Authorization:Bearer
を追加して、body を POST します。
aibo が処理を成功したか判定するために、レスポンスで返ってきた値executionId
をoutputResult
関数の引数に入れて実行します。// API 実行結果 出力 function outputResult (id) { const url = BASE_PATH + '/executions/' + id; fetch(url, { method: 'GET', mode: 'cors', headers: { Authorization: 'Bearer ' + ACCESS_TOKEN } }) .then(function (response) { return response.json(); }) .then(function (data) { // API 実行結果 出力 console.log(data); }) }引数で渡ってきた
executionId
を元に、API の実行結果をコンソールに出力するようにしています。実行
それでは実行します。
イントロが終わったら、ルンルンし始めるおチャコさんです。課題
ACCESS_TOKEN と deviceId のベタ書きはセキュリティ上よろしくない
developer tools を使えばソースを表示することができてしまいます。
ローカル環境で実行する分には問題ないのですが、公開するのであれば大事な aibo の情報を晒さないようにひと工夫必要です。aibo の集中力が試される
自由気ままにお散歩して、いろんなものに興味津々な aibo。
そんな aibo に天の声を届けようにも気が散ってしまってプログラムの実行が遅れます。
プログラムをきちんと実行してもらうには、事前に SetMode で指示待ちの状態にする必要がありそうです。aibo へ天の声が届くまでに時差がある
端末 → クラウド → aibo へ天の声が届くまでに4秒ぐらいの時差があります。
ですので、その時差を考慮しながらふるまいを早めに実行してあげる必要があります。ドキュメントに記載されているふるまいの動きがわからない
API にある PlayMotion だけで 76 種類ものふるまいが用意されているのですが
ダンスの振り付けをしようにも、ドキュメントはテキストベースなのでどんな動きをするのかピンとこない。
どこかのタイミングで1つ1つの動きを動画にして参照できるようにしようかなと考えています。実行
それでは実行します。
おわりに
現状だと API でできることも限られているので、もっと動きの選択肢が増えるといいな〜!
特別なふるまいがまるっと実行できなくても、実装済みの素敵な動きを
1つずつ API 実装していただければ、よりかわいいダンスの振り付けを
aibo に覚えてもらうことができる…。aibo がアイドルのように…。
いつか東京あいぼるで aibo たちにダンスしてもらえる日を夢見て。次回は、説明を端折っていた API のリクエストに必要となる
deviceId の取得方法を紹介したいと思います。それではまた次回!
- 投稿日:2020-08-04T21:47:16+09:00
JSONトークンで認証ができるようにする
JSONトークンでできること
ある操作が、他の人からはできないようにする
例)
「削除」ができるのは「作成者」のみ、に制限するトークン生成のためのnpmパッケージをインストール
・「jsonwebtoken」https://www.npmjs.com/package/jsonwebtoken
というパッケージを利用$ npm install jsonwebtokenでインストール
・jsonトークンを作ってみる
<公式ドキュメントより>使い方
jwt.sign(payload, secretOrPrivateKey, [options, callback])(非同期) コールバックが与えられた場合は、 err または JWT でコールバックが呼び出されます。
(同期) JsonWebToken を文字列で返します。
(中略)
デフォルトの同期処理(HMAC SHA256)
var jwt = require('jsonwebtoken');
var token = jwt.sign({ foo: 'bar' }, 'shhhhh');const jwt = require('jsonwentoken') const myFunction = async() => { const token = jwt.sign({_id: 'abc123'}, 'thisismykeyword') //第一引数:データベースの中の一意な値・第二引数:トークン作成の署名となる好きな文字列 console.log(token) //作成したトークンを表示 } myFunction() //jsonトークンを作成する同期処理を実行jsonトークンが作成されていたら、console.logで確認できるはず
※jsonトークンの構成:base64でエンコードされている(BASE64でデコード可能)
※デコードすると、トークンの中の情報に、トークン化したid({_id: 'abc123'})と、トークン作成時点のタイムスタンプが含まれているのがわかるトークンを認証に使う
const jwt = require('jsonwebtoken') const myFunction = async() => { const token = jwt.sign({_id: 'abc123'}, 'thisismykeyword',{exporeIn: 'days'}) //第三引数:何日でトークンの効果が切れるか console.log(token) const data = jwt.veryfy(token, 'thisismykeyword')//tokenと、トークン作成の署名となる文字列とで認証 console.log(data) } myFunction()・トークン作成の署名となる文字列
・トークンの効果が切れる期間でエラーを判定
トークンをアプリに組み込む
・アプリのファイル構成
└── src ├── index.js //アプリのメイン処理を記述 ├── models //データベースのためのフィールド設定 ├── middleware //ミドルウェアを設定 └── routers //ルーティング処理●models/user.js
データベースにtokenを保存するよう、データベースのスキーマを設定const jwt = require('jsonwebtoken') const userSchima = new mongoose.Schema({ //mongooseを用いてデータベースのスキーマを定義」 name: { type: String, //データ型の設定 required: true, trim: true }, password:{ type: String, required: true, trim: true, minlength: 7, validate(value){ //toLowerCaseによって、小文字も大文字も小文字と認識される if(value.toLowerCase().includes('password')){ throw new Error ('Do not use "password" to password') } } }, tokens: [{ //tokensの項目を新たに設定 token: { type: String, require: true } }], }) //インスタンスにはメソッドを使って実装。generateAuthToken関数で、トークンを作成しDBへ保存 userSchema.methods.generateAuthToken = async function () { //generateAuthToken関数を定義 const user = this //thisとは、userSchimaで定義したもの const token = jwt.sign({ _id: user._id.toString() }, 'thisismykeyword') user.tokens = user.tokens.concat({ token: token })//concatで、tokensの配列と、入力したtokenがuserのtokenと一致するものを結合する await user.save()//新しいuserをデータベースに保存 return token //返り値にtoken変数を設定 } //モデルにはクラスを使って実装。findbyCredentials関数で、Eメールとパスワードを元にDBを検索 userSchema.statics.findByCredentials = async (email, password) => { const user = await User.findOne({ email }) //emailの値が、引数のemailに一致 if(!user){ //入力したEメールがデータベースにない throw new Error('Unable to login') } const isMatch = await bcrypt.compare(password, user.password) if(!isMatch){ //入力したパスワードがデータベースにない throw new Error('Unable to login') } return user }●routes/users.js
ルーティング処理時にJSONトークンを利用する・JSONトークンの作成と保存
→user作成時の処理router.post('/users', async (req, res) => { const user = new User(req.body) try { await user.save() const token = await user.generateAuthToken() //「models/user.js」で定義したgenerateAuthToken関数を実行 res.status(201).send({user, token}) } catch (e) { res.status(400).send(e) } })・JSONトークンを用いて認証する
→userログイン時の処理router.post('/users/login', async (req, res) => { try { const user = await User.findByCredentials(req.body.email, req.body.password) //User.findByCredentials()はEメール、パスワードを引数にとり、userをemailによって検索し、パスワードをverifyする const token = await user.generateAuthToken() res.send({ user, token }) //ログインに成功した時の処理 }catch(e){ res.status(400).send() } })ミドルウェアを使ってJSONトークン認証を設定する
・ファイル構成
└── src ├── index.js //アプリのメイン処理を記述 ├── models //データベースのためのフィールド設定 ├── middleware //ミドルウェアを設定 └── routers //ルーティング処理●「middleware/auth.js」
に、ミドルウェアとなるコードを記述しモジュールをエクスポート・ミドルウェアの設定
●middleware/auth.js
const auth = async (req, res, next) => { console.log('認証ミドルウェアが動いています') next() } module.exports = authモジュールの雛形を作成
●routes/user.js
モジュールの読み込みconst auth = require('../middleware/auth') //ミドルウェアモジュールの読み込み router.get('/users/me', auth, async (req, res) => { //第二引数にミドルウェア・第三引数にルーティング処理 res.send(req.user) })GETリクエスト時に「認証ミドルウェアが動いています」とcosole.logされていればOK
●middleware/auth.js
・作成されたJSONトークンをコード内に取り込む
HTTPのヘッダーに送られているJSONトークン(key=Authorization)を読み込むconst auth = async(req, res, next) => { try{ const token = req.header('Authorization') console.log(token) }catch(e){ res.status(401).send({error: '認証してください'}) } }●middleware/auth.js
認証させるconst jwt = require('jsonwebtoken') //jwtモジュールの読み込み const User = require('../models/user') //userデータベースの読み込み const auth = async (req, res, next) => { //HTTPヘッダーからJSONトークンの読み込み try { const token = req.header('Authorization').replace('Bearer ', '') const decoded = jwt.verify(token, process.env.JWT_SECRET) //jwtを作るのに使った秘密の文字列を用いてデコード const user = await User.findOne({ _id: decoded._id, 'tokens.token': token }) //userデータベースのidが、decodeしたJSONトークンの中に含まれるidと一致し、userデータベースのtokens配列の中のtokenと、tokenが一致 if(!user){ throw new Error() } req.token = token req.user = user next() } catch (e) { res.status(401).send({error: 'please authenticate'}) } } module.exports = auth
- 投稿日:2020-08-04T21:24:22+09:00
Blobって
Blobって
Blob - MDN Web Docs - Mozilla
Blob オブジェクトはファイルに似たオブジェクトで、immutable な生データです。データを表す blob は必ずしも JavaScript ネイティブなフォーマットではありません。File インターフェイスは Blob を基礎にしておりArrayBuffer とビューは ECMA 規格、JavaScript の一部です。
ブラウザには、さらに File API に記載されている高水準のオブジェクトがあります。特に Blob です。
Blob はオプションの文字列 type (通常は MIMEタイプ) と blobParts – 一連の他の Blob オブジェクト、文字列や BufferSources から構成されます。
コンストラクタの構文は次の通りです:
new Blob(blobParts, options);blobParts は Blob/BufferSource/String の値の配列です
options オプションのオブジェクト:
type – blob タイプ, 通常は例えば image/png のような MIME タイプです,
endings – blob が現在の OS の改行(\r\n or \n)に対応するように行末を変換するかどうかを意味します。デフォルトでは "transparent" (何もしません)ですが、 "native" (変換する)にすることもできます。
Blob を base64 にする
URL.createObjectURL の代替は blob を base64 エンコードされた文字列に変換する方法です。Image を blob にする
画像、画像の一部、あるいはページのスクリーンショットの blob を作成することもできます。どこかにアップロードするときに便利です。画像操作は 要素を通して行われます:
canvas.drawImage を使って、canvas 上で画像(または一部)を書きます。
blob を作成し、完了時に callback を実行する canvas メソッド .toBlob(callback, format, quality) を呼び出します。
- Blob から ArrayBuffer へ Blob コンストラクタは、BufferSource を含め、ほぼ何からでも blob を作成することができます。
しかし、低レベルの処理を実行する必要がある場合、FileReader を使って、最も低レベルである ArrayBuffer を取得することもできます。:
- 投稿日:2020-08-04T20:51:47+09:00
【JS】if文の中でletが使えない...
やりたいこと
function fullname(first, last) { let last_name = ""; if (typeof last === "string") { last_name = last; } return first + last_name; } console.log(fullname("山田", "太郎")); // => 山田太郎この
let
をconst
にしたい。でも、再代入できないよなあ。ってことで三項演算子ちゃん
unction fullname(first, last) { const last_name = typeof last === "string" ? last : ""; return first + last_name; } console.log(fullname("山田", "太郎")); // => 山田太郎スッキリかけるけど、可読性が落ちる。ケースバイケース。
- 投稿日:2020-08-04T20:42:57+09:00
JSについて本気出して考えてみた
はじめに
こんにちはばーんです
今回はJavaScriptの言語仕様について書いていきます。JavaScriptの勉強会参加と(https://x-hack.connpass.com/)
その際に勧められた書籍を読んで、自分で得た知識を整理していきます。なるべく言語仕様書のように堅苦しくなく説明していくよう心掛けますw
今回の対象者
【JavaScriptは殆どオブジェクトである】という言葉の意味が理解できていない方
- そもそもオブジェクトって何?
- これってメソッド?プロパティ?
- console.log("hello world") が "hello world" を表示するまでに何をしているのか?
といったことを解決していきたいと思います。
ゴール
【JavaScriptは殆どオブジェクトである】が理解できる
具体的には下記の内容を理解できればOKだと思っています。
①「そもそもオブジェクトがどういうものか?理解する」
↓
②「JavaScriptがどういうもので構成されているか知る」
↓
③「どういう流れで普段自分たちが②を意識せずに使えているか知る」第1章: オブジェクト / プロパティ / メソッド って何?
前段の通りJavaScriptは殆どがオブジェクトです。
関数も配列も
※3章で掘り下げますオブジェクトとは「名前と値を持つプロパティを格納するコンテナ」です。
例えば下記のようなオブジェクトがあった場合は、const baan = { age: 31, gender: "man", sayHello: function () { console.log("こんにちは!"); }, };オブジェクト / プロパティ / メソッドを下記のように分類できます。
const baan = { age: 31, // ageという名前(キー)と31という値を持つプロパティです gender: "man", // genderという名前(キー)とmanという値を持つプロパティです sayHello: function () { console.log("こんにちは!"); }, // sayHelloという名前(キー)と値に関数を持つプロパティです // このプロパティの値はメソッドとなります }; console.log(baan); // 出力: { age: 31, gender: 'man', sayHello: [Function: sayHello] } // baan は3つのプロパティを持ったオブジェクトです baan.sayHello(); // 出力: こんにちは!自分自身もオブジェクト、プロパティ、メソッドは混乱していましたが、このように明示できます。
オブジェクトのプロパティへのアクセス方法
どのようにオブジェクトを使用するか?ということです。
オブジェクト名 + ドット + プロパティ名(名前またはキー)でアクセスできます。
ちなみに関数の場合は()をつけることで実行されます。const baan = { age: 31, gender: "man", sayHello: function () { console.log("こんにちは!"); }, }; console.log(baan.age); // 出力: 31 console.log(baan.gender); // 出力: man baan.sayHello(); // 出力: こんにちは! baan.sayHello; // 何も出力されません (sayHelloにアクセスしていますが括弧演算子がついていないので)※ドット記法とブラケット記法がありますが、話が逸れるのでブラケット記法については書きません。
Point: console.log()は関数です
※正確には関数ではなくconsoleオブジェクトの中のメソッドの1つですが、伝わりやすくする為上記のような表記としています。
当時JS完全に理解した状態だった自分は、関数と聞くと
function () { "hogehoge" };みたいなモノを想像していました。
しかし、初学者にとっても馴染みの深いconsole.log()が関数だったなんて!と衝撃を覚えました。このようにchromeのDevtoolにconsole.logを入力すると
ƒ log() { [native code] }
と表記されます。 ƒ はfunctionのことですね^^
第1章まとめ
- オブジェクトはただの箱
- 中に0個以上のプロパティを持っている
- 使う時はオブジェクト名とキーをドットで繋げる
- 関数を値に入れるとメソッドになる
このことを念頭に読み進めて頂けるとm_ _m
第2章: JSの構成要素を知る
まずここでは、JavaScriptがどのような要素で構成されているか?を見ていきます。
結論から言うとJavaScriptはプリミティブ値とネイティブオブジェクト(コンストラクタ)で構成されています。
プリミティブ
原始的な、基本の みたいな意味ですね。
JavaScriptでは数字、文字列、真偽値などが当てはまります。
(https://developer.mozilla.org/ja/docs/Glossary/Primitive)ネイティブオブジェクト(コンストラクタ)
はい。こちらがややこしいので詳しく書いていきます。
コンストラクタ(関数)
そもそもコンストラクタ(関数)とは、
new演算子を使って実行されるとオブジェクトを生成する関数です。ちょっと待って下さい。ブラウザバックしないで欲しい。
// ①最初にこれを実行するとエラーが出ます console.log(baan); const baan = new Object(); // 出力: ReferenceError: Cannot access 'baan' before initialization// ②次にこちらを実行して下さい const baan = new Object(); console.log(baan); // 出力: {}当然といえばそうですが、①はbaanを定義していないので構文エラーが出ます。
②はnew演算子を使って実行しているので空のオブジェクトが生成されています。
これを普段見慣れているような形にすると、// ③普段見かける形 const baan = new Object(); baan.age = 31; baan.gender = "man"; console.log(baan); // 出力: { age: 31, gender: 'man' }このObject()の部分がコンストラクタ関数です
ネイティブオブジェクト(コンストラクタ)
そして、原始的に用意されているネイティブオブジェクトは9つです。
Number()
String()
Boolean()
Object()
Array()
Function()
Date()
RegExp()
Error()これ以外を宣言するとエラーが出ます。
// 無作法に新しいコンストラクタはできません const baan = new Person(); baan.age = 31; baan.gender = "man"; console.log(baan); // 出力: ReferenceError: Person is not definedちなみにPersonを使用したい場合は、
const Person = function Person(age, gender, sayHello) { this.age = age; this.gender = gender; this.sayHello = sayHello; this.sayHello = function () { return sayHello; }; }; const baan = new Person(31, "man", "こんにちは!"); console.log(baan); // 出力: Person { age: 31, gender: 'man', sayHello: [Function (anonymous)] } console.log(baan.sayHello()); // 出力: こんにちは!このようにコンストラクタ関数を宣言すればOKです!
これで想定通りの振る舞いになりました^^2章まとめ
- JavaScriptはプリミティブ値とネイティブオブジェクト(コンストラクタ)で構成されている
- コンストラクタをnewすることでオブジェクトが生成される
第3章: 殆どがオブジェクトである理由を知る
ここではネイティブオブジェクト(コンストラクタ)から、どのようにして普段使っているオブジェクトになっているのかを掘り下げていきます。
その為には1章の冒頭部分を掘り下げていきます。前段の通りJavaScriptは殆どがオブジェクトです。
関数も配列も関数オブジェクトについて
関数もオブジェクトです。なので値としてセットできます。
例えば関数の引数であったり、メソッドとして。const plusFunc = function (x, y) { return x + y; }; const subtractFunc = function (x, y) { return x - y; }; console.log(plusFunc(5, subtractFunc(4, 1))); // plusFuncの引数は2つあります。この場合数値の5とsubtractFuncという関数です // 今回subtractFuncは引数に4と1を持っており結果として3を返します。なので // 出力: 8 (5 + 3なので)※メソッドについては1章で触れているので省略します
また、ネイティブオブジェクト(コンストラクタ)についてですが、
const myFunction = new Function("x", "y", "return x + y"); console.log(myFunction); // [Function: anonymous] console.log(myFunction(1, 3)); // 出力: 4 const result = myFunction(2, 3); console.log(result); // 出力: 5このようにnewすることで、無名関数を生成しています。
もう少しわかりやすくする為chromeのDevtoolを使います。無名関数が生成されていますね^^
※ただし、Functionコンストラクタによる関数の生成は推奨されません。これは、JSエンジンによる最適化を妨げたり、他の問題を引き起こしたりする場合があるためです。
配列オブジェクトについて
こちらも関数同様にネイティブオブジェクト(コンストラクタ)をnewしてみます。
// ①ネイティブオブジェクト(コンストラクタ)を使用した配列の生成 const myArr = new Array(1, "test"); console.log(typeof myArr); console.log(myArr[0]); console.log(myArr[1]); // ②配列リテラルを使用した配列の生成 const myArray = [1, "test"]; console.log(typeof myArray); console.log(myArray[0]); console.log(myArray[1]); // myArrもmyArrayも出力は全て同じです // 出力: object / 1 / test普段私たちは②を使用していると思います。
が、内部的にはJavaScriptがよしなにやってくれているだけで、配列の生成は①で行われています。このように普段使用している関数も配列もオブジェクトです。
そして、それらはネイティブオブジェクト(コンストラクタ)より生成されています。なので「JavaScriptは殆どオブジェクト」なのです。
ちょっとまってプリミティブ値は?
2章まとめ
- JavaScriptはプリミティブ値とネイティブオブジェクト(コンストラクタ)で構成されている
ここで述べているプリミティブ値はどーなんの?
という話ですが、プリミティブ値はオブジェクトでラップされる時があります。
つまり、擬似的にオブジェクトのように振る舞います。const num = 1 console.log(num.toString()); console.log((1).toString()); // 出力: "1"本来1(数値)はプリミティブ値なのでtoStringのプロパティを持ちませんが、プリミティブ値のプロパティにアクセスする際に、オブジェクトでラップされるのでこのような表現になります。
3章まとめ
つまり1〜3章をまとめて
「JavaScriptは殆どオブジェクト」なのです。番外編: グローバルオブジェクト / プロトタイプチェーンを知る
自分自身が衝撃を受けた項目があるので、最後に番外編として追記させて頂きます。
グローバルオブジェクト
私たちがconsole.log()を使用する時、consoleオブジェクトについてはそれほど考えないと思います。
ただ、それでもchromeのDevtoolにconsole.logを入力すると使えてしまいます。それはつまり、JavaScriptがよしなにやってくれてます。
具体的にブラウザは、グローバルオブジェクトとしてwindowオブジェクトを持っています。
※正確にはブラウザを立ち上げたクライアントPCのメモリ上に、グローバルオブジェクトを展開していますそして、 console はオブジェクトであり、 window のプロパティです。 log はメソッドです。
①まずchromeのDevtoolにwindowを入力します
②windowのプロパティを見てみると大量のプロパティが設定されてあります
// いつも書いてる形 console.log("hoge") // こちらでも同じ結果が出力される window.console.log("hoge")ちなみにブラウザ上なのでwindow.console.log("hoge") でも動きますが、Node.jsではエラーが出ます(ReferenceError: window is not defined)
グローバルオブジェクトが違うので。外面は同じですが内面は違う動きをしています。プロトタイプチェーン
const myArr = [1, 2]; console.log(myArr); // 出力: [ 1, 2 ] const result = myArr.join(""); console.log(result); // 出力: 12普段私たちは配列を操作する時にこのようにメソッドを使用します(今回は join)。
このような時にmyArrにjoinというプロパティを定義しましたか?していません。ですが、実際に私たちは明示的にjoinを定義しなくても使えています。
それにはJavaScriptのプロトタイプチェーンが関係しています。まずプロトタイプチェーンを文面だけで説明すると、
ネイティブオブジェクトコンストラクタ関数(Object, Function, Arrayなど)はオブジェクトを生成する際にprototypeプロパティを継承させます。
待って諦めないで聞いて欲しい。スクロールはもう少し我慢して欲しい。
配列を例に説明していきます。まず、配列を作る時、普段は
const myArr = [1, 2];と宣言します。
これは、第3章>配列オブジェクトで記載している通りconst myArr = new Array(1, 2);と同意です。つまり、ネイティブオブジェクトコンストラクタ関数である Array()をnewしてインスタンス(この場合myArr)を生成しています。
そして、その際にprototypeというプロパティを継承させています。なので、私たちは明示しなくともjoinというメソッドが使えるのです。
プロトタイプチェーンは今回の場合であれば、myArrにjoinメソッドがないと判断するとエラーを返すのではなく遡って確認しにいきます。
※最終的にはObject()まで確認しにいきます
自分はプロトタイプチェーンを知ってから格段におまじないみたいなコードが減りました。
何故エラーが出るか?どういう仕組みで?が理解できたので。簡単に言うとprototypeでリンクしているというイメージでいいかと思います。ブラウザでは
__proto__
という表記のものもあります。補足
何点か補足事項があります。
今回書けなかった話
- thisとは?
- classとは?
- インターフェースとは?
- 予約語とは?
この辺りは次回以降にまとめていこうと思います。
書籍について
開眼!JavaScriptという本です。
とても楽しく読める言語仕様についての本でした^^
ただし、恐らく勉強始めてすぐにこれに出会っていても自分は理解できなかったと思います。できればJavaScriptで何か動かしてから購入をおすすめします。
(道中呪文みたいな文章結構あるので)質問 / ツッコミに関して
この記事に関して細部の認識はずれている可能性があります。
技術的なマサカリwは大歓迎ですので、何かあれば遠慮なくコメント頂けると幸いです。参考サイト
参考にさせていただきましたm_ _m
ありがとうございました^^https://developer.mozilla.org/ja/docs/Web/JavaScript
https://nodejs.org/api/console.html
https://harakotan.hatenablog.jp/entry/2015/05/17/004707
https://www.tweeeety.blog/entries/2014/02/05さいごに
今回自分がこの記事を書くきっかけになったのはxhackさんの勉強会がきっかけでした。
参加していなければ理解が浅いまま進んでいたと思います。
この場を借りてお礼申し上げます。ありがとうございましたm_ _mそれではまた^o^/
- 投稿日:2020-08-04T20:35:44+09:00
【JS】分割代入のお作法(ES2015)
- 投稿日:2020-08-04T20:29:39+09:00
meta description にREADME のテキストがセットされてしまう現象
先日仕事で Web ページの不具合修正しデプロイ、その日は問題なく終了。そして数日が経ちました。
ある日マーケティングチームから Slack から一報が。meta description に変な値が設定されているのですが、確認していただけますか?
さすがに驚いて確認したところ、コンフルエンスの URL が設定されていた…
これは完全に凡ミスで、いくつかの条件が重なって発生した問題です。後述しますが、普通に
create-nuxt-app
を使ってプロジェクトを立ち上げた場合は大丈夫だと思います。状況および事象
まずは各ファイルの設定です。
nuxt.config.js(一部抜粋)... head: { title: process.env.npm_package_name || '', meta: [ { charset: 'utf-8' }, { name: 'viewport', content: 'width=device-width, initial-scale=1' }, { hid: 'description', name: 'description', content: process.env.npm_package_description || '' // ←ここが今回のポイント } ], link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }] }, ...package.json(一部抜粋){ "name": "project-name", "version": "1.0.0", "author": "kkeeth", "private": true, ... (description の設定無し)README.md# project name hogehoge
この場合、meta description がどうなるかと言うと、タイトル通り README のテキストが設定されます。実際のブラウザのキャプチャがこちら↓↓↓
これの修正方法は簡単で、
- nuxt.config.js に description のデフォルト値を設定する
- package.json の description を設定する
README は他の値を設定することもありますので、あまりおすすめしません。
原因究明
ではこの事象の根本的原因はなんだったのか?
▼仮説1
「これはNuxt
がデフォルトでこの値を設定している?」
↓
ということで、Nuxt
のソースコードを読むも原因が分からず…▼仮説2
「いや、確かNuxt
はmeta
情報を vue-meta というライブラリで扱ってなかったか?」
↓
ということで、vue-meta
のソースコードを読むも原因が分からず…ここでハッと気付く…
正解
「
process.env.npm_package_description
だから、npm がデフォルトの値を設定していないか?」
↓
ということで、npm 公式サイト を見ますと、しっかり書いてありました。。。description: info from the README, or an empty string ""
はい。package.json に description がない場合は README から設定する1、なければ空文字列をセットします(実際に動作確認してみました)。2 要は、npm の仕様だったわけです。
余談
現在は
create-nuxt-app
でプロジェクトを作成しますと、nuxt.config.js の記述は以下のように npm ではなく package.json の設定を利用するようになっております。nuxt.config.js+ import pkg from './package' head: { - title: process.env.npm_package_name || '', + title: pkg.name, meta: [ { charset: 'utf-8' }, { name: 'viewport', content: 'width=device-width, initial-scale=1' }, { hid: 'description', name: 'description', - content: process.env.npm_package_description || '' + content: pkg.description } ], link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }] },したがって、今回の問題はかなりのエッジケースになりますのでご安心ください。
まとめ
- 公式の CLI のボイラープレートを信じよう
- package.json の
description
はちゃんと書こうではでは(=゚ω゚)ノ
- 投稿日:2020-08-04T19:51:06+09:00
【JS】データ型について学ぶ
プリミティブ型とオブジェクト
データ型を大きく分けるとプリミティブ型とオブジェクト**の二つに分けることができます。
プリミティブ型
一度作成したらそのあとで変更することができない(イミュータブル)な特性を持つ。
- 真偽値(true,false)
- 数値(1,2.3など)
- 文字列("test"など)
- シンボル
- BigInt
- null
- undefined
この七種類がJSにおけるプリミティブ型です。
オブジェクト
作成したあとでも変更することができる(ミュータブル)な特性を持つ。
- プリミティブ型以外のデータ
- 配列,オブジェクト,関数など
データ型を調べるメソッド
typeof
を使えばOKconsole.log(typeof "name"); // => string console.log(typeof 111); // => number console.log(typeof true); // => boolean console.log(typeof []); // => object console.log(typeof {}); // => object
- 投稿日:2020-08-04T19:35:40+09:00
モバイルでのモーダル表示時の背景スクロール禁止処理
以前よりhtml, body への
overflow:hidden;
はiOS Safari(webkit)では効かないため
主にjQueryでtouchmove
イベントにpreventDefault();
で対応していたが以前のコード// スクロール無効 $(window).on('touchmove.noScroll', function(e) { e.preventDefault(); }); // スクロール無効を解除 $(window).off('.noScroll');
iOS 11.3 Safari 11.1
及びChrome 51
以降はaddEventlistner
の第3引数に{ passive: false }
を渡して対応する必要がある。document.addEventListener('touchmove', function(e) { e.preventDefault(); }, { passive: false });exfunction scroll_control(e) { e.preventDefault(); } function no_scroll(){ document.addEventListener("touchmove", scroll_control, {passive: false}); } function return_scroll(){ document.removeEventListener('touchmove', scroll_control, {passive: false}); }
preventDefault()
の付け外しはex
のように関数化しないとうまくいかなかった。
また'passive' オプションに未対応ブラウザのためにPolyfill
を書く必要がある。polyfill// Test via a getter in the options object to see if the passive property is accessed var supportsPassive = false; try { var opts = Object.defineProperty({}, 'passive', { get: function() { supportsPassive = true; } }); window.addEventListener("testPassive", null, opts); window.removeEventListener("testPassive", null, opts); } catch (e) {} // Use our detect's results. passive applied if supported, capture will be false either way. elem.addEventListener('touchstart', fn, supportsPassive ? { passive: true } : false);※
elem
fn
の箇所と{ passive: true }
を適宜変更して使用Browser
- webkit
- chrome
対応方法の参考リンク
- スクロール禁止が overflow:hidden や preventDefault(); でできないときの対処法
- マウスによるスクロールやスマホのスワイプを制御するjs(passive: false)
- Not working with iOS 11.3 Mobile Safari
- Can't prevent
touchmove
from scrolling window on iOSPassive Event Listenersについての参考リンク
- Passive event listeners
- Passive Event Listeners によるスクロールの改善
- Passive Event Listenersのミニマムpolyfillを書いた。
- addEventListener の第3引数が拡張されてるという話
- 投稿日:2020-08-04T19:02:18+09:00
Javascriptのfetch
初心者が解説のサイトなどを見て、Javascriptのfetch()を理解しようとしています。
参考 fetch() の基本的な使い方
- fetch() メソッドは従来の XMLHttpRequest や jQuery の $.ajax() を使って実現していたような、 リモートリソースの非同期取り込みに使える
- 非同期呼び出しは Promise で実装されていて、then() で Response オブジェクトを受け取
- ネットワークエラー以外は、基本的に最初の then() まで到達します。最初の then((response)) で response.ok や response.status をチェックすることで、サーバー側からの応答の状態を確認できます。
- エラーを検出したら、Error() オブジェクトをスローすることで、catch() に処理が移る
Fetchの利用
- サービスワーカーのような他の技術から簡単に利用することができます。 Fetch は CORS や HTTP 拡張のような HTTP に関連する概念をまとめて定義する場所でもあります。fetch('http://...',{オプション}) .then((response)=>{ if(!response.ok){ throw new Error(); } return response.blob();//あるいは response.json() }) .then((blob)=>{ }) .catch((reason)=>{ //エラー });fetch() による GET リクエストの送信
fetch('/test1') .then((res) => { if (!res.ok) { throw new Error(`${res.status} ${res.statusText}`); } return res.blob(); }) .then((blob) => { // ... }) .catch((reason) => { console.log(reason); }); fetch() による POST リクエスfetch() による POST リクエストの送信
const data = new FormData(); data.set('message', 'Hello!'); fetch('/test', { method: 'POST', cache: 'no-cache', body: data }) .then((res) => { if (!res.ok) { throw new Error(`${res.status} ${res.statusText}`); } return res.blob(); }) .then((blob) => { // blob にレスポンスデータが入る }) .catch((reason) => { console.log(reason); });JSON文字列をポストする場合
const data = { message: 'Hello' }; fetch('/test', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }) .then((res) => { if (!res.ok) { throw new Error(`${res.status} ${res.statusText}`); } return res.blob(); }) .then((blob) => { // blob にデータが入る }) .catch((reason) => { console.log(reason); });?やばい、よくわからない
- 最初の then((response)) にて、return response.blob() とすることで、 レスポンスの内容を Blob オブジェクトに詰め込んで、次の then() に渡すことができます。
Blobオブジェクトとは:
- fetch() から返される Promise は レスポンスが HTTP 404 や 500 を返して HTTP エラーステータスの場合でも拒否されません。代わりに (ok ステータスが false にセットされて) 正常に解決し、拒否されるのはネットワークのエラーや、何かがリクエストの完了を妨げた場合のみです。
- fetch() はサイトをまたぐクッキーを受け付けません受信することができます。フェッチを使用してサイトをまたぐセッションを確立することができませんできます。他のサイトからの Set-Cookie ヘッダーは暗黙に無視されます。
- fetch はサーバーとの間で cookies を送受信しないため、サイトがユーザーセッションの維持に頼っている場合は未認証のリクエストになります。クッキーを送るには、認証情報の init オプションを設定しておく必要があります。
簡単な例
fetch('http://example.com/movies.json') .then(response => response.json()) .then(data=>consol.elog(data));参考
これを実際に使ってみたら何となく理解できたような気がする<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <title>サンプル</title> </head> <body > <input type="button" value="ボタン1" onclick="clickBtn1()"> <input type="text" name="cs1" id="cs1" value="custom1" maxlength="7"> <input type="text" name="cs2" id="cs2" value="custom2" maxlength="7"> <script> function clickBtn1(){ // URLSearchParamsに画面の値をセット const para1 = new URLSearchParams(); para1.set("cs1",document.getElementById("cs1").value); para1.set("cs2",document.getElementById("cs2").value); fetch("http://httpbin.org/get?" + para1.toString()) .then(function(response1) { //成功時に実行される console.log("status=" + response1.status); //status=200 return response1.json(); }) .then(function(data1) { //成功時に実行される console.log(JSON.stringify(data1)); //JSONを出力 }) .catch(function(err1) { //失敗時に実行される console.log("err=" + err1); }); } </script> </body> </html>Service WorkersではこのFetch APIを使うことになっている
お疲れさまXMLHttpRequest、こんにちはfetch
Service Workersでは、XMLHttpRequestが使えません。その代わり、XMLHttpRequest (以下、XHR)に代わるWHATWGの仕様としてFetch APIがあり、Service WorkersではこのFetch APIを使うことになっていますので、その使い方を簡単に紹介します。
Fetch API自体は、Service Workers専用のものではなく、メインスレッドでもXHRの代わりに使うことが可能です。
fetch('URLあるいは相対パスなど').then(...);
- 投稿日:2020-08-04T18:12:32+09:00
P5.js 日本語リファレンス(translate)
このページでは「P5.js 日本語リファレンス」 の translate 関数を説明します。
translate()
説明文
表示ウィンドウ内のオブジェクトを移動する量を指定します。 x パラメータは左/右への移動を指定し、y パラメータは上/下への移動を指定します。
変換は累積的であり、関数への後続の呼び出しが効果を累積した後に発生するすべてに適用されます。たとえば、translate(50, 0) を呼び出してから translate(20, 0) を呼び出すことは translate(70, 0) と同じです。 draw() 内でtranslate() が呼び出された場合、ループが再び始まると変換がリセットされます。この関数は push() および pop() を使用してさらに制御できます。
構文
translate(x, y, [z])
translate(vector)
パラメタ
x
Number:左/右変換y
Number:アップ/ダウン変換z
Number:順方向/逆方向変換(webglのみ)(オプション)vector
p5.Vector:変換するベクトル例1
function setup() { createCanvas(400, 400); stroke("red"); rect(0, 0, 55, 55); stroke("green"); translate(30, 30); rect(0, 0, 55, 55); stroke("blue"); translate(30, 30); rect(0, 0, 55, 55); }実行結果
https://editor.p5js.org/bit0101/sketches/PI43OkNFn
例2
function setup() { createCanvas(200, 200); } function draw() { background(200); rectMode(CENTER); translate(width / 2, height / 2); // ミリ秒を1000で割った数を角度とし長さ60のベクトルを作成する。 // (回転する半径が60になる) translate(p5.Vector.fromAngle(millis() / 1000, 60)); rect(0, 0, 20, 20); }実行結果
https://editor.p5js.org/bit0101/sketches/tVYVP1BjY
著作権
p5.js was created by Lauren McCarthy and is developed by a community of collaborators, with support from the Processing Foundation and NYU ITP. Identity and graphic design by Jerel Johnson.
ライセンス
Creative Commons(CC BY-NC-SA 4.0) に従います。
- 投稿日:2020-08-04T18:11:05+09:00
P5.js 日本語リファレンス(shearY)
このページでは「P5.js 日本語リファレンス」 の shearY関数を説明します。
shearY()
説明文
角度パラメータで指定された量だけ y 軸を中心に形状をせん断変形します。角度は angleMode で指定する必要があります。オブジェクトは常に原点に対する相対位置を中心にせん断変形し、正の数はオブジェクトを時計回りにせん断変形します。
変換は関数への後続の呼び出しが効果を蓄積した後に発生するすべてに適用されます。たとえば shearY(PI / 2) を呼び出してから shearY(PI / 2) を呼び出すことは shearY(PI) と同じです。 draw() 内でshearY() が呼び出された場合、ループが再び始まると変換がリセットされます。
技術的には shearY() は現在の変換行列に回転行列を乗算します。この関数は push() および pop() 関数によってさらに制御できます。
構文
shearY(angle)
パラメタ
- angle
Number:現在の angleMode に応じて、ラジアンまたは度で指定されたせん断角度例1
function setup() { createCanvas(200, 200); } function draw() { background(220); translate(10, 10); stroke("black"); rect(0, 0, 30, 30a); stroke("red"); shearY(PI / 6.0); // 角度30°を指定 rect(0, 40, 30, 30); stroke("green"); shearY(PI / 6.0); // 更に角度30°を指定 rect(0, 80, 30, 30); }実行結果
https://editor.p5js.org/bit0101/sketches/Wp-4pk72E
著作権
p5.js was created by Lauren McCarthy and is developed by a community of collaborators, with support from the Processing Foundation and NYU ITP. Identity and graphic design by Jerel Johnson.
ライセンス
Creative Commons(CC BY-NC-SA 4.0) に従います。
- 投稿日:2020-08-04T18:10:57+09:00
P5.js 日本語リファレンス(shearX)
このページでは「P5.js 日本語リファレンス」 の shearX関数を説明します。
shearX()
説明文
角度パラメータで指定された量だけ x 軸を中心に形状をせん断変形します。角度は angleMode で指定する必要があります。オブジェクトは常に原点に対する相対位置を中心にせん断変形し、正の数はオブジェクトを時計回りにせん断変形します。
変換は関数への後続の呼び出しが効果を蓄積した後に発生するすべてに適用されます。たとえば shearX(PI / 2) を呼び出してから shearX(PI / 2) を呼び出すことは shearX(PI) と同じです。 draw() 内でshearX() が呼び出された場合、ループが再び始まると変換がリセットされます。
技術的には shearX() は現在の変換行列に回転行列を乗算します。この関数は push() および pop() 関数によってさらに制御できます。
構文
shearX(angle)
パラメタ
- angle
Number:現在の angleMode に応じて、ラジアンまたは度で指定されたせん断角度例1
function setup() { createCanvas(200, 200); } function draw() { background(220); translate(10, 10); stroke("black"); rect(0, 0, 30, 30); stroke("red"); shearX(PI / 6.0); // 角度30°を指定 rect(40, 0, 30, 30); stroke("green"); shearX(PI / 6.0); // 更に角度30°を指定 rect(80, 0, 30, 30); }実行結果
https://editor.p5js.org/bit0101/sketches/OKHFZN84F
著作権
p5.js was created by Lauren McCarthy and is developed by a community of collaborators, with support from the Processing Foundation and NYU ITP. Identity and graphic design by Jerel Johnson.
ライセンス
Creative Commons(CC BY-NC-SA 4.0) に従います。
- 投稿日:2020-08-04T18:10:49+09:00
P5.js 日本語リファレンス(scale)
このページでは「P5.js 日本語リファレンス」 の scale関数を説明します。
scale()
説明文
頂点を拡大および縮小することにより、形状のサイズを拡大または縮小します。オブジェクトは常に相対的な原点から座標系にスケーリングされます。スケール値は10進数のパーセンテージとして指定されます。たとえば関数呼び出し scale(2.0) は図形の次元を200%増やします。
変換は関数の呼び出しの後に発生するすべてのものに適用され、効果が乗算されます。たとえば scale(2.0) を呼び出してから scale(1.5) を呼び出すことは scale(3.0)と同じです。 scale() がdraw() 内で呼び出された場合、ループが再び始まると変換がリセットされます。
WEBGLモードでのみ z パラメータを使用することができます。この関数は push() および pop() でさらに制御できます。
構文
scale(s, [y], [z])
scale(scales)
パラメタ
s
Number | p5.Vector | Number[]:オブジェクトをスケーリングするためのパーセント、または複数の引数が与えられた場合にx軸でオブジェクトをスケーリングするためのパーセントy
Number:y軸でオブジェクトをスケーリングするパーセント(オプション)z
Number:z軸でオブジェクトをスケーリングするパーセント(webglのみ)(オプション)scales
p5.Vector | Number []:オブジェクトをスケーリングするための軸ごとのパーセント例1
function setup() { createCanvas(200, 200); } function draw() { background(220); stroke("red"); rect(20, 20, 50, 50); scale(1.5, 1.5); stroke("blue"); rect(20, 20, 50, 50); }実行結果
https://editor.p5js.org/bit0101/sketches/HPq7XBVIh
著作権
p5.js was created by Lauren McCarthy and is developed by a community of collaborators, with support from the Processing Foundation and NYU ITP. Identity and graphic design by Jerel Johnson.
ライセンス
Creative Commons(CC BY-NC-SA 4.0) に従います。
- 投稿日:2020-08-04T18:10:42+09:00
P5.js 日本語リファレンス(rotateZ)
このページでは「P5.js 日本語リファレンス」 の rotateZ関数を説明します。
rotateZ()
説明文
Z軸を中心に回転します。
構文
rotateZ(angle)
パラメタ
- angle
Number:現在のangleMode(RADIANS、DEGREES)に応じて、ラジアンまたは度で指定される回転角度例1
function setup() { createCanvas(200, 200, WEBGL); } function draw() { background(255); rotateZ(millis() / 1000); box() ; }実行結果
https://editor.p5js.org/bit0101/sketches/lxND0EVWX
著作権
p5.js was created by Lauren McCarthy and is developed by a community of collaborators, with support from the Processing Foundation and NYU ITP. Identity and graphic design by Jerel Johnson.
ライセンス
Creative Commons(CC BY-NC-SA 4.0) に従います。
- 投稿日:2020-08-04T18:10:35+09:00
P5.js 日本語リファレンス(rotateY)
このページでは「P5.js 日本語リファレンス」 の rotateY関数を説明します。
rotateY()
説明文
Y軸を中心に回転します。
構文
rotateY(angle)
パラメタ
- angle
Number:現在のangleMode(RADIANS、DEGREES)に応じて、ラジアンまたは度で指定される回転角度例1
function setup() { createCanvas(200, 200, WEBGL); } function draw() { background(255); rotateY(millis() / 1000); box() ; }実行結果
https://editor.p5js.org/bit0101/sketches/OxM5qzrJd
著作権
p5.js was created by Lauren McCarthy and is developed by a community of collaborators, with support from the Processing Foundation and NYU ITP. Identity and graphic design by Jerel Johnson.
ライセンス
Creative Commons(CC BY-NC-SA 4.0) に従います。
- 投稿日:2020-08-04T18:10:27+09:00
P5.js 日本語リファレンス(rotateX)
このページでは「P5.js 日本語リファレンス」 の rotateX関数を説明します。
rotateX()
説明文
X軸を中心に回転します。
構文
rotateX(angle)
パラメタ
- angle
Number:現在のangleMode(RADIANS、DEGREES)に応じて、ラジアンまたは度で指定される回転角度例1
function setup() { createCanvas(200, 200, WEBGL); } function draw() { background(255); rotateX(millis() / 1000); box() ; }実行結果
https://editor.p5js.org/bit0101/sketches/fZxfUVFZU
著作権
p5.js was created by Lauren McCarthy and is developed by a community of collaborators, with support from the Processing Foundation and NYU ITP. Identity and graphic design by Jerel Johnson.
ライセンス
Creative Commons(CC BY-NC-SA 4.0) に従います。
- 投稿日:2020-08-04T18:10:17+09:00
P5.js 日本語リファレンス(rotate)
このページでは「P5.js 日本語リファレンス」 の rotate関数を説明します。
rotate()
説明文
角度パラメータで指定された量だけ形状を回転させます。この関数はangleModeを考慮しているため RADIANS または DEGREES のいずれかで角度を指定します。
オブジェクトは常に原点に対する相対位置を中心に回転し、正の数はオブジェクトを時計回りに回転させます。変換は関数への後続の呼び出しが効果を蓄積した後に発生するすべてに適用されます。たとえば rotate(HALF_PI) を呼び出してから rotate(HALF_PI) を呼び出すことは rotate(PI) と同じです。 draw() が再び開始するとすべての変換がリセットされます。
技術的には rotate() は現在の変換行列に回転行列を乗算します。この関数は push() および pop() によってさらに制御できます。
構文
rotate(angle, [axis])
パラメタ
angle
Number:現在の angleMode(RADIANS、DEGREES) に応じてラジアンまたは度で指定される回転角度axis
p5.Vector | Number []:(3d)回転する軸(オプション)例1
function setup() { createCanvas(200, 200); angleMode(RADIANS); } function draw() { background(220); stroke("red"); rect(100, 0, 52, 52); rotate(PI / 6.0); // 30°時計回りに回転 stroke("green"); rect(100, 0, 52, 52); rotate(PI / 6.0); // 更に30°時計回りに回転 stroke("blue"); rect(100, 0, 52, 52); }実行結果
https://editor.p5js.org/bit0101/sketches/ZDsjqSn6b
著作権
p5.js was created by Lauren McCarthy and is developed by a community of collaborators, with support from the Processing Foundation and NYU ITP. Identity and graphic design by Jerel Johnson.
ライセンス
Creative Commons(CC BY-NC-SA 4.0) に従います。
- 投稿日:2020-08-04T18:02:13+09:00
P5.js 日本語リファレンス(resetMatrix)
このページでは「P5.js 日本語リファレンス」 の resetMatrix関数を説明します。
resetMatrix()
説明文
現在の行列を単位行列に置き換えます。
構文
resetMatrix()
例1
function setup() { createCanvas(200, 200); angleMode(DEGREES); rectMode(CENTER); } function draw() { background(220); translate(60, 60); // 45°回転 let angle = 45 applyMatrix( cos(angle), sin(angle), -sin(angle), cos(angle), 0, 0); stroke("red"); rect(0, 0, 40, 40); //applyMatrix() をリセットします。(translate()もリセットします) resetMatrix(); translate(20, 20); stroke("blue"); rect(0, 0, 40, 40); }実行結果
https://editor.p5js.org/bit0101/sketches/H_oflZuQg
著作権
p5.js was created by Lauren McCarthy and is developed by a community of collaborators, with support from the Processing Foundation and NYU ITP. Identity and graphic design by Jerel Johnson.
ライセンス
Creative Commons(CC BY-NC-SA 4.0) に従います。
- 投稿日:2020-08-04T17:38:40+09:00
正式リリース前に総予習!! Vue3の変更点まとめ
8月上旬に正式リリース予定とされているVue3の変更点をいち早く理解できるように概要をまとめてみました。それぞれの項目ごとにvuejs/rfc又はVue3 Docmentへのリンクを貼っているので索引的に使ってもらえると嬉しいです。
この記事は以下バージョン時点の情報です。
Composition APIの追加
おそらく一番大きな目玉となる変更はこちら。Composition APIという新しいAPIが追加されます(PluginでVue2系でも使用可能です)。
Composition APIはコンポーネントのロジックの柔軟な再構成を可能にする関数ベースのAPI群です。
なお、Vue2系のOptional APIのサポートも継続されるので、Vue2系からのVue3へのバージョンアップ時にComposition APIに書き換える必要はありません。<!-- Vue3 Composition API --> <template> <div> <input type="text" v-model="message" /> <p>{{ nameAndMessage }}</p> <button @click="submit">submit</button> </div> </template> <script lang="ts"> import { defineComponent, computed, ref, onMounted } from "vue"; export default defineComponent({ props: { name: { type: String, required: true } } setup(props, context) { // reactive data const message = ref('Hello Vue3'); // computed const upperCaseMessage = computed(() => `${props.name} ${message.value}`) // emit const submit = () => context.emit('submit', message.value) // lifecycle hook onMounted(() => { // .... }) return { message, nameAndMessage, submit }; } }); </script>Composition APIについてはこちらの記事でより詳細にまとめています。
先取りVue 3.x !! Composition API を試してみる - Qiita
Vue Composition APIで使えるリアクティブ関連のAPI一覧 - QiitaTeleportの追加
Teleportは定義したコンポーネントが属するDOMツリーとは別の場所に、まるでテレポートしたかのようにコンポーネントを移動できる機能です。Vue2系でもサードパーティのプラグインLinusBorg/portal-vueで実現されていました。
以下のようにモーダル表示をハンドルするコンポーネントで
<teleport>
を使うと、to
で指定したDOM要素に内部のコンポーネントを移動できます。<template> <div class="container"> <button @click="toggleModal">toggle modal</button> <teleport to="#teleport-target"> <MyModal v-if="isVisible"/> </teleport> </div> </template> <script lang="ts"> import { defineComponent, ref } from "vue"; export default defineComponent({ setup() { const isVisible = ref(false); const toggleModal = () => { isVisible.value = !isVisible.value; }; return { isVisible, toggleModal }; } }); </script>
to
で指定できるDOM要素は自信の属するDOM要素以外でもOKです。<html lang="ja"> <body> <div id="app"></div> <!-- VueがマウントされるDOM --> <div id="teleport-target"></div> <!-- teleportで指定されているDOM。ここにMyModalが表示される--> <script src="/dist/main.js"></script> </body> </html>
teleport
を利用すると、いままでCSSのz-index
で調整していたDOMの重なり順制御を、宣言的に制御できるようになりz-index
の指定に悩まされることはなくなります。
Vue3を入れたらすぐに使いたいと思える実用的な機能ですね。こちらの記事でも詳細をまとめています。
Vue.js 3.0 の新機能を試す。 〜 Teleport 編〜 - QiitaFragmentsの追加
FragmentsはVue2系では実現できなかったmulti-root nodeのコンポーネントを可能にするものです。
Vue2系ではコンポーネントのroot要素は必ず1つという制約がありました。<template> <div> <header>...</header> <main>...</main> <footer>...</footer> </div> </template>Vue3ではFragmentsのおかげでその制約がなくなり、root要素に複数の要素を記載できます。冗長なdivでのラップなどが不要になります。簡潔で良いですね。
<template> <header>...</header> <main>...</main> <footer>...</footer> </template>ただ、注意点とし子てコンポーネントに直接Class指定をしていると、今まで自動的にroot要素にClassを当てられたのですが、それがfragmentsの場合は明示的な指定が必要になるというのがあります。
Suspenseの追加(実験的)
Suspenseは非同期処理が解決されるまでフォールバックコンテンツ(例えばLoading中アイコン)を表示してくれる特別なコンポーネントです。いままで、
v-if="loading === true"
などの状態変数を使って制御していたものを、状態変数を使わずに簡潔に書くことができます。Suspenseはまだ実験的な機能で、Vue3.0の段階では仕様が確定しておらず今後変更が入ることも考えられます。Vue 3.1での正式リリースを見越しているとのことです。
<template> <Suspense> <template #default> <AsyncComponents/> <!-- 非同期処理を実行するコンポーネント --> </template> <template #fallback> loading... </template> </Suspense> </template>Suspenseの詳細はこちらにまとめています。
Vue.js 3.0 の新機能を試す。 〜 Suspense 編〜 - Qiitav-modelの仕様変更
v-modelの機能が拡張され、ひとつの要素に複数のv-modelの設定が可能になります。
Vue2系のv-bind.syncで実現していたようなことがv-modelで実現できるようになるイメージですね。この機能によってv-bind.syncは代替されるので利用できなくなります。以下v-modelの複数バインドの例です。
v-model:xxxx
のxxxのところで明示的にバインドするpropsを指定しています。<!-- 親コンポーネント --> <template> <UserForm v-model:name="name" v-model:message="message" /> </template><!-- UserFormコンポーネント --> <template> <form> <label>name</label> <input type="text" @input="$emit('update:name', $event.target.value)" > <label>message</label> <input type="text" @input="$emit('update:message', $event.target.value)" > </form> </template> <script lang="ts"> import { defineComponent } from "vue"; export default defineComponent({ props: { name: { type: String, default: '' }, age: { type: String, default: '' } }, setup() { return {} } }) </script>また、modifiersの機能が拡張され、
.lazy
,.number
,trim
のデフォルトのmodifiers以外に独自に,modifiersを定義できるようになりました。
以下はcapitalizeというmodifiersを設定している例です。v-model:name.capitalize=
とすることで入力値にcapitalizeを実行しています。<!-- 親コンポーネント --> <template> <form> <MyName v-model:name.capitalize="form.name"/> <!-- ... --> </form> </template><!-- MyNameコンポーネント --> <template> <input :value="name" @input="updateName" type="text" name="name" /> </template> <script> import { defineComponent } from "vue"; export default defineComponent({ props: { name: { type: String, default: '' }, nameModifiers: { default: () => ({}) } }, setup (props, { emit }) { const updateName = event => { let val = event.target.value if (props.nameModifiers.capitalize) { val = val.charAt(0).toUpperCase() + val.slice(1) } emit('update:name', val) } return { updateName } } } </script>scoped CSSの仕様変更
scoped CSSで使える擬似クラスの仕様変更・機能追加が行われます。
まず1つ目が::v-deep()
でこれは、今まで/deep/
として設定していた、子コンポーネントにスタイルを適用するための擬似クラスです。
/deep/
の記法がDEPRECATEDとなり、新たに::v-deep()
が追加されています。::v-deep(.foo) {}/* コンパイル後 */ [v-data-xxxxxxx] .foo {}2つ目が、
::v-slotted()
で、これはslotで受け取った親コンポーネントの要素にスタイルを適用するためのものです。Vue3からデフォルトではslotで受け取った要素は、子コンポーネントのスタイルが適用されなくなるため、こちらが追加されました。::v-slotted(.foo) {}/* コンパイル後 */ .foo[v-data-xxxxxxx-s] {}最後が、
::v-global()
で、これはscoped CSSの中でグローバルなスタイルの定義を可能とするものです。この擬似要素を設定したクラスには[v-data-xxxx]
が付与されないため、グローバルに適応されます。::v-global(.foo) {}.foo {}$attrsの仕様変更
$attrs
の機能が拡張され、今まで$listeners
で参照していたネイティブイベントや別管理であったclass、styleも全て包括して$attrs
から取得できるようになりました。<MyButton @click="handleClick" @custom="handleCustom" v-model="value" type="button" class="btn" /><!-- MyButton --> $attrs: { class: 'btn' type: 'button', onClick: handleClick, onCustom: handleCustom, 'onUpdate:modelValue': () => { value = payload }, }そのため、
$listeners
はDEPRECATEDとなります。(実行時に警告がでます)
$listeners
を使って透過的なラッパーコンポーネントを作っていた場合は、$listeners
を削除し$attrs
への書き換えが必要です。<!-- Vue2系 --> <input v-bind="$attrs" v-on="$liseners" /><!-- Vue3 --> <input v-bind="$attrs" />Global APIの仕様変更
Vueの初期化処理が変わります。
createApp
でインスタンスを生成し、そのインスタンススコープでuse
やmixin
などが適応されるようになります。
これによってテストケースでのグローバル設定の汚染を防いだり、同一ファイル内で別設定のVueインスタンスの初期化が容易になります。import { createApp } from 'vue' import App from './App.vue' const app = createApp(App) // インスタンスを生成 app.config.isCustomElement = tag => tag.startsWith('app-') app.use(/* ... */) // インスタンススコープで設定される app.mixin(/* ... */) app.component(/* ... */) app.directive(/* ... */) app.config.globalProperties.customProperty = () => {} app.mount(App, '#app')filterの廃止
filterは、パイプ演算子
|
を使って関数適応をlinuxの標準入出力のパイプラインするものですがJavaScriptにはない独自構文で学習コストが増加する、構文解析を複雑にするという理由で削除されます。filterの処理は通常の関数適応で代替できます。
<!-- filter形式 --> <p>{{ msg | uppercase | reverse }}</p> <!-- 通常の関数適応形式 --> <p>{{ reverse(uppercase(msg)) }}</p>他の代替方法についてはrfcs/0015-remove-filters.md#alternativesをご覧ください。
Event Emitter系のAPIの廃止
Event Emitter系のAPI(
$on
,$off
,$once
)が削除されます。
グローバルなイベント管理としてEvent Emitterを仕様している場合は書き換えが必要です。
Event管理の代替にはMittなどの別のEvent Emitterライブラリの利用が推奨されています。Functional Componentの廃止
Functional Componentはdata等の状態を持たない代わりにレンダリングパフォーマンスの大幅な改善が行えるコンポーネントです。
Vue3ではFunctional Componentを作る際に使用するfunctional: true
のオプションや、<template functional>
が削除されます。Vue3では、通常のコンポーネントとFunctional Componentの性能差は大幅に縮小され、ほとんどのユースケースでは取るに足らないものとなったそうです。
SFC上でfunctionalを使用している場合は、functionalの属性を削除し、attrs、listnersの参照方法の修正が必要です。
<!-- Vue2 functional component --> <template functional> <component :is="`h${props.level}`" v-bind="attrs" v-on="listeners" /> </template> <script> export default { props: ['level'] } </script><!-- Vue3 --> <template> <!-- functionalを削除 --> <component v-bind:is="`h${props.level}`" v-bind="$attrs" <!-- attrs及びlistnersは$attrsにまとめられる --> /> </template> <script> export default { props: ['level'] } </script>終わりに
以上「正式リース前に総予習!! Vue3の変更点まとめ」でした。
色々ワクワクするような新機能が追加されていてVue3のリリースが待ち通しいですね。
他にも諸々細かい点が変わってるのでより詳細な変更はvuejs/rfcをご確認ください。参考
- 投稿日:2020-08-04T17:13:12+09:00
ウェブサイト作成用備忘録・3号:video タグを活用した疑似アニメーション背景
日々の学習のアウトプットの為、自主学習の際に工夫した内容を記録していきます。
今回は video タグを用いた疑似アニメーション背景について
css の background プロパティには動画ファイルを直接設定することが出来ません。
そこで、自分でリサーチした内容をまとめていきたいと思います。
方法:body タグ直下に video タグを配置し、css の設定で画面全体を覆うようにサイズを変更する。そして video タグには position: fiexd、それ以外の同じ階層の親要素には position: relative プロパティを設定して、各要素を重ねて表示する。
前準備
mp4 形式のファイルをそのまま採用する場合、そのままの画質でウェブサイトに表示させようとすると、動画の読み込みに時間が掛かってしまいます。ウェブサイトの背景に使用する動画のファイルサイズは最大でも1MB以内をオススメします。
(自分が普段利用している著作権フリーの動画素材サイトを共有しておきます。参考になれば幸いです)
高品質なフリー動画素材 - Pixabayこのサイトでは高画質な動画素材をダウンロードできますが、ファイルサイズが小さな動画でも1MBを超えているものがほとんどです。
その為、次にダウンロードした動画を圧縮加工する必要があります。
(自分が普段利用しているオンラインサービスを共有しておきます。参考になれば幸いです)
VideoSmallerダウンロードした動画をこのサイトで圧縮することで、ファイルサイズを1MB以下まで小さくすることが出来ます。
今回はウェブサイトの背景の為の動画素材なので、「ビデオからオーディオを削除する」のチェックボックスを忘れずに有効にしておきましょう。記述例
HTML
<html> <body> <video class="background_video" src="動画背景用素材" autoplay loop muted poster="動画背景用素材のスクリーンショット"></video> <div class=""> <h1>hello world</h1> </div> </body> </html>CSS
body { margin: 0; } div { position: relative; z-index: 1; } h1 { margin: 0; } .background_video { min-width: 100%; min-height: 100%; position: fixed; z-index: 0; }解説
1・video タグには以下の設定を行い、position: fixed と z-index プロパティをそれぞれ設定する。
autoplay(サイト読み込み時に自動再生)
loop(再生終了後にループ再生)
muted(動画の音声を再生しない、事前にオーディオを削除していても、この設定をしないと自動再生が行われない)
poster(ブラウザが動画再生未対応の場合、posterで設定した画像が代わりに表示される)2・video と同階層の別要素には position: relative と z-index プロパティをそれぞれ設定する。
今回はこれで以上になります。
あくまで自分用の備忘録ですが、他の方の参考になれば幸いです。
- 投稿日:2020-08-04T17:02:15+09:00
【Nuxt.js】Nuxt文法編:computed
? この記事はWP専用です
https://wp.me/pc9NHC-wY前置き
今回はcomputed?
getter関数とsetter関数が使える
算出プロパティです!簡単な使い方や
methodsとの違いを解説しています?♀️computed
簡単な使い方
テキストを反転させます?
【index.vue】
プロパティなので呼び出す際は
{{ reversedMessage() }}
ではなく
{{ reversedMessage }}
でOKです?index.vue<template> <div class="page"> <p>message: {{ message }}</p> <p>reversed message: {{ reversedMessage }}</p> </div> </template> <script> export default { data () { return { message: 'Hello Nuxt.js!', } }, computed: { reversedMessage () { return this.message.split('').reverse().join('') }, }, } </script>methodsを使った場合のコード
呼び出す物が関数になるので
{{ reversedMessage() }}index.vue<template> <div class="page"> <p>message: {{ message }}</p> <p>reversed message: {{ reversedMessage() }}</p> </div> </template> <script> export default { data () { return { message: 'Hello Nuxt.js!', } }, methods: { reversedMessage () { return this.message.split('').reverse().join('') }, }, } </script>thisコンテキストを使う
thisコンテキストが使えます。
this.messageを平仮名にしてみます。index.vue<template> <div class="page"> <p>message: {{ message }}</p> <p>reversed message: {{ reversedMessage }}</p> </div> </template> <script> export default { data () { return { message: 'Hello Nuxt.js!', } }, computed: { reversedMessage () { let message = this.message = 'あいうえお' return message.split('').reverse().join('') }, }, } </script>methodsとの違い
computedはプロパティ
methodsはメソッドなので
そもそも土台が違うのですが
似ていますよね?? 続きはWPでご覧ください?
https://wp.me/pc9NHC-wY
- 投稿日:2020-08-04T16:30:00+09:00
P5.js 日本語リファレンス(applyMatrix)
このページでは「P5.js 日本語リファレンス」 の applyMatrix関数を説明します。
applyMatrix()
説明文
現在の行列にパラメータで指定された行列を乗算します。これは、平行移動、拡大縮小、剪断、回転をすべて同時に実行できる強力な操作です。ウィキペディアで変換マトリックスの詳細を学ぶことができます。
ここでの引数の命名は、WHATWG仕様の命名に従い、次の形式の変換行列に対応します。
2次元変換マトリックス
\begin{pmatrix} a & c & e \\ b & d & f \\ 0 & 0 & 1 \end{pmatrix}2次元平行移動
- e: x方向の平行移動量
- f: y方向の平行移動量
\begin{pmatrix} 0 & 0 & e \\ 0 & 0 & f \\ 0 & 0 & 1 \end{pmatrix}2次元拡大縮小
- a: x方向の拡大縮小率
- d: y方向の拡大縮小率
\begin{pmatrix} a & 0 & 0 \\ 0 & d & 0 \\ 0 & 0 & 1 \end{pmatrix}2次元回転
a: cos(回転角度)
b: sin(回転角度)
c: -sin(回転角度)
d: cos(回転角度)\begin{pmatrix} a & c & 0 \\ b & d & 0 \\ 0 & 0 & 1 \end{pmatrix}3次元変換マトリックス
\begin{pmatrix} m11 & m21 & m31 & m41 \\ m12 & m22 & m32 & m42 \\ m13 & m23 & m33 & m43 \\ 0 & 0 & 0 & 1 \end{pmatrix}3次元平行移動
m41: x方向の平行移動量
m42: y方向の平行移動量
m43: z方向の平行移動量\begin{pmatrix} 1 & 0 & 0 & m41 \\ 0 & 1 & 0 & m42 \\ 0 & 0 & 1 & m43 \\ 0 & 0 & 0 & 1 \end{pmatrix}3次元拡大縮小
m11: x方向の拡大縮小率
m22: y方向の拡大縮小率
m33: z方向の拡大縮小率\begin{pmatrix} m11 & 0 & 0 & 0 \\ 0 & m22 & 0 & 0 \\ 0 & 0 & m33 & 0 \\ 0 & 0 & 0 & 1 \end{pmatrix}3次元x軸回転
m22: cos(回転角度)
m23: -sin(回転角度)
m32: sin(回転角度)
m33: cos(回転角度)\begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & m22 & m32 & 0 \\ 0 & m23 & m33 & 0 \\ 0 & 0 & 0 & 1 \end{pmatrix}3次元y軸回転
m11: cos(回転角度)
m13: sin(回転角度)
m31: -sin(回転角度)
m33: cos(回転角度)\begin{pmatrix} m11 & 0 & m31 & 0 \\ 0 & 1 & 0 & 0 \\ m13 & 0 & m33 & 0 \\ 0 & 0 & 0 & 1 \end{pmatrix}3次元z軸回転
m11: cos(回転角度)
m12: sin(回転角度)
m21: -sin(回転角度)
m22: cos(回転角度)\begin{pmatrix} m11 & m21 & 0 & 0 \\ m12 & m22 & 0 & 0 \\ 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 1 \end{pmatrix}構文
applyMatrix(a, b, c, d, e, f)
applyMatrix(m11, m12, m13, m21, m22, m23, m31, m32, m33, m41, m42, m43)
パラメタ
a - f
Number:乗算する2x3行列を定義する数値m11 - m43
Number:乗算する3x4行列を定義する数値例1 2次元の平行移動
function setup() { frameRate(10); rectMode(CENTER); } function draw() { let step = frameCount % 20; background(200); // 2次元の平行移動 applyMatrix( 1, 0, 0, 1, 40 + step, 30 + step); rect(0, 0, 50, 50); }実行結果
https://editor.p5js.org/bit0101/sketches/hnW37L2tv
例2 2次元の拡大縮小
function setup() { frameRate(10); rectMode(CENTER); } function draw() { let step = frameCount % 20; background(200); translate(50, 50); // 2次元の拡大縮小 applyMatrix(1 / step, 0, 0, 1 / step, 0, 0); rect(0, 0, 50, 50); }実行結果
https://editor.p5js.org/bit0101/sketches/hqHo8r7DW
例3 2次元の回転
function setup() { frameRate(10); rectMode(CENTER); } function draw() { let step = frameCount % 20; let angle = map(step, 0, 20, 0, TWO_PI); background(200); translate(50, 50); // 2次元の回転 applyMatrix( cos(angle), sin(angle), -sin(angle), cos(angle), 0, 0); rect(0, 0, 50, 50); }実行結果
https://editor.p5js.org/bit0101/sketches/AxKDBbXgO
例4 3次元の平行移動
function setup() { createCanvas(200, 200, WEBGL); frameRate(10); rectMode(CENTER); } function draw() { let dx = frameCount % 30; let dy = frameCount % 30; let dz = frameCount % 30; background(200); // 3次元x、y、z方向の平行移動 applyMatrix( 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, dx, dy, dz, 1); box(50); }実行結果
https://editor.p5js.org/bit0101/sketches/aHQKDWt8r
例5 3次元の拡大縮小
function setup() { createCanvas(200, 200, WEBGL); frameRate(10); rectMode(CENTER); } function draw() { let step = frameCount % 20; background(200); // 3次元のx、y方向の拡大縮小 applyMatrix(1 / step, 0, 0, 0, 0, 1 / step, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); box(50); }実行結果
https://editor.p5js.org/bit0101/sketches/Bz2HX45eP
例6 3次元のx軸を中心とした回転
function setup() { createCanvas(100, 100, WEBGL); noFill() ; } function draw() { background(200); rotateX(PI / 6); stroke(153); box(35); let rad = millis() / 1000; // 3次元のx軸を中心とした回転 applyMatrix( 1, 0, 0, 0, 0, cos(rad), -sin(rad), 0, 0, sin(rad), cos(rad), 0, 0, 0, 0, 1); stroke(255); box(50); }実行結果
https://editor.p5js.org/bit0101/sketches/rIg-BgThL
例7 3次元のy軸を中心とした回転
function setup() { createCanvas(100, 100, WEBGL); noFill() ; } function draw() { background(200); rotateY(PI / 6); stroke(153); box(35); let rad = millis() / 1000; // 3次元のy軸を中心とした回転 applyMatrix( cos(rad), 0.0, sin(rad), 0.0, 0.0, 1.0, 0.0, 0.0, -sin(rad), 0.0, cos(rad), 0.0, 0.0, 0.0, 0.0, 1.0); stroke(255); box(50); }実行結果
https://editor.p5js.org/bit0101/sketches/Sd8nJItVe
例8 3次元のz軸を中心とした回転
function setup() { createCanvas(100, 100, WEBGL); noFill() ; } function draw() { background(200); rotateZ(PI / 6); stroke(153); box(35); let rad = millis() / 1000; // 3次元のz軸を中心とした回転 applyMatrix( cos(rad), sin(rad), 0, 0, -sin(rad), cos(rad), 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); stroke(255); box(50); }実行結果
https://editor.p5js.org/bit0101/sketches/OexDrcluT
例9 平行移動とx軸回転の組み合わせ
function setup() { createCanvas(200, 200, WEBGL); frameRate(10); rectMode(CENTER); } function draw() { let dx = frameCount % 30; let dy = frameCount % 30; let dz = frameCount % 30; let rad = millis() / 1000; background(200); // 3次元x、y、z方向の平行移動 applyMatrix( 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, dx, dy, dz, 1); // 3次元のx軸を中心とした回転 applyMatrix( 1, 0, 0, 0, 0, cos(rad), -sin(rad), 0, 0, sin(rad), cos(rad), 0, 0, 0, 0, 1); box(50); }実行結果
https://editor.p5js.org/bit0101/sketches/TQM4XFV1W
著作権
p5.js was created by Lauren McCarthy and is developed by a community of collaborators, with support from the Processing Foundation and NYU ITP. Identity and graphic design by Jerel Johnson.
ライセンス
Creative Commons(CC BY-NC-SA 4.0) に従います。
- 投稿日:2020-08-04T15:17:18+09:00
textareaの高さを入力に合わせて自動調整する
地味に面倒くさい、textareaの高さ自動調整。
$("textarea").height( $("textarea")[0].scrollHeight );※ 適時イベントハンドリングすること。
これぐらい、デフォルト仕様になればいいのにね。
- 投稿日:2020-08-04T15:13:42+09:00
Internet Explorerでは try { } catch { } は動かない
JavaScriptにて例外処理を書いていまして、ビックリしたんですけど、
この書き方(try { } catch { }
の引数を省略した形)だと、EdgeとIEで動きませんでした。try { throw new Error('error.'); } catch { console.log('error.'); }エラーが出ました。
SCRIPT1005: SCRIPT1005: Expected '('こう書かないと
try { throw new Error('error.'); } catch(e) { console.log('error.'); }ChromeやFireFoxでは大丈夫だったのですが、
catch
の引数e
が必要でした。
できれば省略したかったのに・・・。バージョン
Microsoft Edge 44.18362.449.0
Internet Explorer 11.0.195
- 投稿日:2020-08-04T14:44:15+09:00
Visual Studio Code設定メモ
Extensions
PHP
View側
多言語ファイル
インデント、改行コード、全角スペース他
エディタの機能追加・設定
コードフォーマッター
改行コードを変更する
settings.json設定例{ "files.eol": "\n" }参考 :
- VS Codeで改行コードを変更するには
タブインデント、空白を表示させる設定
settings.json設定例{ "editor.insertSpaces": false, "editor.renderWhitespace": "all" }参考 :
- VS Codeで空白文字を一目で分かるように表示するには
- VS Code でドキュメントの空白文字を見やすくしてみる
インデント幅を言語毎に指定する
settings.json設定例{ "[javascript]": { "editor.tabSize": 2 }, "[html]": { "editor.tabSize": 4 } }参考 :
- VSCodeでプログラム言語ごとの設定を行う
- Visual Studio Codeで言語ごとにインデント設定を行う方法
Smartyのデリミタを変更
やったこと
blockComment["{", "}"],
=>[ "<{*", "*}>" ]
へ修正
brackets["{", "}"],
=>["<{", "}>"],
へ修正
autoClosingPairs , surroundingPairs に["<{", "}>"],
を追加
C:\Users\<USER NAME>\.vscode\extensions\imperez.smarty-0.3.0\smarty.configuration.json
smarty.configuration.json設定例{ "comments": { // symbols used for start and end a block comment. Remove this entry if your language does not support block comments "blockComment": [ "<{*", "*}>" ] // [ "{*", "*}" ]から変更 }, // symbols used as brackets "brackets": [ ["<{", "}>"], // ["{", "}"],から変更 ["[{", "}]"], ["[", "]"], ["(", ")"] ], "autoClosingPairs": [ + ["<{", "}>"], ["{", "}"], ["[", "]"], ["(", ")"], ["\"", "\""], ["'", "'"], ["`", "`"] ], "surroundingPairs": [ + ["<{", "}>"], ["{", "}"], ["[", "]"], ["(", ")"], ["\"", "\""], ["'", "'"], ["`", "`"] ] }参考 :
- VSCode(Visual Studio Code)のSmarty拡張機能でデリミタを変更する方法
- VS Code 1.27 の新機能 - 自動閉じ括弧、自動括弧囲い機能の設定追加
*.tplなどでEmmet(Html/CSSの入力補完)を効かせる
settings.json設定例"emmet.includeLanguages": { "smarty": "html" },参考 :
- [VSCode]HTMLファイル以外でもEmmetを使えるようにしたい!
自動アップデートを無効化する方法
C:\Users\<ユーザー名>\AppData\Roaming\Code\User\settings.json
settings.json設定例{ "update.channel": "none" }参考 :
- VS Codeの自動更新を有効化/無効化するには
- 投稿日:2020-08-04T14:09:50+09:00
Amplifyで、STSの認証を直接行う
Amazon CognitoのIDプールを使って外部プロバイダーがウェブベースの認証を提供する場合に、Cognitoが発行する認証の有効期限を伸ばすことがそのままでは難しかったので、その調査の記録を書いておきます。
そもそもの認証フロー
開発者認証or外部プロバイダーどちらを使ったとしても、Amplifyの認証を素直に使うと下の拡張認証フローになります。
引用元:
https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/authentication-flow.htmlこの図を見てもらうとわかるのですが、最終的な認証情報はAWS STSから渡ってきます。そして、AWS STSでは認証情報を発行する際にその有効期限を指定することができます。しかし、拡張認証フローだとAmazon CognitoがAWS STSとやり取りしてしまうため、有効期限を指定することが出来ず、デフォルトの有効期限(
3600
秒)が指定されてします。そこで、先程のページに有る、基本的な認証フローを使うことになります。
引用元: https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/authentication-flow.html
見ての通り、AWS STSへ直接アクセスすることが出来ます。
実際のやり方
AmplifyでのCognito認証はすでに済んでいるものとし、AWS STSの認証に必要な下記のパラメータはすべて準備出来ているものとします。
- (A)
sts:AssumeRoleWithWebIdentity
アクションが実行可能なIAM Role(そしてそのARN)- (B) 64字以下のセッション名として使う任意の文字列
- (C)
GetOpenIdToken...
で発行されたトークン上記がそろえば、あとはさっくりAWS SDKのAPIを叩くだけです。
const stsParams = { DurationSeconds: 900, // 最小900秒(15分)〜最大43200秒(12時間)まで設定することが出来ます。 RoleArn: `(A)の値`, RoleSessionName: `(B)の値`, WebIdentityToken: `(C)の値`, }; const sts = new AWS.STS(); const stsResponse = await sts.assumeRoleWithWebIdentity(stsParams).promise(); AWS.config.update({ credentials: new AWS.Credentials({ accessKeyId: stsResponse.Credentials.AccessKeyId, secretAccessKey: stsResponse.Credentials.SecretAccessKey, sessionToken: stsResponse.Credentials.SessionToken, }), });Amplifyの認証設定はいっさいやらないんかい!って感じですが、Amplifyのコードを見る限り、Credentialsクラスなどから認証情報を設定する方法はなさそうです。AWSのグローバルの認証情報を更新しておくと、Amplifyのもろもろはそれを見て勝手に認証してくれるようなので、この書き方に落ち着きました。
- ※ Amplifyのバージョンによって、aws-sdkのバージョンが違ってくるので、この書き方はできない場合があります。
- ※ この書き方はaws-sdk v2系を想定しています。
- ※サーバー側のAPIを用意できるなら、CognitoのEPをそのままモックしてしまうほうが良いです。