20211012のJavaScriptに関する記事は17件です。

GSAPでサイドバーを固定しながらスクロール追従

GSAPのScrollTriggerのピン留め機能を使用したら簡単に実装できました。 デモ See the Pen GSAPでサイドバーを固定しながらスクロール追従 by miyakezaka (@miyakezaka) on CodePen. GSAPを使う利点 実装が簡単で動作も安定している スクロールの対象のエリアのみ処理が行われるためブラウザ負荷が少ない IE11にも対応している その他の方法で実装した場合 GSAPを使用しないでサイドバーを固定する方法だと主に以下が考えられます。 CSSプロパティのposition: sticky;で実装 position: sticky;を紹介した記事をたくさん目にしますが、使用する場面が限られると思いました。 サイドバーに要素が多いと実装できない IE11に対応していない(ポリフィル読めば対応できるらしい) JS処理を組み合わせて実装 こちらは実装と他コンテンツの考慮などとにかく大変でした。 ページによってコンテンツの有無で高さが異なるなど、上手く設計してメンテしないと表示崩れが起きやすい。 スクロールの対象のエリア外でも常に処理が行われるため負担がブラウザ負荷がかかる コード解説 JS部分のコードの解説に入ります、GSAPの基本的なところは省きます。 まずはGSAP本体とScrollTriggerの2つを読み込みます。 HTML <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.8.0/gsap.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.8.0/ScrollTrigger.min.js"></script> ScrollTriggerを設定していきます。 ポイントはendTriggerキーに固定を解除したい要素を指定して、endキーに指定要素のどの位置で解除するかを指定します。 マーカーで位置を確認しながら進めるとやりやすいです、狙った箇所で簡単に固定 〜 解除ができました。 JS gsap.to('.sidebar', { scrollTrigger: { trigger: '.sidebar', start: 'bottom 100%', end: 'bottom 100%', endTrigger: 'main', pin: true, markers: true } });
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

jsでobjectのキーの順序を変更する

{ address:'', age:'', client_name:'', customer_id:'', first_visit_date:'', prefecture:'', } jsのobjectのキーを自分の指定した、順序に並び替える方法。 //json並び替え key_orderの順番に並び替える let key_order = ['address','client_name','first_visit_date','prefecture','customer_id','age'] let hash = {} let items_data = key_order.map(function(x){ return json.items[0][x] }) for (let [i,j] of zip(key_order,items_data)){ hash[i] = j } json.items[0] = hash 参考文献: https://teratail.com/questions/106913
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

js drag&dropとinput fileに情報を入れ込む

drag & dropしたら、画像情報がinputに入る仕組みを作成。 調査していると、input fileの中身はいじることができないような記事が出てきたがなんとか実現。 <form> <input id="upload" type="file" accept="image/*" name="image"> <input type="submit" value="送信"> </form> $("#upload").on("drop", function(e){ e.preventDefault(); document.getElementById("upload").files = e.originalEvent.dataTransfer.files; }); dropした時に、イベントが発火する形にします。 id = "upload"を指定して、取得。 filesオブジェクトを取得し、そこへe.originalEvent.dataTransfer.filesを挿入。 すると、inputに画像データが入り、formで送信することができるようになる。 しかし、これだけだとdrag & dropしても動かない時があります。というのも普通dropエリアは広げることを前提に作成するかと思います。drop areaというやつでしょうか。 その際、dropすれば、ブラウザ側が反応して画像をブラウザが開いてしまうことがあります。 そのために、dragoverした際の処理も追加しておきます。 js $("upload").on("dragover",function(e){ e.preventDefault; e.stopPropagation; }) drop-area参照:https://css-tricks.com/drag-and-drop-file-uploading/ 以上ですが、dropした際に、画像の名前を表示させたい場合もあると思います。 それと総合して、全文が以下になります。 let form = $("#upload"); let labels = $(".labels") //html上にlabelsが存在している場合 let showFile = function(files){ $labels.text(file.length > 1 ? files[files.length-1].name:files[0].name) } //画像は1つだけしか許可しないため、複数dropされたら最後の画像の名前を反映 $form.on("dragover",function(e){ e.preventDefault; e.stopPropagation; }); $form.on("drop",function(e){ e.preventDefault; e.stopPropagation; dropfile = e.originalEvent.dataTransfer.files; showFiles( dropfile ); document.getElementById("file").files = dropfile; }) 多分、e.originalEvent.dataTransfer.files;が重要なんだろうけど..... 追記: e.oroginalEventはイベントのプロパティが入っているらしい。 中身は、eventごとに微妙に違うぽく、clickの時、drop時色々違う。 今回は、dropの時にdataTransferプロパティの中にinputのfile情報が入っているためそこを利用する形だと思われる。 e.targetとかで取れない時にはみてみるといいかも。 参照:https://honey8823.hateblo.jp/entry/2018/08/29/125121 https://html5exam.jp/measures/dojo_1_08.html drag drop参考:http://www.it-view.net/drag-and-drop-file-upload-jquery-178.html
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Vue.js】条件分岐 v-show について

はじめに こんにちは! 松本 佑大(まつもと ゆうだい)と申します! 今回はv-showについてアウトプットしていきます! v-show とは 要素の表示/非表示を切り替えることができます。 v-ifと違うポイントとしてはp要素そのものが削除されるのではなくcssのdisplay プロパティをon/offされるで表示/非表示が繰り返されます。 書き方 HTML <div> <p v-show="toggle"> Good night! </p> </div> Vue.js var app = new Vue({ el:'#app', data:{ toggle:true } ※細かい書き方はv-ifと同じで前記事で解説しているので省略します。 まとめ ・v-showではdisplayプロパティがon/offされる。 ・全体的な書き方はv-ifと一緒。 最後に 今回はv-showについてアウトプットしました。 今回の記事を読んで気になったこと、質問等あればコメント等頂けると幸いです。 今後ともQiitaにてアウトプットしていきます! 最後までご愛読ありがとうございました!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【JavaScript】非同期処理について

はじめに こんにちは。 こちらの記事では、非同期処理についてアウトプットしていきます! 誤っている点がございましたらコメントいただけると幸いです。 同期処理とは コードの記述のように上から順番に処理が実行されるのが同期処理。 非同期処理とは ひとつの処理の完了を待たず、複数の処理を同時に実行することができるのが非同期処理。処理の完了を待たないので、処理の順番を制御する記述が必要となる。 非同期処理はなぜ必要なのか 同期処理の場合、全ての処理が完了するまで待たなければいけないので、サイトの表示速度が落ちてしまい、離脱率が上がってしまうことが考えられる。 そのため、非同期処理で実行することでユーザーの使いやすさを考慮した実装をすることができる。 ここでは非同期処理を制御する、コールバック関数 / Promise / async,awaitについて、1秒ごとに文字を表示する処理で記述の仕方を比較していきます! コールバック関数 コールバック関数でも非同期処理は記述できるが、ネストが深くて見づらくなるという欠点があるため、現在はあまり使用されていない。 Vue.js setTimeout(() => { console.log("たまご"); setTimeout(() => { console.log("ひよこ"); setTimeout(() => { console.log("にわとり"); }, 1000); }, 1000); }, 1000); Promise Promiseを訳すと「約束」という意味を持つ。.then()で処理を繋げることができ、コールバック地獄から解放されるきっかけとなった。 JavaScript new Promise(resolve => { setTimeout(() => { console.log("たまご"); resolve(); }, 1000); }).then(() => { return new Promise(resolve => { setTimeout(() => { console.log("ひよこ"); resolve(); }, 1000); }); }).then(() => { return new Promise(resolve => { setTimeout(() => { console.log("にわとり"); resolve(); }, 1000); }); }); async , await asyncは、非同期関数を定義する関数宣言のこと。 awaitは、async関数内でPromiseの結果(resolve、reject)が返されるまで待機する(処理を一時停止する)演算子のこと。 JavaScript func = async () => { await log("たまご"); await log("ひよこ"); await log("にわとり"); }; log = (test) => { return new Promise(resolve => { setTimeout(() => { console.log(test); resolve(); }, 1000); }) } func(); Promiseで.then()メソッドの記述が多くなる場合、コードが見づらくなるがasync / awaitを用いることで、さらにシンプルに記述することができるようになった。 おわりに ここまで非同期処理についてまとめました。 非同期処理を行う上で、個人開発でも現場でもよく使われるものだと思うので引き続き復習しながら、アプリ開発も進めていきます! 以上、最後まで読んでいただきありがとうございました!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

(JS)変数・定数・ブーリアン・プリミティブ型・オブジェクト

はじめに 初学者です。 基本は備忘録 間違っていたら教えてくださると助かります。 変数の違い タイプ 再宣言 再代入 スコープ 初期化(ホイスティング) let x ○ ブロック x const x x ブロック x var ○ ○ 関数 undefined 暗黙的な型変換 状況によって型が自動で変更される 動的型付け言語 →自動で型が変更される 静的片付け言語 →宣言時に型を指定する 厳格な等価性 a === b 型が一致しているかまで比較する 抽象的な等価性 a == b 型はあっている必要がない 抽象的な等価性では比較時にどちらかの型に合わせる console.log(true == 1)//処理結果 true //1がtrueに変換されて比較 falsyとtruthy falsy false 0 0n '' null undefined //変数を代入なしで宣言した等 Nan //期待->数値 数値として処理できなかった時 truthy→それ以外全て AND条件とOR条件 const a = 0 const b = 1 const c = 3 const d = 2 console.log(a && b)//結果: 0 console.log(a || b)//結果: 1 console.log((a || b) && (c || d))//結果: 3 //&&は左から順にtrueの限り判定を繰り返す //falseが出た時点でその値を返し、出なければ最後を返す //&&は左から順にfalseの限り判定を繰り返す //trueが出た時点でその値を返し、出なければ最後を返す AND条件とOR条件の応用 ORの応用 function hello(name) { name = name || 'Ren'; console.log('Hello' + name); } hello() //値に何も渡されなければ(false)Renをnameにセットする ANDの応用 function hello(name) { name = name || 'Ren'; console.log('Hello' + name); } let name; name && hello(name); //nameがtrueなら関数を実行する プリミティブ型とオブジェクト データ型 JavaScriptには8種類ある 8種類を大きく分けて二つに分けることができる プリミティブ型 String Number Boolean Undefined Null Symbol BigInt オブジェクト型(プリミティブ型以外の全て) object プリミティブ型 変数には値が格納される 一度作成するとその値を変更することはできない(immutable) let a = 'いちご' //メモリの、異なるaddress2つに「いちご」と変数aが保存される //変数aはいちごへの参照を保持する a = 'ぶどう' //いちごとは異なるaddresにぶどうが保存される //変数aの参照先をぶどうに書き換える //プリミティブ型(String)のいちごが変更されたわけではない //再代入は変数の参照先を変えている オブジェクト型 変数には参照が格納される。 値を更新できる(mutable) let a = { name: 'いちご' } //参照の流れ //変数a→オブジェクトへの参照{...}→オブジェクトの実態{name}→nameの参照先{いちご} //オブジェクトの実態が変わっても変数aの参照先は変わらない(mutable) //オブジェクトは名前{プロパティー}付きの参照を管理する入れ物 プリミティブ型のコピー let a = 'いちご'; let b = a; b = 'ぶどう' //値を新しいaddressにコピーするので、コピー元に影響はない let a = いちご a = b b = ぶどう いちご coppied,いちご - a ↑ b↑ →ぶどう - - aの参照先がぶどうを向く オブジェクトのコピー let a = { name: 'いちご' }; let b = a; b.name = 'ぶどう' //値をコピーするのではなく参照先をコピーするので、 //bのnameを変更するとコピー元(a)の値にも影響する let a = {name: いちご} b = a b.name = ぶどう いちご - - {name}↑ ←copyied {...}への参照 - {...}への参照↑ b↑ - a↑ - aもbもぶどうに変わる 実際の挙動 //プリミティブ型のコピー let a = 'いちご' let b = a; b = bye; console.log(a, b) //結果 いちご ぶどう //参照先の値がコピーされる。 //オブジェクト型のコピー let c = { name: 'いちご' } let d = c d.name = 'ぶどう' console.log(c, d)//結果 ぶどう ぶどう //オブジェクトへの参照がコピーされる d = {} //のように新しいオブジェクトを生成するとcとdの参照しているオブジェクトは別々のものになるので、dに変更を加えてもcに影響はない 参照とconst プリミティブ型 const a = 'いちご' a = 'ぶどう'; console.log(a)//結果 エラー //constによりa→「いちご」の参照が固定されているため変更不可 オブジェクト const b { name: 'いちご' } //b = {} x constによりオブジェクトへの参照が固定されているため変更不可 b.name = 'ぶどう'; console.log(b); //結果 ぶどう //constで固定されているのはオブジェクトへの参照の固定のみ //オブジェクト内の値については何も制限を受けていないので変更可能 関数の引数に値を渡す プリミティブ型 let a = 0; function fn1(arg1) { arg = 1; console.log(a, arg1);//結果 0 1 } fn1(a); //プリミティブ型を関数の引数に渡す場合は値が別々に存在しているため //変更がコピー元に影響しない オブジェクト型 let b = { name : 'いちご' } function fn2(arg2) { arg2.name = 'ぶどう' console.log(b, arg2);//結果 ぶどう ぶどう } fn2(b); //オブジェクトを関数の引数に渡す場合はオブジェクトへの参照がコピーされる //参照しているオブジェクトは同じなので、コピー元に影響がある 分割代入 オブジェクトから特定のプロパティーを抽出して宣言を行う。 const a = { name: 'いちご' } let { name } = a; name = 'パンダ'; console.log(a.name, name);//いちご ぱんだ //a.nameの値をコピーする //オブジェクトとは切り離され、変数nameと値の「いちご」が生成される //分割代入を行う場合:変数とkeyの名前は合わせる let {name: animal} = a;//変数名を変更したい場合 関数と分割代入 const a = { name: 'いちご' } function fn(obj) { let { name } = a; name = 'ぶどう' console.log(a, name);//いちご ぶどう } fn(a); //元のオブジェクトへの影響はない //簡略化できる function fn2({ name }) { name = 'ぶどう' console.log(a, name);//いちご ぶどう } fn2(a); //関数の引数にオブジェクトが入る際分割代入で引数nameが使える状態になる 多階層のオブジェクトから分割代入で宣言した変数が、オブジェクトだった場合値を変更すると分割代入元の値にも影響がある オブジェクトの比較 const a { name: 'いちご' } const b { name: 'いちご' } console.log(a === b)//結果 false console.log(a == b)//結果 false //オブジェクトの格納されている変数はオブジェクトへの参照を保持している //参照しているオブジェクトが違うためfalseになる console.log(a.name === b.name)//結果 true //オブジェクトの値を比較するとtrueになる
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

fetchとかで取ってきた生HTMLからDOMを作ってqueryselector()をしたい。

ブラウザのJavaScriptでただの文字列状態のHTMLを、DOM(ツリー、NODE)に変換して色々操作したいって場合を調べたくて検索をかけると div = document.createElement('div'); div.innerHTML = textHtml; って感じにして取り出す感じの記事しか見つからなくて、モヤモヤするのでメモ。 そもそもこの手法だと <!DOCTYPE html> とか入っていると変換もできない。 しかも、imgタグとか不必要なコンテンツも読み込んでしまう。 手法としては DOMParser を使う。 function convert(textHtml) { const parser = new DOMParser(); const $document = parser.parseFromString(textHtml, 'text/html'); return $document; } これだけ。 以上。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【javascript】スプレット構文の使い方基礎

jsのスプレット構文うろ覚えすぎて一瞬なにそれ?となった(やばい)ので改めて調べて手を動かして覚えよう!ということでその備忘録です。 間違いや認識違いなどなにかあったらコメントいただけると嬉しいです〜 スプレット構文とは MDN先生によると スプレッド構文 (...) を使うと、配列式や文字列などの反復可能オブジェクトを、0 個以上の引数 (関数呼び出しの場合) や要素 (配列リテラルの場合) を期待された場所で展開したり、オブジェクト式を、0 個以上のキーと値の組 (オブジェクトリテラルの場合) を期待された場所で展開したりすることができます。 そのまんまですね。要素を展開してくれるので、配列の[ ]やオブジェクトの{ }を外すことができるし、変更などで使う事もできる。 使い方 展開 シンプルな配列の場合[]をはずして展開されます。 arrayという箱から1つづつポイポイ出してくれた(展開した)ので[]がとれたということですね。 const array = [1,2,3] console.log(array) //[ 1, 2, 3 ] console.log(...array) //1 2 3   オブジェクトの場合は{}をつける必要があります。箱から1つづつポイポイ出してもkeyとvalueはあるからです。 オブジェクトのすべてのキーと値の組を渡してくれます。 const objectArray = {a: 1, b:2} console.log(objectArray) //{ a: 1, b: 2 } console.log({...objectArray}) //{ a: 1, b: 2 }   文字列を展開することもできます。 const str = "こんにちは" console.log(str)//こんにちは console.log(...str)//こ ん に ち は 配列やオブジェクトに展開することもできます。 const strArray = [...str] console.log(strArray) //[ 'こ', 'ん', 'に', 'ち', 'は' ] const strObject = {...str} console.log(strObject)//{ '0': 'こ', '1': 'ん', '2': 'に', '3': 'ち', '4': 'は' } 追加(マージ) 配列同士をマージしたり、前後に要素を追加することができます。 const array1 = [1,2,3] const array2 = [4,5,6] const array3 = [...array1,...array2] const array4 = [...array2,7,8,9] const array5 = [-2,-1,0,...array1] console.log(array3) //[ 1, 2, 3, 4, 5, 6 ] console.log(array4) //[ 4, 5, 6, 7, 8, 9 ] console.log(array5) //[ -2, -1, 0, 1, 2, 3 ]   オブジェクトも同様です const objectArray1 = {a: 1, b:2} const objectArray2 = {c: 3, d:4} const objectArray3 = {...objectArray1,...objectArray2} const objectArray4 = {...objectArray1, d: 4} const objectArray5 = {z: 0, ...objectArray1} console.log(objectArray3) //{ a: 1, b: 2, c: 3, d: 4 } console.log(objectArray4) //{ a: 1, b: 2, d: 4 } console.log(objectArray5) //{ z: 0, a: 1, b: 2 } キーの名前が同じ場合はマージされ、後の値で上書きされます const objectArray1 = {a: 1, b:2} const objectArray2 = {c: 3, d:4} const objectArray3 = {...objectArray1,...objectArray2, d: 10} const objectArray4 = {d: 20, ...objectArray1} console.log(objectArray3) //{{ a: 1, b: 2, c: 3, d: 10 } console.log(objectArray4) //{ d: 20, a: 1, b: 2 } 複製 変数を渡してあげることで、arr.slice() のような動きをしてくれるので、変数の参照渡しを回避することができます。 const arr1 = [1, 2, 3] const arr2 = arr1 const arr3 = [...arr1] arr1.push(4); console.log(arr1)// [ 1, 2, 3, 4 ] console.log(arr2)// [ 1, 2, 3, 4 ] console.log(arr3)// [ 1, 2, 3 ] オブジェクトの場合も同様です const objectArray1 = {a: 1, b:2} const objectArray2 = objectArray1 const objectArray3 = {...objectArray1} objectArray1.c= 3; console.log(objectArray1)// { a: 1, b: 2, c: 3 } console.log(objectArray2)// { a: 1, b: 2, c: 3 } console.log(objectArray3)// { a: 1, b: 2 } 注意点 コピーは1段階の深さで行われるため、多次元配列のようなオブジェクトをコピーする場合には適していません。 次の例では、array1にも影響が出てしまっています。 let array1 = [[1], [2], [3]]; let array2 = [...array1]; array2.shift().shift(); console.log(array1)// [ [], [ 2 ], [ 3 ] ] console.log(array2)// [ [ 2 ], [ 3 ] ] 関数使用例 function sum(x, y, z) { return x + y + z } const numArray = [1,2,3] console.log(sum(...numArray))// 6
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【AWS】ElasticTranscoderで動画変換する仕組みを構築する

はじめに 今回、弊社運動通信社で開発しているスポーツブルアプリの中のスーパープレイ動画機能の裏側について少しご紹介させていただきます。 スーパープレイ動画機能とは様々な競技のスーパープレイの部分を切り取った縦型の動画集をスワイプしながらザッピング感覚で閲覧できるものです。 ↓動画は以下のように縦型フルスクリーンで閲覧できます。 ザッピング感覚で閲覧できるようにする上で通信環境の考慮が必要となってきます。 通信環境によって読み込み時間が長いと体験が損なわれてしまうため、通信環境に応じた複数ビットレートの動画を用意し、その点を解決しました。 具体的にはAWSのElasticTranscoderを使ってその仕組みを構築してみましたので、事例としてご紹介したいと思います。 構成イメージ ざっくりした構成と処理の流れはこんな感じになります。 手順 ElasticTranscoderの設定 Pipeline ジョブを管理するキューです。作成したキューをLambda側から指定するため必要な項目を入力し作成します。 主な設定内容は以下となります。 変換元ファイル入力先S3バケット 変換後ファイル出力先S3バケット サムネイル出力先S3バケット SNSのtopic作成 Preset 変換処理に適用される設定を定義したテンプレートです。こちらも事前に作成しておいて、Lambdaからジョブを作成する際に使用するものを指定します。 設定の詳細については公式ドキュメントで参照できます。 Lambdaの作成 まず構成イメージの①②のところにあたる変換を実行するコードを書いていきます。 変換実行のサンプルコード const aws = require('aws-sdk'); const transcoder = new aws.ElasticTranscoder({apiVersion: '2012-09-25', region: 'ap-northeast-1'}); exports.handler = async (event, context, callback) => { const key = event['Records'][0].s3.object.key; const file = key.split('/').reverse()[0]; const filename = file.split('.')[0]; new Promise((resolve, reject) => { try { const params = { // ElasticTranscoderのコンソールから作成したPipelineのID PipelineId: 'xxxxxxxxxxxxx-xxxxxx', OutputKeyPrefix: 'sample/', Input: { Key: key, FrameRate: 'auto', Resolution: 'auto', AspectRatio: 'auto', Interlaced: 'auto', Container: 'auto' }, // 複数ビットレートの動画を出力する場合はここで対応する複数のpresetを指定する Outputs: [ { Key: `preset1/${filename}.mp4`, ThumbnailPattern: `thumbnail/${filename}-{count}`, // ElasticTranscoderのコンソールから作成したPresetのID PresetId: 'xxxxxxxxxxxxx-xxxxxx', Rotate: 'auto' } ] }; // ElasticTranscoderのJob作成 transcoder.createJob( params, function(error, data) { if (error) { console.log(error); throw new Error(error); } else { console.log('Job submitted.'); } } ); } catch(e) { reject(e); return; } resolve(); return; }).catch((e) => { callback(e); }); callback(null, 'Success.'); } 変換完了後は構成イメージの④⑤のようにSNSから通知を受け取り、完了後の処理を実装できます。 変換完了後のサンプルコード const aws = require('aws-sdk'); exports.handler = async (event, context, callback) => { const snsMessage = JSON.parse(event.Records[0].Sns.Message); // メッセージの中身を見て必要な処理を行う }; 終わりに 今回は、ElasticTranscoderを使った構成についてご紹介させていただきました。実際にシステムに組み込む場合は動画をサーバーからアップロードしたり、完了後にも必要な処理を組み込むなどあるかと思いますが、動画変換については基本的には今回ご紹介したような形になるかと思いますので少しでもご参考になる方がいらっしゃれば幸いです。 それでは。 参考サイト 運動通信社は 「日本を世界が憧れるスポーツ大国にする」というビジョンを達成するべく、 一緒に働く仲間を募集しています! https://sportsbull.jp/about/#recruit
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

基礎の「き」。Typescriptで学ぶ「クラス」

はじめに 最近、プログラミング初学者の天敵(?)である「クラス」をようやく退治する気になりました。 という訳で、本記事ではTypescriptにおける「クラス」について基礎から探っていきます。 ※執筆者である私は、プログラミング初学者です。そのため扱うレベルが低く、内容に誤りが含まれている可能性もありますが、ご容赦下さい。 クラスとは? JavascriptやTypescriptにおいて、オブジェクトを生成する方法は2つあります。 ①オブジェクトリテラル ②クラス ①のオブジェクトリテラルは、直接オブジェクトを生成する方法です。 //こんな感じ const point = { x: 1, y: 2 } 一方、クラスとはオブジェクトの設計図のようなものです。 設計図を用意しておき、必要な場面でオブジェクトを生成します。 同じようなオブジェクトが複数必要な場合は、クラスを用いると便利です。 クラスの定義 一例ですが、クラスは下記のように定義されます。 class Point { x: number; y: number; constructor(x: number, y: number) { this.x = x; this.y = y; } } var p1 = new Point(0, 10); var p2 = new Point(10, 20); classというキーワードを使って、クラスが定義されています。 何か色々と見慣れないものが出てきましたが、まずこの部分に着目します。 var p1 = new Point(0, 10); var p2 = new Point(10, 20); 定義されたクラスを、上記の記述によって、オブジェクトを作成しています。 クラスから作成されたオブジェクトは、「インスタンス」と呼ばれます。 仮にクラスを使用しないとなると、p1やp2といったオブジェクト毎に記述が必要になってしまいます。 クラスの便利さが何となく分かってきました。 console.log()でオブジェクトを確認しておきます。 console.log(p1) console.log(p2) console.log(Point) //結果 下記のようなオブジェクトが出来上がる。 { "x": 0, "y": 10 } { "x": 10, "y": 20 } コンストラクタ 次は、下記部分を理解していきます。 constructor(x: number, y: number) { this.x = x; this.y = y; } これは「コンストラクタ」と呼ばれるメソッドです。コンストラクタは、newでインスタンス(オブジェクト)を作成する際に、最初に呼び出される特別なメソッドです。 コンストラクタは、オブジェクトの作成に必要な「引数」を渡す役割を担います。 クラスは設計図です。そこに、データ(引数)を渡すことで、個別のインスタンス(オブジェクト)が作成されます。 データ(引数)は、コンストラクタというメソッドを用いて、クラスに渡されます。 var p1 = new Point(0, 10); //0,10 がコンストラクタメソッドの引数に渡される。 var p2 = new Point(10, 20); //10,20がコンストラクタメソッドの引数に渡される。 コンストラクトを用いないと? コンストラクタを用いない場合、どういう記述になるか気になりました。 こんな感じでしょうか? class Point { x: number; y: number; } var p1 = new Point(); p1.x = 0; p1.Y = 10 var p2 = new Point(); p2.x = 10; p2.Y = 20; コンストラクタを用いたほうが、簡単にインスタンスが作成できそうです。 クラスにメソッドを追加する クラスにはメソッドを追加することが出来ます。 class Point { x: number; y: number; constructor(x: number, y: number) { this.x = x; this.y = y; } //functionは省略して記述される。 showNumber() { console.log(`x:${this.x}, y:${this.y}`); } //function showNumber() { // return new Point(this.x + point.x, this.y + point.y); // } } var p1 = new Point(0, 10); //メソッドを呼び出す。 p1.showNumber() クラス内の値を参照する時は、thisを用います。thisの挙動については、非常に面白いので後述します。 クラス内のメソッドの活用 クラス内のメソッドは、例えば下記のように活用することができます。 class Point { x: number; y: number; constructor(x: number, y: number) { this.x = x; this.y = y; } add(point: Point) { return new Point(this.x + point.x, this.y + point.y); } } var p1 = new Point(0, 10); var p2 = new Point(10, 20); var p3 = p1.add(p2); // {x:10,y:30} 難しいですね。 ちなみにこれらのコードは、公式ドキュメントから拝借しています。 流れとしては、こんな感じでしょうか。 ①p1,p2オブジェクトの作成 ②p1オブジェクトの、addメソッドを呼び出す。その際、引数としてp2オブジェクトが渡される。(p1.add(p2)の部分) ③addメソッドは、新しいインスタンス(オブジェクト)を作成する(返す)。 そして、p3をconsole.log()で確認すると、{x:10,y:30}が出力される。 p1{x:0,y:10}にp2{x:10,y:20}が加算され、{x:10,y:30}になっています。 クラスを定義すると、自動で型が生成される。 この部分に着目してみて下さい。 //引数に型Pointが指定されている。 add(point: Point) { //省略 } 引数にPoint型が指定されています。 Point型がいつ定義されているかというと、クラスを定義したタイミングです。 クラスを定義したタイミングで、そのクラスの型が自動で作成されます。 この場合Point型は、x,yプロパティ、addメソッドを持つオブジェクトです。 add(point: Point)において、addメソッドの引数には、Point型しか渡せないという指定になっています。 thisの挙動 ここからは少々マニアック?な話になります。 class Point { x: number; y: number; constructor(x: number, y: number) { this.x = x; this.y = y; } showNumber() { console.log(`x:${this.x}, y:${this.y}`); } } var p1 = new Point(0, 10); p1.showNumber() //結果 "x:0, y:10" 上記のようなコードを、以下のように書き換えてみます。 class Point { x: number; y: number; constructor(x: number, y: number) { this.x = x; this.y = y; } showNumber() { console.log(`x:${this.x}, y:${this.y}`); } } var p1 = new Point(0, 10); const anotherP1 = { anotherShowNumber: p1.showNumber } anotherP1.anotherShowNumber() //結果 "x:undefined, y:undefined" undefinedになってしまいますね。 オブジェクトの中でthisを使用した場合、thisはそのオブジェクトを示します。 つまりこの場合のthisは、anotherP1を参照しているのです。 例えばこのように記述してみます。 class Point { x: number; y: number; constructor(x: number, y: number) { this.x = x; this.y = y; } showNumber() { console.log(`x:${this.x}, y:${this.y}`); } } var p1 = new Point(0, 10); const anotherP1 = { x: 100, //追加 y: 200, //追加 anotherShowNumber: p1.showNumber } anotherP1.anotherShowNumber() //結果 "x:100, y:200" thisの使用についてはまだまだ追求できそうですが、とりあえずここまでにしておきます。 興味のある方は、class内のメソッドをアロー関数で記述したらどうなるか、試してみると面白いです。 最後に 長くなったので、続きは別の記事にしておきます。 次回以降は、クラスの継承やメソッドのオーバーライド、アクセス修飾詞、setterとgetterについて触れていきます。 参考 TypeScript Deep Drive 日本語版 超TypeScript入門 完全パック(2021) TypeScriptハンズオン
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ブラウザのテキスト読み上げに合わせてバーが伸び縮みするアニメーション

ブラウザのテキスト読み上げに合わせてバーが伸び縮みするアニメーション TEXTAREA に入力したテキストを読み上げます。 ページ下部のソースをローカルに保存してご利用ください。 Windows 10 上の Google Chrome、Microsoft Edge、Firefox で動作を確認しています。 Microsoft Edge は、音声で日本語を選択しないと読み上げてくれませんでした。 パソコンのスピーカーから出た音声をマイクで拾って可視化しているので、ヘッドホンなどで音声出力がふさがっていると、バーの表示は何も起きません。 ブラウザが読み上げた台詞だけでなく、ユーザが読み上げた台詞にも反応しますが、気にしてはいけません。 「それは失敗じゃない。”大失敗”だ。」 Canvasで赤いLEDが残光を曳くアニメーション が必要な方は過去の投稿をどうぞ。 使い方 TEXTAREA にお好みの名台詞/迷台詞を入力して「話す」ボタンを押すと、マイクの使用許可を求めるダイアログが出ます。 マイクの使用を許可すると、数秒後に読み上げが始まります。 実行するとこんな感じです。 ソース speak.html <!DOCTYPE html> <html lang='ja'> <head> <meta http-equiv='Content-Type' content='text/html; charset=utf-8' /> <meta http-equiv="Pragma" content="no-cache"> <meta http-equiv="Cache-Control" content="no-cache"> <title>What would you like to hear?</title> <script> let $ = e => document.getElementById(e); const LEDColor = { red: 0, yellow: 1 }; Object.freeze(LEDColor); class Lamp { constructor() { this.width = 20; this.height = 11; this.x = 0; this.y = 0; this.brightness = 100; //0 <= brightness <= 100 this.colortype = LEDColor.red; } color() { const alpha = ((this.brightness == 0) ? 0 : 1); return (this.colortype == LEDColor.red) ? {r:Math.round(255 * this.brightness / 100), g:0, b:0, a:alpha} : {r:Math.round(255 * this.brightness / 95), g:Math.round(255 * this.brightness / 90), b:0, a:alpha}; } drawon(context) { const mycolor = this.color(); context.fillStyle = "rgba(" + mycolor.r + "," + mycolor.g + "," + mycolor.b + "," + mycolor.a + ")"; context.fillRect(this.x, this.y, this.width, this.height); } } const LEDArray = { vLamp: [[], [], []], col: 3, row: 16, brightness_min: 10, colortype: LEDColor.red, init() { let r = this.row; this.vLamp = new Array(3); this.vLamp[0] = new Array(r).fill(0); this.vLamp[1] = new Array(r).fill(0); this.vLamp[2] = new Array(r).fill(0); const gap_x = 3; const gap_y = 1; let x0 = 40, y0 = 28, x = x0, y = y0; for (let i = 0; i < this.col; i++) { y = y0; for (let j = 0; j < r; j++) { this.vLamp[i][j] = new Lamp(); Object.assign(this.vLamp[i][j], {x:x, y:y, brightness:10}); y += (this.vLamp[i][j].height + gap_y); } x += (this.vLamp[i][0].width + gap_x); } }, setBrightness_off() { for (let i = 0; i < this.col; i++) { for (let j = 0; j < this.row; j++) { Object.assign(this.vLamp[i][j], {brightness:this.brightness_min, colortype:this.colortype}); } } }, setBrightness(brightness) { //center for (let j = 0; j < this.row; j++) { Object.assign(this.vLamp[1][j], {brightness:brightness * Math.cos((j - 7.5) / 23.5 * Math.PI), colortype:this.colortype}); } //side if (this.colortype == LEDColor.red) { for (let i = 0; i < this.col; i += 2) { for (let j = 0; j < this.row; j++) { Object.assign(this.vLamp[i][j], {brightness:brightness * Math.cos((j - 7.5) / 13.5 * Math.PI), colortype:this.colortype}); } } } else { for (let i = 0; i < this.col; i += 2) { for (let j = 0; j < this.row; j++) { Object.assign(this.vLamp[i][j], {brightness:brightness * (1 - Math.sin((j + 0.5) / 15.5 * Math.PI)), colortype:this.colortype}); } } } } } const Animation = { context: 0, init() { LEDArray.init(); const canvas = $("canvas"); if (!canvas.getContext) { return; } this.context = canvas.getContext("2d"); this.redraw_off(); }, redraw_off() { LEDArray.setBrightness_off(); for (let i = 0; i < LEDArray.col; i++) { for (let j = 0; j < LEDArray.row; j++) { LEDArray.vLamp[i][j].drawon(this.context); } } }, redraw(brightness) { LEDArray.setBrightness(brightness); for (let i = 0; i < LEDArray.col; i++) { for (let j = 0; j < LEDArray.row; j++) { LEDArray.vLamp[i][j].drawon(this.context); } } } } const allVoicesObtained = new Promise(function(resolve, reject) { let voices = window.speechSynthesis.getVoices(); if (voices.length !== 0) { resolve(voices); } else { window.speechSynthesis.addEventListener("voiceschanged", function() { voices = window.speechSynthesis.getVoices(); voices.sort(function(a, b) { return (a.lang > b.lang) ? 1 : -1; }); resolve(voices); }); } }); function InitVoice() { let ssu = new SpeechSynthesisUtterance(); ssu.text = " "; window.speechSynthesis.speak(ssu); allVoicesObtained.then(voices => { const select = $("selVoice"); let nSelected = -1; for (let i = 0; i < voices.length; i++) { const option = document.createElement("option"); option.text = voices[i].lang + " " + voices[i].name; option.value = i; select.appendChild(option); if ((nSelected == -1) && (voices[i].lang.substr(0, 2) == "en")) { nSelected = i; } } if (nSelected == -1) { nSelected = 0; } select.options[nSelected].selected = true; }); } function doSpeak() { const select = $("selVoice"); const option = select.options[select.selectedIndex]; let ssu = new SpeechSynthesisUtterance(); ssu.lang = option.text.substr(0, 5); ssu.volume = 1.0; ssu.rate = 1.0; ssu.pitch = 1.0; ssu.text = " "; window.speechSynthesis.speak(ssu); allVoicesObtained.then(voices => { for (let i = 0; i < voices.length; i++) { if (voices[i].name == option.text.substring(6)) { ssu.voice = voices[i]; break; } } }); ssu.text = $("script").value; ssu.onend = function(ev) { //$("btnStop").onclick(); } window.speechSynthesis.speak(ssu); } function doShutUp() { window.speechSynthesis.cancel(); } function split_text(text) { const eol = text.match(/\r\n|\n|\r/); let vLines = text.split(eol).map(s => s.trim()); return vLines.filter(s => s != ""); } const MediaStream = { stream: {}, start() { //window.speechSynthesis.onvoiceschanged = function() { // window.speechSynthesis.getVoices(); //}; let objAudioContext = new (window.AudioContext || window.webkitAudioContext)(); navigator.mediaDevices.getUserMedia({ audio: true, video: false }).then((stream) => { doSpeak(); this.stream = stream; let src = objAudioContext.createMediaStreamSource(this.stream); let analyser = objAudioContext.createAnalyser(); analyser.fftSize = 2048; let processor = objAudioContext.createScriptProcessor(0, 1, 1); processor.onaudioprocess = (ev) => { let dataArray = new Uint8Array(analyser.fftSize); analyser.getByteTimeDomainData(dataArray); let ymax = 0; for (let i = 0; i < dataArray.length; i++) { let y = dataArray[i] / 128.0 * 100 - 100; ymax = Math.max(ymax, y); } Animation.redraw(ymax); } src.connect(processor); processor.connect(objAudioContext.destination); src.connect(analyser); }).catch((err) => { console.log(err); }) }, stop() { doShutUp(); this.stream.getTracks().forEach((track) => { track.stop(); }) } } window.onload = function() { if (!navigator.getUserMedia) { navigator.getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia; } $("btnStart").onclick = () => { $("btnStart").disabled = true; $("btnStop").disabled = false; MediaStream.start(); } $("btnStop").onclick = () => { if (!$("btnStart").disabled) { return; } $("btnStart").disabled = false; $("btnStop").disabled = true; MediaStream.stop(); } document.getElementsByName("rdoColor").forEach( e => e.addEventListener("change", ev => { LEDArray.colortype = (ev.target.value == 1) ? LEDColor.yellow : LEDColor.red; Animation.redraw_off(); } ) ); InitVoice(); Animation.init(); } </script> </head> <body> <h2>テキスト読み上げに合わせてバーが伸び縮み</h2> <canvas id="canvas" width="150" height="250" style="background-color:#1e1e1e;"></canvas> <br /> <div> 色: <input type="radio" name="rdoColor" value="0" checked />赤 <input type="radio" name="rdoColor" value="1" />黄 <br /> 音声: <select id="selVoice" style="width:350;"> </select> <button id="btnStart">話す</button> <button id="btnStop" disabled>中止</button> </div> <textarea id="script" rows="20" col="100" style="width:700px;height:150px;"> The quick brown fox jumps over the lazy dog. </textarea> </body> </html>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[JavaScript] Promiseオブジェクトを順次実行するサンプル

Promise ではまったことがあったので、サンプルを動かしつつ学びなおしました。 参考 配列のPromiseを直列で実行する方法 https://zenn.dev/wintyo/articles/2973f15a265581 こちらの実装を元にして応用させていただきました。ありがとうございます。 動作確認 下記環境で行いました。 node -v v16.5.0 deno -V deno 1.9.0 コード const waitTimes = [300, 100, 200, 500, 400]; function wait(waitTime, name) { return new Promise((resolve) => { setTimeout(() => { console.log(`${name} ${waitTime}ms waited.`); resolve(); }, waitTime); }); } (async () => { console.log('start wait') await (async () => { wait(waitTimes[0], 'wait'); wait(waitTimes[1], 'wait'); wait(waitTimes[2], 'wait'); wait(waitTimes[3], 'wait'); wait(waitTimes[4], 'wait'); })(); console.log('end wait') await wait(2000, 'end wait') // 単に Promise オブジェクトを生成すると並列に実行され // end も待機しない // start wait // end wait // wait 100ms waited. // wait 200ms waited. // wait 300ms waited. // wait 400ms waited. // wait 500ms waited. console.log('start Promise.all 1') await (async () => { await Promise.all([ wait(waitTimes[0], 'Promise.all 1'), wait(waitTimes[1], 'Promise.all 1'), wait(waitTimes[2], 'Promise.all 1'), wait(waitTimes[3], 'Promise.all 1'), wait(waitTimes[4], 'Promise.all 1'), ]); })(); console.log('end Promise.all 1') // Promise.all で並列に実行され、終了も待機することができる // start Promise.all 1 // Promise.all 1 100ms waited. // Promise.all 1 200ms waited. // Promise.all 1 300ms waited. // Promise.all 1 400ms waited. // Promise.all 1 500ms waited. // end Promise.all 1 console.log('start Promise.all 2') await (async () => { await Promise.all( waitTimes.map((waitTime) => { return wait(waitTime, 'Promise.all 2'); }) ); })(); console.log('end Promise.all 2') // Promise.all に Promise オブジェクトの配列を渡す場合は // 並列に実行され、終了も待機することができる // start Promise.all 2 // Promise.all 2 100ms waited. // Promise.all 2 200ms waited. // Promise.all 2 300ms waited. // Promise.all 2 400ms waited. // Promise.all 2 500ms waited. // end Promise.all 2 console.log('start Promise.all 3') await (async () => { await Promise.all( waitTimes.map((waitTime) => { wait(waitTime, 'Promise.all 3'); }) ); })(); console.log('end Promise.all 3') await wait(2000, 'end wait') // Promise.all に Promise オブジェクトの配列を渡さない場合は // 待機されずに実行されるので、end が先に実行される // start Promise.all 3 // end Promise.all 3 // Promise.all 3 100ms waited. // Promise.all 3 200ms waited. // Promise.all 3 300ms waited. // Promise.all 3 400ms waited. // Promise.all 3 500ms waited. console.log('start Promise.all 4') await (async () => { await Promise.all( waitTimes.map(async (waitTime) => { await wait(waitTime, 'Promise.all 4'); }) ); })(); console.log('end Promise.all 4') // Promise.all に async 関数を渡して // await で待機すると、Promise オブジェクトを渡したのと同じく動作する // start Promise.all 4 // Promise.all 4 100ms waited. // Promise.all 4 200ms waited. // Promise.all 4 300ms waited. // Promise.all 4 400ms waited. // Promise.all 4 500ms waited. // end Promise.all 4 console.log('start Promise.all 5') await (async () => { await Promise.all( waitTimes.map(async (waitTime) => { wait(waitTime, 'Promise.all 5'); }) ); })(); console.log('end Promise.all 5') await wait(2000, 'end wait') // Promise.all にasync関数を渡すが // async 関数内で await しないと // 待機されずに実行されるので、end が先に実行される // start Promise.all 5 // end Promise.all 5 // Promise.all 5 100ms waited. // Promise.all 5 200ms waited. // Promise.all 5 300ms waited. // Promise.all 5 400ms waited. // Promise.all 5 500ms waited. console.log('start for await') await (async () => { for await (const result of [ wait(waitTimes[0], 'for await'), wait(waitTimes[1], 'for await'), wait(waitTimes[2], 'for await'), wait(waitTimes[3], 'for await'), wait(waitTimes[4], 'for await'), ]) {} })(); console.log('end for await') // for await は並列に実行され、終了も待機することができる // start for await // for await 100ms waited. // for await 200ms waited. // for await 300ms waited. // for await 400ms waited. // for await 500ms waited. // end for await console.log('start for() { await }') await (async () => { for (const waitTime of waitTimes) { await wait(waitTime, 'for() { await }'); } })(); console.log('end for() { await }') // for 内で await すると、順次実行される // start for() { await } // for() { await } 300ms waited. // for() { await } 100ms waited. // for() { await } 200ms waited. // for() { await } 500ms waited. // for() { await } 400ms waited. // end for() { await } console.log('start then callback') await (() => new Promise(resolve => { wait(waitTimes[0], 'then callback').then(() => { wait(waitTimes[1], 'then callback').then(() => { wait(waitTimes[2], 'then callback').then(() => { wait(waitTimes[3], 'then callback').then(() => { wait(waitTimes[4], 'then callback').then(() => { resolve() }) }) }) }) }) }))(); console.log('end then callback') // Promise オブジェクトの then 内で さらに then を呼び出して // 連続コールバック関数を使うと、順次実行される // start then callback // then callback 300ms waited. // then callback 100ms waited. // then callback 200ms waited. // then callback 500ms waited. // then callback 400ms waited. // end then callback console.log('start then mechod chain 1') await (() => new Promise(resolve => { wait(waitTimes[0], 'then mechod chain 1') .then(() => wait(waitTimes[1], 'then mechod chain 1')) .then(() => wait(waitTimes[2], 'then mechod chain 1')) .then(() => wait(waitTimes[3], 'then mechod chain 1')) .then(() => wait(waitTimes[4], 'then mechod chain 1')) .then(() => { resolve() }) }))(); console.log('end then mechod chain 1') // Promise オブジェクトの then のメソッドチェーンを使って // then 内で Promise オブジェクトを return すると、順次実行される // start then mechod chain 1 // then mechod chain 1 300ms waited. // then mechod chain 1 200ms waited. // then mechod chain 1 500ms waited. // then mechod chain 1 400ms waited. // end then mechod chain 1 console.log('start then mechod chain 2') await (() => new Promise(resolve => { wait(waitTimes[0], 'then mechod chain 2') .then(() => { wait(waitTimes[1], 'then mechod chain 2') } ) .then(() => { wait(waitTimes[2], 'then mechod chain 2') } ) .then(() => { wait(waitTimes[3], 'then mechod chain 2') } ) .then(() => { wait(waitTimes[4], 'then mechod chain 2') } ) .then(() => { resolve() }) }))(); console.log('end then mechod chain 2') await wait(2000, 'end wait') // Promise オブジェクトの then のメソッドチェーンを使って // then 内で Promise オブジェクトを return しないと、 // wait(waitTimes[0] だけ待機したあとに end が実行され // あとは平行実行される // start then mechod chain 2 // then mechod chain 2 300ms waited. // end then mechod chain 2 // then mechod chain 2 100ms waited. // then mechod chain 2 200ms waited. // then mechod chain 2 400ms waited. // then mechod chain 2 500ms waited. console.log('start then mechod chain 3') await (() => new Promise(resolve => { wait(waitTimes[0], 'then mechod chain 3') .then(wait(waitTimes[1], 'then mechod chain 3')) .then(wait(waitTimes[2], 'then mechod chain 3')) .then(wait(waitTimes[3], 'then mechod chain 3')) .then(wait(waitTimes[4], 'then mechod chain 3')) .then(() => { resolve() }) }))(); console.log('end then mechod chain 3') await wait(2000, 'end wait') // Promise オブジェクトの then のメソッドチェーンを使って // then 内で Promise オブジェクトを返す関数を渡すと // 並行実行され、wait(waitTimes[0] のあとに end が実行される // start then mechod chain 3 // then mechod chain 3 100ms waited. // then mechod chain 3 200ms waited. // then mechod chain 3 300ms waited. // end then mechod chain 3 // then mechod chain 3 400ms waited. // then mechod chain 3 500ms waited. })(); 解説 最初にミリ秒を指定する配列を、順番ばらばらに定義しています。 wait 関数で、指定ミリ秒を待機してからログ出力しています。 並列実行、つまり非同期実行する場合は、待機ミリ秒に従って 100,200,300,400,500 の順番で出力されます。 直列実行、つまり、非同期を同期的に実行する順次実行の場合は、配列の定義通り、300, 100, 200, 500, 400 の順に実行されます。 あとは、コード内のコメント参照してください。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Gmail】特定のメールへの直リンクを取得する方法

はじめに 2022年の改正電子帳簿保存法にNotionで対応するために、Gmail内のメールを紐付けられるURLを取得したかったのですが、直リンク発行が機能として提供されていないようでした。 GASや何かを使う方法は目にしましたが、よりシンプルな方法で実現できたので共有します。 直リンク取得方法 下記のスクリプトをブックマークレットとして登録して、Gmailメール本文上で実行します。 ( my_email をあなたのGmailアドレスに置き換えます。) ブックマークレット javascript: (function () { async function copyPermalink() { try { my_email = "example@gmail.com"; search_url = "https://mail.google.com/mail/u/" + my_email + "/#search/msgid%3A"; message_id = document .querySelector("div[data-message-id]") .getAttribute("data-message-id") .substring(7); await navigator.clipboard.writeText(search_url + message_id); alert("Copied!\n\n" + search_url + message_id); } catch (err) { alert("Error!"); } } copyPermalink(); })(); メッセージIDで検索するリンクをクリップボードにコピーする 動作です。 さいごに 改正電子帳簿保存法的には、メール本文への直リンクなどなくてもスクショで十分な雰囲気ですが、メールに限らず原本へのリンクがあると便利だと思うので、用意しておきました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【JavaScript】変数と参照の振り返り⑤ AND条件とOR条件の応用

はじめに Udemyの【JS】ガチで学びたい人のためのJavaScriptメカニズムの講座の振り返りです。 前回の記事 目的 変数についての理解を深める 本題 1.AND条件とOR条件の応用 例 function hello(name){ console.log("Hello" + name); } // Hello Bobと表示される hello("Bob") // 引数がない場合、Hello undefinedと表示される hello() これを避けるためにif文を使って、該当しなかった場合の処理を追記する。 function hello(name){ // nameがundifine = falseな値である場合にTomと出力されればいいので // NOT演算子を条件式に加える if(!name){ name = "Tom" } console.log("Hello" + name); } // 結果、ここでは「Hello Tom」と出力される hello() この書き方を更に簡略化するためにAND条件、OR条件で書き換える。 function hello(name){ // OR条件の場合、trueな値が見つかった時点で出力する name = name || "Tom"; console.log("Hello" + name); } // nameはundefined(空欄)なのでfalse,結果Tomが出力される hello() // ここではnameに”Bob”が入っているので上記のnameがtrueになった時点で出力されている hello("Bob") // ES6からはデフォルト引数が設けられるため以下でも同じ意味になる function hello(name = "Tom"){ // name = name || "Tom"; console.log("Hello" + name); } // nameがTomじゃないからBobが出力される hello("Bob") OR条件を使う際の注意点 falseな場合に初期値を返すが、”数値”である場合は注意が必要 function hello(name){ name = name || "Tom"; console.log("Hello" + name); } // この場合、「Hello 0」と出力したいが0はfalseな値なのでTomと出力される hello(0) 応用例 function hello(name){ name = name || "Tom"; console.log("Hello" + name); } hello() let name = "Bob" if(name){ hello(name); } // nameがtrueである場合、Bobを呼ぶようにしたい if文でも書くことができるが、AND条件を用いて簡略化すると、以下の通りになる。 function hello(name){ name = name || "Tom"; console.log("Hello" + name); } hello() let name = "Bob" // 下記のように記述すると最初のnameがfalseの場合、次のhello(name)は実行されない name && hello(name) function hello(name){ name = name || "Tom"; console.log("Hello" + name); } hello() // 試しに下記のように、"Bob"を消してみると let name // nameはfalseになるので、上記のhello()のみになる name && hello(name) 今日はここまで! 参考にさせて頂いた記事 【JS】ガチで学びたい人のためのJavaScriptメカニズム
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[javascript] Object.keysの使い方

[javascript] Object.keysの使い方 Object.keysとは MDN Web Docsにはこのように説明されています。 Object.keys() メソッドは、指定されたオブジェクトが持つプロパティの 名前の配列を、通常のループで取得するのと同じ順序で返します。 Object.keys()を使ってみる js const object1 = { a: 'somestring', b: 42, c: false }; console.log(Object.keys(object1)); logの結果はArray ["a", "b", "c"]このように表示されます。 ここでObject.keys()は()の中に受け取ったObjectのプロパティを配列にして返しています。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Reactを始めたい人へ。今日だけでできるTODO #21 useContext①

useContextとは? propsを直接渡したい子孫コンポーネントに値を渡すことができるフックです。 孫コンポーネントに値を受け渡す場合、親コンポーネントから子コンポーネントに受け渡した値をさらに孫コンポーネントに渡す。 ということが必要でしたがuseContextを利用することで直接を渡すことができます。 オブジェクト / コンポーネント 説明 Contextオブジェクト React.createContext()の戻り値 Providerコンポーネント Contextオブジェクトが保持しているコンポーネント Consumerコンポーネント useContext()を利用することで、Contextオブジェクトから値を取得できる Contextオブジェクト const ContextObj = React.createContext(); または、 import React, { createContext } from 'react'; const ContextObj = createContext(); Providerコンポーネント .Providerでラップするとラップされたコンポーネントのツリー内でvalueの値を参照できるようになります。 <ContextObj.Provider value={ツリー内で共有可能なコンテキストオブジェクトの値} > <Consumer /> </ContextObj.Provider> import時にuseContextを読み込みます。 import React, { useContext } from 'react'; const コンテキストオブジェクトの値 = useContext(コンテキストオブジェクト); useContextの利用 import React, { createContext, useContext } from 'react'; const ContextObj = createContext(); const Consumer = () => { const message = useContext(ContextObj); console.log(message); return <p>{message}</p>; }; const message = 'React useContext'; export default function App() { return ( <> <ContextObj.Provider value={message}> <Consumer /> </ContextObj.Provider> </> ); }; useContextでContextオブジェクトから値を取得し、変数messageに格納します。 const message = useContext(ContextObj); messageにはProviderコンポーネントにてvalueに指定された値を受け取ります。 const message = 'React useContext'; export default function App() { return ( <> <ContextObj.Provider value={message}> <Consumer /> </ContextObj.Provider> </> ); }; すると画面に「React useContext」が表示されると思います。 次はファイルを分割した場合を試してみたいと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

これからReact始めたい人のための今日だけでできるTODO#21 useContext①

useContextとは? propsを直接渡したい子孫コンポーネントに値を渡すことができるフックです。 孫コンポーネントに値を受け渡す場合親コンポーネントから子コンポーネントに受け渡した値をさらに孫コンポーネントに渡す。 ということが必要でしたがuseContextを利用することで直接を渡すことができます。 オブジェクト / コンポーネント 説明 Contextオブジェクト React.createContext()の戻り値 Providerコンポーネント Contextオブジェクトが保持しているコンポーネント Consumerコンポーネント useContext()を利用することで、Contextオブジェクトから値を取得できる Contextオブジェクト const ContextObj = React.createContext(); または、 import React, { createContext } from 'react'; const ContextObj = createContext(); Providerコンポーネント .Providerでラップするとラップされたコンポーネントのツリー内でvalueの値を参照できるようになります <ContextObj.Provider value={ツリー内で共有可能なコンテキストオブジェクトの値} > <Consumer /> </ContextObj.Provider> Consumerコンポーネント import時にuseContextを読み込みます。 import React, { useContext } from 'react'; const コンテキストオブジェクトの値 = useContext(コンテキストオブジェクト); useContextの利用 import React, { createContext, useContext } from 'react'; const ContextObj = createContext(); const Consumer = () => { const message = useContext(ContextObj); console.log(message); return <p>{message}</p>; }; const message = 'React useContext'; export default function App() { return ( <> <ContextObj.Provider value={message}> <Consumer /> </ContextObj.Provider> </> ); }; useContextでContextオブジェクトから値を取得し、変数messageに格納します。 const message = useContext(ContextObj); messageにはProviderコンポーネントにてvalueに指定された値を受け取ります。 const message = 'React useContext'; export default function App() { return ( <> <ContextObj.Provider value={message}> <Consumer /> </ContextObj.Provider> </> ); }; すると画面に「React useContext」が表示されると思います。 次はファイルを分割した場合を試してみたいと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む