20220109のJavaScriptに関する記事は11件です。

お正月休みにGitをインタラクティブに操作できるサブコマンドツール作ってきました

年末からお正月にかけての時間で趣味でツールを作ってみました? Gitのちょっと面倒な操作をインタラクティブに行えるGitのサブコマンドツールgit-exを作成してnpmに公開しています。 僕は普段はAndroidエンジニアとしてKotlinを書いていますが、趣味ではVimのカラースキーム作ったり、Goでツール作ったり、Rustに手を出したり、、、など色々しています。今回はJavaScriptのターミナルのライブラリがとても良さそうだったのでnode製のCLIツールを作ってみました?! このQiita記事では前半にツールの紹介と、後半で実装面を書いてみようと思います。 ツールの紹介 僕は普段Gitをターミナル上でコマンドで使っているのですが、たまにSourceTreeなどのGUIツールやTIGなどのツールが使いたくなるときがあります。 たとえば、ファイルパスをいちいちGitの引数に指定しなければならないときなどです。そういうときだけSource Tree起動するのも面倒ですし、TIGを使うんとなると操作を覚えないとなかなか使い勝手がよくありません。 もう少し、ターミナル上で簡易に使えるようなツールがあれば便利だなと思って開発してみました。 git-exをインストールすると、いちいちファイルパスを指定しないといけないようなちょっと面倒なGit操作をターミナル上でインタラクティブに操作することができるようになります。 npmで公開しているJavaScript製のツールになります。インストールは下記で可能です。 npm i -g @yasukotelin/git-ex このツールをインストールすると git-ex コマンドが使えるようになるのですが、Gitはgit-xxx形式のコマンドをサブコマンドとして認識するので、git ex 形式で実行することが可能です。 サブコマンドとして認識されない場合は、一度ターミナルを再起動すると反映されると思います。 git-ex コマンドがそもそも見つからない場合は、npmのグローバルインストールモジュールへのパスが通っていないと思うので環境変数を確認してください。 git ex stage / unstage ステージング操作をするときは通常ターミナルでステージングするには下記のようなコマンドを打ちます。 # Gitプロジェクト内のすべての変更をステージングする git add -A # こっち使う人も多いかも。 git add . 大抵のケースでは正直これで事足ります。ですが、特定のファイルをaddしたいときは結構面倒です。 git add ファイルパス 例えば変更が3ファイルあって、1ファイルはコミットに含めたくないみたいなケースです。この場合、毎回愚直に引数にパス指定をするか、一度add allしてから、省きたいファイルをresetするみたいな操作をする必要があり、かなり面倒です。 ましてや、自分はAndroid開発をしているのもあって、Java系のファイルパスの長さは地獄です。とても補完で選択はしてられません。 そこで git ex stage コマンドを使うとマルチセレクトでファイルをステージングすることができるのでとても便利です? また逆の操作のアンステージも git ex unstage でできます。Gitってアンステージ処理をしようと思うと、そもそもコマンドが確かRESETかなんかで覚えにくいという部分もあります。個人的には git ex stage コマンドよりも重宝してます。 git ex stash 次はStashをよく使う人にもおすすめな git ex stash コマンドです。 Stashの基本的な操作をインタラクティブに選ぶ機能と、Stashの一覧から復元や破棄を選択して実行できる機能があります。 こんな感じです。 Stashの一覧を見て、選択するだけでpopしています。 これをGitのコマンドでやろうと思うと、微妙にやり方忘れててhelp引いたり、Listのどの部分を引数に指定すればいいんだっけってなっていたので助かります。 あと、Gifだと確認しづらいですが、うっすらとpopやapplyなどにカーソル合わせた時に説明も右側に出しているので、popだっけapplyだっけってなっても安心です。 追記ですが、記事執筆中にStashの内容も機能追加しました? git ex discard 変更を削除したいとき、SourceTreeなどのGUIツールでは変更を破棄するDiscard処理(Reset処理)が簡単にできると思います。 ターミナルで変更を破棄したい場合は、 git checkout ファイル名 や、 git clean -df などでできますが、そのものずばりな操作な感じではないのでいつも迷います。 この git ex discard を使えば下のGif画像のようにインタラクティブに変更を破棄できます。 PRレビューでちょっと試した差分を破棄したいときとかに便利です。 このDiscard処理は破棄になるのでGitの履歴には残りません。ご使用には十分ご注意ください。 git ex rm-merged 最後に、微妙に便利な、マージ済みブランチを削除できる git ex rm-merged コマンドを紹介します。 マージ済みのブランチをいつまでも残しておくと、checkout(switch)するときに無駄に選択肢が残っていたり、名前被りしていいことなかったりします。 GithubではPRをマージしたタイミングでマージ済みブランチを削除できるのでリモートブランチは削除しやすいです。ですがローカルは別途自分で git branch -d ブランチ名 しなくてはならないので億劫になりがちです。 そこでこの git ex rm-merged を使うとマージ済みブランチをリスト表示してくれてマルチセレクトで削除することができます。 このGifでは1件なのですが、たくさんあって一括で削除したい時も複数選択できます。ちなみに、aをタイプするとallで全選択されます。 マージ済みブランチはmain(master)やdevelopも対象になるのですが、現状はハードコーディングで対象外にしています。親ブランチなどを誤って削除しないようにご注意ください。 実装面 nodeで動作するJavaScript製のツールです。最初はTypeScriptで実装していたのですが、紆余曲折あって今はJavaScriptで実装されています。 webpackやbabelなどのビルドツール的なものは一切使っていないシンプル構成になっています。 JavaScript(TypeScript)はだいぶ前に業務で触ってたことがある程度で、普段は書いてません。なので実装時間よりも結構色々調べるところのほうが時間がかかりました? JavaScriptとTypeScript 普段Kotlinを書いてますし、今までツールを書くときにはGoをよく使っています。 久しぶりに型定義のない言語も書いてみたくなったというのもあってTypeScriptではなくJavaScriptを選びました(笑) 正直それ以外の理由は基本的には特にないです。JavaScriptが書きたくなったので選んだって感じです? それにしても、型定義しないで書くの、なんだか魔術感があってわくわくしますね? 個人で書くには楽ちんで結構ありだよなとちょっと再認識もできました。 あとは、ここ最近のJavaScriptの進化も体感してみたいというのもありました。jQuery全盛時代から考えると本当に色々書きやすくなっていて、不満はなかったですね。。classも、自分が読んでいた本ではprototypeを使って頑張るイメージでしたが普通に使えますし、いつの間にかフィールドも普通に定義できるようになってるんですね。 ESモジュールとCommonJS Reactの開発経験はあったのでES6は知っていましたが、CommonJSはよくわかっていませんでした(意識したことなかった)。 端的にまとめると、nodeはCommonJSなのでrequireを使ってモジュールをインポートしますが、ブラウザサイドはESモジュールなのでimportを使います。 // CommonJS const a = require('module'); // ESモジュール import a from 'a'; 最初ここらへんの知識がなかったので微妙に苦戦しました。僕はESモジュールで書きたかったのですが、 nodeはESモジュールにも対応しているようだったので、package.jsonで指定しました。 { "type": "module", } これでnodeでもESモジュール形式になってimport形式になりました。 また、import側だけでなくてモジュールをexportする側の書き方もESモジュールとCommonJSで書き方が違うので注意が必要でした。 ESモジュール指定をしていれば下記のような形式で書くことができます。 export default class XXX {} package.jsonを読み込みたい コマンドラインツールなので、 --help でバージョン表示などをしたいのですが、ここは可能ならpackge.jsonで定義しているバージョン情報などを使いたいところです。 CommonJSであれば、requireでjsonを読み込むことができます。 const { version, description } = require("../package.json"); ですが、ESModuleでは上記のように読み込むことはできません? その場合は、requireを生成してあげることで取得することができました。 const require = createRequire(import.meta.url); const { version, description } = require("../package.json"); CLIツールとして動作させるために nodeのモジュールをCLIツールとして動作させるには、package.jsonのbinに実行パスを指定するのとシバンの指定をすればOKです。 package.json { "bin": { "git-ex": "./src/index.js" }, } "git-ex" の部分がコマンド名です。右辺側に実行するパスを指定します。TypeScriptなどでコンパイルしている場合はそちらを指定します。 TypeScriptでdistに出力しているような場合 package.json { "bin": { "git-ex": "./dist/index.js" }, } あとはその実行ファイルの先頭行にシバンの指定をしてあげます。 #! /usr/bin/env node import { Option, program } from "commander"; import { RmMerged } from "./command/rmMerged.js"; // 実装がつらつら シバンとはなんぞやという方はこちらをご覧ください。 要はそのスクリプトファイルを何で実行するかを定義してあげる必要がある感じです。 ちょっと注意点としては、webpackを使った際にこのシバンの定義が消えてしまっていて、npm installした際に動かなくなってしまいました。今回は結局そういうのは使わなかったのでいいのですが、使いたい場合は調べたほうが良さそうです(回避策はありそう?な感じでした) ソースコードからインストール 開発中は以下のように実行できます。 node ./src/index.js package.jsonのscriptに指定して、普通は npm start とかで実行するものかなと思うのですが、ソースコードからグローバルインストールするにはどうすればいいのでしょうか? 意外とググっても出てこなかったのですが、そのままカレントディレクトリを指定すればOKみたいです npm install -g ./ こうするとローカルのプロジェクトをグルーバルインストールできます。npmに公開しなくてもツールのインストールができるので便利ですね。 commander.js コマンドラインの解析ツールにはcommander.jsを使用しました。 引数のパース処理とか、オプション、サブコマンド、ヘルプの自動生成をしてくれるライブラリで、これを使えば誰でもCLIツールが作れるようになります(?) なにか自分でCLIツールを作りたいときは、その言語でこの手のライブラリを見つけることから始めるといいと思います。だいたいどの言語にも作ってくれている人がいると思うので、活用するのがおすすめです(自分でやろうと思ったらあまりにも大変だと思う。。) これは git-ex の一部ですが、こんな感じで引数のサブコマンドを指定してあげるだけでよしなに関数を呼び出してくれる感じです。しかも、ヘルプまで生成してくれます。 index.js program .command("switch") .description("switch branch") .option("-r, --remote", "switch remote branch") .action((options) => switchBranch.action(options.remote)); program .command("stage") .description("stage files") .addOption(instructionsOption) .action((options) => stage.action(options.instructions)); prompts 2つ目がpromptsです。git-exの核を担っているライブラリで、ターミナルでセレクターや入力などのプロンプトのUIを提供してくれているライブラリです。 正直、このライブラリが良さそうだったので、git-exはJavaScriptで書きました。 このライブラリとても良くできていて、書きやすく、動作もばっちしでした。 ただ、作者がTypeScriptを使っていないというのもあって、TypeScriptから使おうとすると苦戦するかもです。 READMEの書き方で書けないですし、記載もないので自分でPRかコードを見て把握する必要があります。また、ESCキーなどでのキャンセルの動作もサポートされているはずなのですが、TypeScriptで記述した場合Exceptionが返ってきました(笑) Gitの呼び出し部分 皆さんご存知Gitは、なかなか融通の効かない感じになっておりまして、git-exはGitを呼び出しては、わりとごにょごにょ工夫して実装している部分がおおいです(笑) Gitの呼び出しには child_process の execSync() と spawnSync() を使っています。 同期関数なので処理はブロックしてしまうのですが、ターミナルは止めても問題ないので特に気にせず使っています。 使い分けなのですが、Gitのコマンド実行の結果を画面に表示せず取得したいときは execSync で、Gitのコマンド結果を画面に出力したい場合は spawnSync を使用しています。 例えば、ブランチの取得ですが、実行するのは git branch です。これをspawnのほうで実行してしまうとターミナルに結果が出力されてしまうので、execのほうを使ってあげることで文字列として結果を取得することができます。 const branches = execSync("git branch").toString().split(/\n/); // 最後の空行はトリミング 今度はDiffの実行です。今度は、ユーザーが選択したファイルをもとにDiffの結果を出力してあげたいので、spawnを使ってあげます。 spawnSync("git", ["diff", ...files], { stdio: "inherit" }); spawnのほうは若干癖のある書き方の気がしますね。inheritの部分をなしで実行するとdiffの結果が色無しで出力されてしまいます。inheritをつけてあげると、そのまま git diff を実行したときと同じ結果が出力されるようになる感じです。 prettierとGithub Actions テストとかLinterとかは書いてないですし導入もしてないのですが、フォーマッターは欲しいなと思ってprettierを入れてみました。 特にこだわりはないのでprettierはデフォルトの設定のまま入れています。 npm i -d prettier # フォーマット実行 npx prettier --write 'src/**/*.js" VSCodeの自動保存でフォーマットをかけるか、PR前に忘れずに実行すればいいのですが、人間忘れがちなものです。 そこでGithub Actionsで prettier --check 'src/**/*.js' を実行するようにして、PR時にパスしてなければやり直してねって形にしています。 おわり npmに公開するCLIツールを作ったのは初めてだったのですが、かなり書きやすくていい感じでした。 npmの公開の仕方も簡単でしたし、保守もやりやすそうです。 今後別のツールを作るときもしばらくはnodeで作ろうかなと思います。 慣れておけばWebのフロントエンドやサーバーサイドも書けるのでやっぱり便利よなって思いました。 git-ex自体も機能追加していって便利にしていく予定です✨
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScriptでPrimitive Type vs Reference Typeについて調べよう

JavaScriptはPrimitive TypeとReference Typeという二つのデータ型を提供し、オブジェクトを除いた全てのものはPrimitiveな性格を持っている。 Primitive Type : 基本型/データの情報が入っている Reference Type : クラス型/オブジェクト実体の場所情報入っている Primitive Type (基本型) Primitive Typeのデータは変数に割り当てられる時、メモリ上に固定された大きさで保存され、当該変数が原始データの値を保管する。 Primitive Typeのデータ型はすべて変数宣言、初期化、割り当て時に値が保存されたメモリ領域に直接的にアクセスする。 すなわち、変数に新しい値が割り当てられる場合、変数に割り当てられたメモリブロックに保存された値をすぐに変更する。 Primitive Typeの種類 Boolean number String undefined BigInt シンボル Primitive Typeの変数の複製 各変数の間でPrimitive Typeのデータをコピーする場合、データの値がコピーされる。 var x = 100; var y = x; x = 99; console.log(y); // 100; データの値をコピーするためconsoleを使う前にxを99に変わったが、以前の値である100をコピーしておいたので100が出力されることがわかる。 Reference Type (クラス型) Reference Typeのデータは、大きさが決まっておらず、変数に割り当てることになると、値が直接当該変数に保存されることはできず、変数にはデータに対する住所が保存されている。変数の値が保存されたヒープメモリの住所を保存する。Reference Typeは変数の値が保存されたメモリブロックの住所を持っていてjavascriptエンジンが変数が持っているメモリアドレスを利用して変数の値に接近する。 Referece Typeの種類 Object ( array, function, object ) Reference Typeの変数の複製 各変数の間でReferece Typeのデータをコピーする場合、データの住所がコピーされる。 var x = { count : 100 }; var y = x; x.count = 99; console.log(y); // 99 変数xとyは同じ住所の値を持っている。したがって、同一のオブジェクトを指すことになる。 Primitive Type vs Reference Type 例 1 var list1 = [1, 2, 3]; // メモリ住所 : 8765e と仮定する var list2 = [1, 2, 3]; // メモリ住所 : 9524d と仮定する var isSame = list1 === list2; // 8765e === 9524d console.log(isSame); // false list1、list2の中の要素は同じだが、配列を新しく作り変えて変数に埋めているため、それぞれ新しいメモリ住所を作って保存し、その住所を参照して変数に該当する住所の値を保存するのと同じである。 したがって、結果はfalseとなる。 例 2 var list3 = [ 1, 2, 3]; var list4 = list3; var isSame = list3 === list4; console.log(isSame); // true 上の例題とは異なり、新しく配列を生成せずにlist3の位置値をそのままlist4に入れるのであるから、メモリ住所が同じ場合と言える。 したがって結果はtrueとなる。 例 3 var updateAge = function () { this.age++; }; // 'メモリ住所 : 4737d' と仮定する var son = { age : 3, growUp : updateAge }; var daugther = { age : 7, growUp : updateAge }; var mother = { age : 38, growUp : updateAge, children : [ son, daugther ] }; var father = { age : 38, growUp : updateAge, wife : mother, children : [ son, daugther ] }; // ### 例 3.1 if (father.growUp === son.growUp) { // 4737d === 4737d console.log('成長可能'); } // output : 成長可能 // ### 例 3.2 if (father.children === mother.children) { console.log('夫婦!'); } // falseなので、console.logが実行されない 例3.1の場合、updateAgeという変数のデータ値に関数の住所の値を保存した。仮想メモリアドレスが4737dという仮定の下にobjectは、当該データの住所の値を保存するため、father.growUpとson.growUpの値は同じ値になる。 したがって、結果はtrueにconsoleに'成長可能'が出力される。 例3.2の場合、同じ変数が埋められているが、オブジェクト内で配列を新たに作ってmother.childrenとfather.childrenは異なる住所の値を新たに割り当てられたため、住所の値が異なる。 したがって、結果はfalseにconsoleに何も出力されない。 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【React.js】ToDoリストを作ってみた

背景 実務でReactも使っているようで、入社前のキャッチアップとしてToDoリストを作成します。 まずは基本的な部分の理解を深めたかったのでJavaScript+Reactで作っていこうと思います。 完成イメージ 今回はあくまでReactの学習に重きをおいているのでHTML/CSSは省きました。 機能としては4つ、それぞれ以下のように動きを区分しました。 1. タスク追加機能 フォームに文字列を入力 追加ボタンをクリックするとタスク追加、追加後はフォームの値を""にする 追加すると、ID、コメント(=タスク名)、状態ボタン、削除ボタンを表示 IDは0から始まる連番 入力後の状態は作業中 2. タスク削除機能 削除ボタンを押すと同じ行のタスクを削除 削除後はID更新 3. タスクの状態変更 "作業中"のときにクリックすると"完了"に更新 "完了"のときにクリックすると"作業中"に更新 4. タスクフィルター機能 ラジオボタン 上のラジオボタンの選択状況を判定 フィルターに応じて表示分け 例: 作業中のラジオボタンが選択されているときは状態が"作業中"のタスクのみ表示 0. 前提 ディレクトリ構造 ディレクトリ構造は以下の通り、最低限のものになりました。 - node_modules - src |- App.jsx |- index.js -package-lock.json -package-json 今回いじるのはApp.jsxのみです! その他のディレクトリについては学習中です、、、 JSXについて jsxというJacaScriptの拡張を使ってReactの要素を生成できるので、React Docsの通りjsxを使って書いていきたいと思います。 JSXの特徴は以下の通り - JavaScriptにHTMLを書ける - マークアップとロジックを両方含むコンポーネントという単位で管理するため - エラーや警告をより多く表示可能 - Reactにとって必須というわけではない(現状、使っている人が多いらしい) プロジェクトの立ち上げ プロジェクトの立ち上げ方は以下を参考にしてください。 React Docs -Create React App プロジェクト立ち上げ npx create-react-app アプリ名 cd アプリ名 ブラウザ表示 npm start index.js import React from "react"; import ReactDOM from "react-dom"; import { App } from "./App"; ReactDOM.render(<App />, document.getElementById("root")); 最後の行の<App />はApp.jsxのことです。 ReactDOM.render(element, document.getElementById("root));とすることでelement(コンポーネント)をレンダーすることができます。 1. タスク追加機能 App.jsx import React, { useState } from "react"; export const App = () => { const [todoText, setTodoText] = useState(""); *1 const [todoList, setNewTodoList] = React.useState([]); // インプットフォームの状態を管理 const onChangeTodoText = (event) => { setTodoText(event.target.value); }; // 追加ボタンを押すとタスクがToDoリストに追加される const onClickAdd = () => { if (todoText === "") return; const newTodo = { comment: todoText, status: "作業中" } // DOMが更新される todoList.push(newTodo); // 入力フォーム内を""にする setTodoText(""); }; return ( <> *2 <div className="task-area"> <h1>ToDoリスト</h1> <table> <thead> <tr> <td >ID</td> <td>コメント</td> <td>状態</td> </tr> </thead> <tbody id="todo-body"> {todoList.map((todo, index) => ( <tr> <td>{index}</td> <td>{todo.comment}</td> <td><button>{todo.status}</button></td> <td><button>削除</button></td> </tr> ))} </tbody> </table> </div> <h2>新規タスクの追加</h2> <div className="add-todo"> <input value={todoText} onChange={onChangeTodoText} /> <button onClick={onClickAdd}>追加</button> </div> </> ); } *1 stateとは現在の状態をあらわすもの。todoTextは現在の状態で、setTodoTextは更新する関数のこと。useState(初期値)`で初期値を設定している。 *2 returnのあとの<></>は、<React.Fragment></React.Fragment>の省略形です。 JSXでは一番上のノードを一つのタグで囲う必要がありますが、余計にタグを使うのも良くないためこのタグが必要です。 2. タスク削除機能 export const App = () => { // todoリスト const [todoText, setTodoText] = useState(""); const [todoList, setNewTodoList] = React.useState([]); // (略) // 削除 const onClickDelete = (index) => { const deletedTodoList = [...todoList]; deletedTodoList.splice(index, 1); setNewTodoList(deletedTodoList); }; return ( <> // (略) <h1>ToDoリスト</h1> <table> <thead> <tr> <td >ID</td> <td>コメント</td> <td>状態</td> </tr> </thead> <tbody id="todo-body">   {todoList.map((todo, index) => (  <tr> <td>{index}</td> <td>{todo.comment}</td> <td><button>{todo.status}</button></td> <td><button onClick={() => onClickDelete(index)}>削除</button></td> // 関数を追加  </tr>   ))} </tbody> </table> </div> // (略) </> ); } splice(n, c) 配列の要素を削除する 引数nは何番目の要素か 引数cはnから数えて何個か onClick={() => 関数(引数)} onClick={関数(引数)}だとレンダリング後すぐに関数が走ってしまうため、この形で回避 ...配列名(スプレット構文) まずは現在のToDoリストを...todoListというスプレット構文で変数に入れます。 削除機能とタスク状態の変更機能はこの配列を更新していく形で実装しています。 3. タスクの状態変更機能 タスクのステータスが"作業中"のときは"完了"に切り替え、 "完了"のときは"作業中"に切り替えるようにしたい。 export const App = () => { // (略) // statusの切り替え const onClickSwitch = (index) => { const switchTodoList = [...todoList]; if (switchTodoList[index].status === "作業中") { switchTodoList[index].status = "完了"; } else if (switchTodoList[index].status === "完了") { switchTodoList[index].status = "作業中"; } setNewTodoList(switchTodoList); }; return ( <> // (略) <h1>ToDoリスト</h1> <table> <thead> <tr> <td >ID</td> <td>コメント</td> <td>状態</td> </tr> </thead> <tbody id="todo-body"> {todoList.map((todo, index) => ( <tr> <td>{index}</td> <td>{todo.comment}</td> <td><button onClick={() => onClickSwitch(index)}>{todo.status}</button></td> <td><button onClick={() => onClickDelete(index)}>削除</button></td> </tr> ))} </tbody> </table> // (略) </> ); } 削除機能と同じように現在の配列をスプレッド構文を使って新たな変数に格納します。 この配列の中にある'status'という要素の状態によって、"作業中"↔"完了"を切り替えるように実装 タスクフィルター機能 export const App = () => { // todoリスト const [todoText, setTodoText] = useState(""); const [todoList, setNewTodoList] = React.useState([]); const [filteredTodoList, setFilteredTodoList] = React.useState([]); const [radio, setRadio] = React.useState('all'); // ラジオボタン更新 const handleChange = (event) => { setRadio(event.target.value); if (event.target.value === "incomplete") { const incompleteTodoList = [...todoList].filter((todo) => todo.status === "作業中"); setFilteredTodoList(incompleteTodoList); } else if (event.target.value === "complete") { const completeTodoList = [...todoList].filter((todo) => todo.status === "完了"); setFilteredTodoList(completeTodoList); } return } // (略) return ( <> <div className="complete-area"> <label> <input type="radio" value="all" onChange={handleChange} checked={radio === 'all'} /> すべて </label> <label> <input type="radio" value="incomplete" onChange={handleChange} checked={radio === 'incomplete'} /> 作業中 </label> <label> <input type="radio" value="complete" onChange={handleChange} checked={radio === 'complete'} /> 完了 </label> <h1>ToDoリスト</h1> <table> <thead> <tr> <td >ID</td> <td>コメント</td> <td>状態</td> </tr> </thead> { radio === "all"? <tbody id="todo-body"> {todoList.map((todo, index) => ( <tr> <td>{index}</td> <td>{todo.comment}</td> <td><button onClick={() => onClickSwitch(index)}>{todo.status}</button></td> <td><button onClick={() => onClickDelete(index)}>削除</button></td> </tr> ))} </tbody> : <tbody id="todo-body"> {filteredTodoList.map((todo, index) => ( <tr> <td>{index}</td> <td>{todo.comment}</td> <td><button onClick={() => onClickSwitch(index)}>{todo.status}</button></td> <td><button onClick={() => onClickDelete(index)}>削除</button></td> </tr> ))} </tbody> } </table> </div> // (略) </> ); } これが一番苦労しました。 大きく分けて以下の3つの機能を実装することにしました。 ラジオボタン handleChange関数でconst [radio, setRadio] = React.useState('all');で初期値を選択し、これでラジオボタンのstateを管理 setRadio(event.target.value);でstateを更新し、クリックされた箇所がチェックされるようにreturn側にもcheckedのプロパティを設定 上のラジオボタンの選択状況を判定 同じくhandleChange関数にラジオボタンの選択状況を判定できるよう、 if (event.target.value === "incomplete")等を書きました。 フィルターに応じて表示分け フィルターされた配列をconst [filteredTodoList, setFilteredTodoList] = React.useState([]);で管理 handleChange関数内でラジオボタンに応じてtodoListの要素が持つstatusでフィルターしました。 最後にradio === "all"? A : B;で表示分け。 完成コード import React, { useState } from "react"; import "./style.css"; export const App = () => { // todoリスト const [todoText, setTodoText] = useState(""); const [todoList, setNewTodoList] = React.useState([]); const [filteredTodoList, setFilteredTodoList] = React.useState([]); const [radio, setRadio] = React.useState('all'); // ラジオボタン更新 const handleChange = (event) => { setRadio(event.target.value); if (event.target.value === "incomplete") { const incompleteTodoList = [...todoList].filter((todo) => todo.status === "作業中"); setFilteredTodoList(incompleteTodoList); } else if (event.target.value === "complete") { const completeTodoList = [...todoList].filter((todo) => todo.status === "完了"); setFilteredTodoList(completeTodoList); } return } // インプットフォームの状態を管理 const onChangeTodoText = (event) => { setTodoText(event.target.value); }; // 追加ボタンを押すとタスクがToDoリストに追加される const onClickAdd = () => { if (todoText === "") return; const newTodo = { comment: todoText, status: "作業中" } // DOMが更新される todoList.push(newTodo); // 入力フォーム内を""にする setTodoText(""); }; // 削除 const onClickDelete = (index) => { const deletedTodoList = [...todoList]; deletedTodoList.splice(index, 1); setNewTodoList(deletedTodoList); }; // statusの切り替え const onClickSwitch = (index) => { const switchTodoList = [...todoList]; if (switchTodoList[index].status === "作業中") { switchTodoList[index].status = "完了"; } else if (switchTodoList[index].status === "完了") { switchTodoList[index].status = "作業中"; } setNewTodoList(switchTodoList); }; return ( <> <div className="complete-area"> <label> <input type="radio" value="all" onChange={handleChange} checked={radio === 'all'} /> すべて </label> <label> <input type="radio" value="incomplete" onChange={handleChange} checked={radio === 'incomplete'} /> 作業中 </label> <label> <input type="radio" value="complete" onChange={handleChange} checked={radio === 'complete'} /> 完了 </label> <h1>ToDoリスト</h1> <table> <thead> <tr> <td >ID</td> <td>コメント</td> <td>状態</td> </tr> </thead> { radio === "all"? <tbody id="todo-body"> {todoList.map((todo, index) => ( <tr> <td>{index}</td> <td>{todo.comment}</td> <td><button onClick={() => onClickSwitch(index)}>{todo.status}</button></td> <td><button onClick={() => onClickDelete(index)}>削除</button></td> </tr> ))} </tbody> : <tbody id="todo-body"> {filteredTodoList.map((todo, index) => ( <tr> <td>{index}</td> <td>{todo.comment}</td> <td><button onClick={() => onClickSwitch(index)}>{todo.status}</button></td> <td><button onClick={() => onClickDelete(index)}>削除</button></td> </tr> ))} </tbody> } </table> </div> <h2>新規タスクの追加</h2> <div className="add-todo"> <input value={todoText} onChange={onChangeTodoText} /> <button onClick={onClickAdd}>追加</button> </div> </> ); } さいごに JavaScriptだとgetElementByIdなどでターゲット要素を指定する必要がありますが、Reactだとevent.target.valueだけでターゲット要素を取得でき、生のJavaScriptで書くよりも圧倒的に簡単に書くことができました。 まだまだコンポーネント化などもできておらず改善点がたくさんありますが、実務でも使いこなせるよう継続して触ってみたいと思います。 参考 React Docs(公式)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【React】ToDoリストを作ってみた

背景 実務でReactも使っているようで、入社前のキャッチアップとしてToDoリストを作成します。 まずは基本的な部分の理解を深めたかったのでJavaScript+Reactで作っていこうと思います。 完成イメージ 今回はあくまでReactの学習に重きをおいているのでHTML/CSSは省きました。 機能としては4つ、それぞれ以下のように動きを区分しました。 1. タスク追加機能 フォームに文字列を入力 追加ボタンをクリックするとタスク追加、追加後はフォームの値を""にする 追加すると、ID、コメント(=タスク名)、状態ボタン、削除ボタンを表示 IDは0から始まる連番 入力後の状態は作業中 2. タスク削除機能 削除ボタンを押すと同じ行のタスクを削除 削除後はID更新 3. タスクの状態変更 "作業中"のときにクリックすると"完了"に更新 "完了"のときにクリックすると"作業中"に更新 4. タスクフィルター機能 ラジオボタン 上のラジオボタンの選択状況を判定 フィルターに応じて表示分け 例: 作業中のラジオボタンが選択されているときは状態が"作業中"のタスクのみ表示 0. 前提 ディレクトリ構造 ディレクトリ構造は以下の通り、最低限のものになりました。 - node_modules - src |- App.jsx |- index.js -package-lock.json -package-json 今回いじるのはApp.jsxのみです! その他のディレクトリについては学習中です、、、 JSXについて jsxというJacaScriptの拡張を使ってReactの要素を生成できるので、React Docsの通りjsxを使って書いていきたいと思います。 JSXの特徴は以下の通り - JavaScriptにHTMLを書ける - マークアップとロジックを両方含むコンポーネントという単位で管理するため - エラーや警告をより多く表示可能 - Reactにとって必須というわけではない(現状、使っている人が多いらしい) プロジェクトの立ち上げ プロジェクトの立ち上げ方は以下を参考にしてください。 React Docs -Create React App プロジェクト立ち上げ npx create-react-app アプリ名 cd アプリ名 ブラウザ表示 npm start index.js import React from "react"; import ReactDOM from "react-dom"; import { App } from "./App"; ReactDOM.render(<App />, document.getElementById("root")); 最後の行の<App />はApp.jsxのことです。 ReactDOM.render(element, document.getElementById("root));とすることでelement(コンポーネント)をレンダーすることができます。 1. タスク追加機能 App.jsx import React, { useState } from "react"; export const App = () => { const [todoText, setTodoText] = useState(""); *1 const [todoList, setNewTodoList] = React.useState([]); // インプットフォームの状態を管理 const onChangeTodoText = (event) => { setTodoText(event.target.value); }; // 追加ボタンを押すとタスクがToDoリストに追加される const onClickAdd = () => { if (todoText === "") return; const newTodo = { comment: todoText, status: "作業中" } // DOMが更新される todoList.push(newTodo); // 入力フォーム内を""にする setTodoText(""); }; return ( <> *2 <div className="task-area"> <h1>ToDoリスト</h1> <table> <thead> <tr> <td >ID</td> <td>コメント</td> <td>状態</td> </tr> </thead> <tbody id="todo-body"> {todoList.map((todo, index) => ( <tr> <td>{index}</td> <td>{todo.comment}</td> <td><button>{todo.status}</button></td> <td><button>削除</button></td> </tr> ))} </tbody> </table> </div> <h2>新規タスクの追加</h2> <div className="add-todo"> <input value={todoText} onChange={onChangeTodoText} /> <button onClick={onClickAdd}>追加</button> </div> </> ); } *1 stateとは現在の状態をあらわすもの。todoTextは現在の状態で、setTodoTextは更新する関数のこと。useState(初期値)`で初期値を設定している。 *2 returnのあとの<></>は、<React.Fragment></React.Fragment>の省略形です。 JSXでは一番上のノードを一つのタグで囲う必要がありますが、余計にタグを使うのも良くないためこのタグが必要です。 2. タスク削除機能 export const App = () => { // todoリスト const [todoText, setTodoText] = useState(""); const [todoList, setNewTodoList] = React.useState([]); // (略) // 削除 const onClickDelete = (index) => { const deletedTodoList = [...todoList]; deletedTodoList.splice(index, 1); setNewTodoList(deletedTodoList); }; return ( <> // (略) <h1>ToDoリスト</h1> <table> <thead> <tr> <td >ID</td> <td>コメント</td> <td>状態</td> </tr> </thead> <tbody id="todo-body">   {todoList.map((todo, index) => (  <tr> <td>{index}</td> <td>{todo.comment}</td> <td><button>{todo.status}</button></td> <td><button onClick={() => onClickDelete(index)}>削除</button></td> // 関数を追加  </tr>   ))} </tbody> </table> </div> // (略) </> ); } splice(n, c) 配列の要素を削除する 引数nは何番目の要素か 引数cはnから数えて何個か onClick={() => 関数(引数)} onClick={関数(引数)}だとレンダリング後すぐに関数が走ってしまうため、この形で回避 ...配列名(スプレット構文) まずは現在のToDoリストを...todoListというスプレット構文で変数に入れます。 削除機能とタスク状態の変更機能はこの配列を更新していく形で実装しています。 3. タスクの状態変更機能 タスクのステータスが"作業中"のときは"完了"に切り替え、 "完了"のときは"作業中"に切り替えるようにしたい。 export const App = () => { // (略) // statusの切り替え const onClickSwitch = (index) => { const switchTodoList = [...todoList]; if (switchTodoList[index].status === "作業中") { switchTodoList[index].status = "完了"; } else if (switchTodoList[index].status === "完了") { switchTodoList[index].status = "作業中"; } setNewTodoList(switchTodoList); }; return ( <> // (略) <h1>ToDoリスト</h1> <table> <thead> <tr> <td >ID</td> <td>コメント</td> <td>状態</td> </tr> </thead> <tbody id="todo-body"> {todoList.map((todo, index) => ( <tr> <td>{index}</td> <td>{todo.comment}</td> <td><button onClick={() => onClickSwitch(index)}>{todo.status}</button></td> <td><button onClick={() => onClickDelete(index)}>削除</button></td> </tr> ))} </tbody> </table> // (略) </> ); } 削除機能と同じように現在の配列をスプレッド構文を使って新たな変数に格納します。 この配列の中にある'status'という要素の状態によって、"作業中"↔"完了"を切り替えるように実装 タスクフィルター機能 export const App = () => { // todoリスト const [todoText, setTodoText] = useState(""); const [todoList, setNewTodoList] = React.useState([]); const [filteredTodoList, setFilteredTodoList] = React.useState([]); const [radio, setRadio] = React.useState('all'); // ラジオボタン更新 const handleChange = (event) => { setRadio(event.target.value); if (event.target.value === "incomplete") { const incompleteTodoList = [...todoList].filter((todo) => todo.status === "作業中"); setFilteredTodoList(incompleteTodoList); } else if (event.target.value === "complete") { const completeTodoList = [...todoList].filter((todo) => todo.status === "完了"); setFilteredTodoList(completeTodoList); } return } // (略) return ( <> <div className="complete-area"> <label> <input type="radio" value="all" onChange={handleChange} checked={radio === 'all'} /> すべて </label> <label> <input type="radio" value="incomplete" onChange={handleChange} checked={radio === 'incomplete'} /> 作業中 </label> <label> <input type="radio" value="complete" onChange={handleChange} checked={radio === 'complete'} /> 完了 </label> <h1>ToDoリスト</h1> <table> <thead> <tr> <td >ID</td> <td>コメント</td> <td>状態</td> </tr> </thead> { radio === "all"? <tbody id="todo-body"> {todoList.map((todo, index) => ( <tr> <td>{index}</td> <td>{todo.comment}</td> <td><button onClick={() => onClickSwitch(index)}>{todo.status}</button></td> <td><button onClick={() => onClickDelete(index)}>削除</button></td> </tr> ))} </tbody> : <tbody id="todo-body"> {filteredTodoList.map((todo, index) => ( <tr> <td>{index}</td> <td>{todo.comment}</td> <td><button onClick={() => onClickSwitch(index)}>{todo.status}</button></td> <td><button onClick={() => onClickDelete(index)}>削除</button></td> </tr> ))} </tbody> } </table> </div> // (略) </> ); } これが一番苦労しました。 大きく分けて以下の3つの機能を実装することにしました。 ラジオボタン handleChange関数でconst [radio, setRadio] = React.useState('all');で初期値を選択し、これでラジオボタンのstateを管理 setRadio(event.target.value);でstateを更新し、クリックされた箇所がチェックされるようにreturn側にもcheckedのプロパティを設定 上のラジオボタンの選択状況を判定 同じくhandleChange関数にラジオボタンの選択状況を判定できるよう、 if (event.target.value === "incomplete")等を書きました。 フィルターに応じて表示分け フィルターされた配列をconst [filteredTodoList, setFilteredTodoList] = React.useState([]);で管理 handleChange関数内でラジオボタンに応じてtodoListの要素が持つstatusでフィルターしました。 最後にradio === "all"? A : B;で表示分け。 完成コード import React, { useState } from "react"; import "./style.css"; export const App = () => { // todoリスト const [todoText, setTodoText] = useState(""); const [todoList, setNewTodoList] = React.useState([]); const [filteredTodoList, setFilteredTodoList] = React.useState([]); const [radio, setRadio] = React.useState('all'); // ラジオボタン更新 const handleChange = (event) => { setRadio(event.target.value); if (event.target.value === "incomplete") { const incompleteTodoList = [...todoList].filter((todo) => todo.status === "作業中"); setFilteredTodoList(incompleteTodoList); } else if (event.target.value === "complete") { const completeTodoList = [...todoList].filter((todo) => todo.status === "完了"); setFilteredTodoList(completeTodoList); } return } // インプットフォームの状態を管理 const onChangeTodoText = (event) => { setTodoText(event.target.value); }; // 追加ボタンを押すとタスクがToDoリストに追加される const onClickAdd = () => { if (todoText === "") return; const newTodo = { comment: todoText, status: "作業中" } // DOMが更新される todoList.push(newTodo); // 入力フォーム内を""にする setTodoText(""); }; // 削除 const onClickDelete = (index) => { const deletedTodoList = [...todoList]; deletedTodoList.splice(index, 1); setNewTodoList(deletedTodoList); }; // statusの切り替え const onClickSwitch = (index) => { const switchTodoList = [...todoList]; if (switchTodoList[index].status === "作業中") { switchTodoList[index].status = "完了"; } else if (switchTodoList[index].status === "完了") { switchTodoList[index].status = "作業中"; } setNewTodoList(switchTodoList); }; return ( <> <div className="complete-area"> <label> <input type="radio" value="all" onChange={handleChange} checked={radio === 'all'} /> すべて </label> <label> <input type="radio" value="incomplete" onChange={handleChange} checked={radio === 'incomplete'} /> 作業中 </label> <label> <input type="radio" value="complete" onChange={handleChange} checked={radio === 'complete'} /> 完了 </label> <h1>ToDoリスト</h1> <table> <thead> <tr> <td >ID</td> <td>コメント</td> <td>状態</td> </tr> </thead> { radio === "all"? <tbody id="todo-body"> {todoList.map((todo, index) => ( <tr> <td>{index}</td> <td>{todo.comment}</td> <td><button onClick={() => onClickSwitch(index)}>{todo.status}</button></td> <td><button onClick={() => onClickDelete(index)}>削除</button></td> </tr> ))} </tbody> : <tbody id="todo-body"> {filteredTodoList.map((todo, index) => ( <tr> <td>{index}</td> <td>{todo.comment}</td> <td><button onClick={() => onClickSwitch(index)}>{todo.status}</button></td> <td><button onClick={() => onClickDelete(index)}>削除</button></td> </tr> ))} </tbody> } </table> </div> <h2>新規タスクの追加</h2> <div className="add-todo"> <input value={todoText} onChange={onChangeTodoText} /> <button onClick={onClickAdd}>追加</button> </div> </> ); } さいごに JavaScriptだとgetElementByIdなどでターゲット要素を指定する必要がありますが、Reactだとevent.target.valueだけでターゲット要素を取得でき、生のJavaScriptで書くよりも圧倒的に簡単に書くことができました。 まだまだコンポーネント化などもできておらず改善点がたくさんありますが、実務でも使いこなせるよう継続して触ってみたいと思います。 参考 React Docs(公式)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【VS Code】JavaScriptのconsole.logをコンソール画面に出力する方法

本記事では、JSのconsole.logを、VS Codeのコンソール画面に出力する方法を紹介します。 環境情報 OS:Windows 10 VS Codeのバージョン:1.63.2 手順 以下の手順を行うことで、コンソール画面にconsole.logの内容を出力できます。 ①Live Preview拡張機能インストール ②Live Previewの設定変更 ①Live Previewインストール Live Preview拡張機能をインストールします。 以下記事の「インストール」セクションに、インストール方法が記載されているので、そちらを参照ください。 https://creating-homepage.com/archives/8616#sec2 ②Live Previewの設定変更 Live Previewのインストールが完了した後、Live Previewの設定をいくつか変更します。 ・変更する設定   Auto Refresh Preview   Debug On External Preview   Open Preview Target Ctrl + 「,」キーでVS Codeの設定画面を開き、拡張機能 → Live Previewを開きます。 こちらの画面で、↑に挙げたLive Preview3項目の設定を変更します。 ・Auto Refresh Preview Auto Refresh Preview を「Never」に設定します。 ※Auto Refresh Previewとは  プレビューを自動的に更新する頻度を設定する項目  Neverに設定すると、ブラウザーの自動更新を無効にする(更新ボタンを押さない限り、ブラウザが更新されない) ・Debug On External Preview Debug On External Previewにチェックを入れます。 ※Debug On External Previewとは  外部プレビュー起動時にJavaScripitデバッガーを有効化 ・Open Preview Target Open Preview Targetを External Browserに設定します。 ※Open Preview Targetとは  プレビューを、埋め込みプレビューor外部プレビューにするかを設定  外部プレビューに設定するので、External Browserを選択します 検証 VS Codeのコンソール画面にconsole.logが出力されるか検証します。 使用するhtml、js 検証で使用するhtmlとjsファイルは以下です。 htmlファイルからjsファイルを呼び出します。 index.html <!DOCTYPE html> <html> <head> <title>Console Test</title> <meta charset="UTF-8" /> </head> <body> <script src="consoletest.js"> </script> <p>コンソール出力テスト</p> </body> </html> consoletest.js console.log('コンソールに出力されるか確認'); 使用するhtmlファイルをVS Codeに表示します。 htmlファイルを表示したら、画面右のボタン(下図赤枠)をクリックします。 すると、ブラウザが起動し、ブラウザ画面にhtmlファイルが表示されます。 このとき、VS Codeのデバッグコンソール画面に、jsファイルに記載したconsole.logの内容が出力されます。 参考記事 Live Previewインストール:https://creating-homepage.com/archives/8616#sec2 Live Previewでconsole.logをVS Codeのコンソールに出力:https://creating-homepage.com/archives/9003
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【実装編】Vue.jsで再利用可能なコンポーネントを実装する方法

props編 slot編 実装編?今ここ はじめに どうすれば再利用可能なコンポーネントを実装することができるのか? 「props」と「slot」を使って実装してみます。 バージョン Vue.js 2.6.11 実装 アコーディオンを用意しました。 必要に応じてタイトル右横に「update」「new」バッジが付与できます。 App.vueでAccordion.vueをimport Accordionタグの中に名前付きslotを使用してコンテンツをコンポーネントに追加する propstype, required, default, validatorをそれぞれ指定 propsの種類としては typeA -> 何もなし typeB -> update typeC -> new App.vue <template> <div id="app"> <img alt="Vue logo" src="./assets/logo.png" width="25%" /> <div> <p>アコーディオン</p> <Accordion variant="typeA"> <template v-slot:title>1.コンテンツについて</template> <template v-slot:content> Lorem ipsum dolor sit amet consectetur adipisicing elit. Sunt quaerat consequatur ipsum quia a quod sed cum quae maxime reprehenderit, porro sequi exercitationem voluptate saepe minus in ullam. Beatae, itaque! </template> </Accordion> <Accordion variant="typeB"> <template v-slot:title>2.不具合について</template> <template v-slot:content> Lorem ipsum dolor sit amet consectetur adipisicing elit. Sunt quaerat consequatur ipsum quia a quod sed cum quae maxime reprehenderit, porro sequi exercitationem voluptate saepe minus in ullam. Beatae, itaque! <br /> <br /> Lorem ipsum dolor sit amet consectetur adipisicing elit. Sunt quaerat consequatur ipsum quia a quod sed cum quae maxime reprehenderit, porro sequi exercitationem voluptate saepe minus in ullam. Beatae, itaque! </template> </Accordion> <Accordion variant="typeC"> <template v-slot:title>3.新コンテンツのお知らせ</template> <template v-slot:content> Lorem ipsum, dolor sit amet consectetur adipisicing elit. Facilis magnam ullam repudiandae, dolorem dignissimos debitis at possimus! Reprehenderit enim illum asperiores, nihil labore veniam vitae, aperiam id a rem consequatur. <a href="#">more</a> </template> </Accordion> <Accordion> <template v-slot:title> 4.その他</template> <template v-slot:content> 準備中... </template> </Accordion> </div> </div> </template> <script> import Accordion from "./components/Accordion"; export default { name: "App", components: { Accordion, }, }; </script> components/Accordion.vue <template> <div class="accordion" :class="[ { 'accordion--A': variant === 'typeA' }, { 'accordion--B': variant === 'typeB' }, { 'accordion--C': variant === 'typeC' }, ]" > <button class="accordion__button" @click="toggleAccordion()" :class="{ 'is-active': isOpen }" > <slot name="title" /> </button> <div class="accordion__content" v-show="isOpen"> <slot name="content" /> </div> </div> </template> <script> export default { name: "", props: { variant: { type: String, required: false, default: "typeA", validator: (value) => ["typeA", "typeB", "typeC"].includes(value), }, }, data() { return { isOpen: false, }; }, methods: { toggleAccordion() { this.isOpen = !this.isOpen; }, }, }; </script> 最後に 参考にどうぞ!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MIDIキーボード

仕様とか解説読んでいくと右脳と左脳がぐちゃぐちゃになるw これならわかりやすかと javascript //https://jumbleat.com/2016/11/26/midi_send_by_arduino/ //https://www.inspiredacoustics.com/en/MIDI_note_numbers_and_center_frequencies $(e=>{ new MidiKeyboard({ NoteC3 : e=>console.log('ド'), NoteCS3 : e=>console.log('ド#'), NoteD3 : e=>console.log('レ'), NoteE3 : e=>console.log('ミ'), NoteF3 : e=>console.log('ファ'), NoteG3 : e=>console.log('ソ'), NoteA3 : e=>console.log('ラ'), NoteB3 : e=>console.log('シ'), NoteC4 : e=>console.log('いっこ上のド'), }) }) class MidiKeyboard{ constructor(hook){ this.hook = hook||{} this.noteOn = 0x90//keydown this.noteOff = 0x80//keyup this.notes = 'C,CS,D,DS,E,F,FS,G,GS,A,AS,B'.split(',') navigator.requestMIDIAccess().then(r=>{ if(r.inputs.size>0){ r.inputs.forEach(v=>{ v.onmidimessage = e=>{ if(e.data[0] & 0x80) this.message(e) } }) }else console.log(r) },s=>console.log) } message(e){ switch(e.data[0]){ case this.noteOn: var s = this.getNote(e.data[1])//noteNumber if(this.hook[s]) this.hook[s]() break case this.noteOff:break default:console.log() } } getNote(i){ var octave = Math.floor(i/12)-1 return 'Note'+this.notes[i%12]+octave } }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MIDIキーボード.js

仕様とか解説読んでいくと右脳と左脳がぐちゃぐちゃになるw これならわかりやすかと javascript //https://jumbleat.com/2016/11/26/midi_send_by_arduino/ //https://www.inspiredacoustics.com/en/MIDI_note_numbers_and_center_frequencies $(e=>{ new MidiKeyboard({ NoteC3 : e=>console.log('ド'), NoteD3 : e=>console.log('レ'), NoteE3 : e=>console.log('ミ'), NoteF3 : e=>console.log('ファ'), NoteG3 : e=>console.log('ソ'), NoteA3 : e=>console.log('ラ'), NoteB3 : e=>console.log('シ'), NoteC4 : e=>console.log('いっこ上のド'), NoteCS3 : e=>console.log('ド#'), }) }) class MidiKeyboard{ constructor(hook){ this.hook = hook||{} this.noteOn = 0x90//keydown this.noteOff = 0x80//keyup this.notes = 'C,CS,D,DS,E,F,FS,G,GS,A,AS,B'.split(',') navigator.requestMIDIAccess().then(r=>{ if(r.inputs.size>0){ r.inputs.forEach(v=>{ v.onmidimessage = e=>{ if(e.data[0] & 0x80) this.message(e) } }) }else console.log(r) },console.log) } message(e){//data[type,noteNumber,velocity] switch(e.data[0]){ case this.noteOn: var s = this.getNote(e.data[1]) if(this.hook[s]) this.hook[s](e) break case this.noteOff:break default:console.log(e) } } getNote(i){ var octave = Math.floor(i/12)-1 return 'Note'+this.notes[i%12]+octave } }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

今回はおみくじを作ります *1日1回御神籤編

前回は、おみくじ何回も押せる編を、作りました 今回は、1日1回編です *ページを更新すると、また、押せます。ページを閉じてまた開くと、また押せます そこには、ご了承ください <!--背景設定したかったら、()に、入れる--> <body style="background-image: url(.jpg);"> <div class="samplearea"> <div class="omikujibase"> <p class="kRes" id="KujiRes2">??</p> <p class="kCom" id="KujiCom2">***</p> </div> <p class="button"> <input id="lottery-start" onclick="ShowKuji( 'KujiRes2', 'KujiCom2' );" type="button" value="おみくじを引く"/> </p> </div> <script type="text/javascript"> mres = []; mcom = []; // おみくじの結果とコメント集 mres[13] = ' 石墨丘 '; mcom[13] = '人生が、30年伸びる~お父さんたちより、80年長く生きれるよ'; mres[12] = ' 平 '; mcom[12] = '大吉より上だ 好き~~~~~~~なこと、させてくれるで'; mres[0] = '大吉'; mcom[0] = '好きなものをなんぼでも買ってくれるかもしれへんで'; mres[1] = '中吉'; mcom[1] = '人生の中で一番楽しい日になるかも'; mres[2] = '小吉'; mcom[2] = '勉強に進んで出来る様になるかもね!!'; mres[3] = ' 吉 '; mcom[3] = '頑張ったら褒められるかも'; mres[4] = '末吉'; mcom[4] = '頭が、回転しなくて勉強できないかも'; mres[5] = ' 凶 '; mcom[5] = '今日は不幸だ。元気に遊んだら変わるかも'; mres[6] = ' 大凶 '; mcom[6] = '誰もからも、しゃべてくれなくなるかも'; mres[7] = ' 鬼吉 '; mcom[7] = 'すごくひどい病気になって30年、入院生活になるかも'; mres[8] = ' 悪吉 '; mcom[8] = 'ストレスがすごくたまって、友達にいじめをしてしまうかも'; mres[9] = ' 嫌凶 '; mcom[9] = 'いらいらして自殺してしまうかも'; mres[10] = ' 変凶 '; mcom[10] = 'パソコンウイルスに感染して、パソコンを没収されるかも '; mres[11] = ' 死亡凶 '; mcom[11] = '巨大地震が起きて、家が壊れてご飯も食べれなくなって、死ぬかも'; /** * くじ引きロジック * @param kRes * @param kCom * @constructor */ function ShowKuji(kRes, kCom) { // くじを混ぜる const lotteries = Math.floor(Math.random() * mres.length); // くじ引き結果表示 document.getElementById(kRes).innerHTML = mres[lotteries]; document.getElementById(kCom).innerHTML = mcom[lotteries]; // 1回だけ引ける document.getElementById('lottery-start').disabled = true; } </script> </body>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

すごくシンプルなタイピングゲームを作ろう

今回は、タイピングゲーム*くそ を、作ってみましょう <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta name="GENERATOR" content="UTF-8 Writer" /> <title>私が作った、タイピングゲーム</title> <h1>私が作った、タイピングゲーム</h1>       <script> document.onkeydown = typeGame; //キー押下時に関数typeGame()を呼び出す //文字を格納する配列 var moji = new Array("a","b","c","d","e","f","g","h","i", "j","k","l","m","n","o","p","q","r", "s","t","u","v","w","x","y","z"," "," "); //キーコードを格納する配列 var kcode = new Array(65,66,67,68,69,70,71,72,73, 74,75,76,77,78,79,80,81,82, 83,84,85,86,87,88,89,90); //0~25までの乱数を格納する配列 var rnd = new Array(); //グローバル変数群 var mondai = ""; //問題の文字列を格納 var cnt=0; //何問目か格納 var typStart,typEnd; //開始時と終了時の時刻を格納 //0~25までの乱数を200個作成して配列rndに格納する関数 function ransu() { for ( var i = 0 ; i < 200 ; i++ ) { rnd[i] = Math.floor( Math.random() * 26 ); } } //タイピングゲームの問題をセットする関数 function gameSet() { //カウント数をクリアする cnt=0; //まずは問題文を作る ransu(); //問題文をテーブルを使って表示。各セルはID名「word+数字」を付す mondai="<table class='Q'>"; for ( var i = 0 ; i < 10 ; i++ ) { mondai += "<tr>"; for ( var j = 0 ; j < 20 ; j++ ) { var idnum =i*20+j; mondai += "<td id='word"+idnum+"'>"+moji[ rnd[idnum] ]+"</td>"; } mondai += "</tr>"; } mondai += "</table>"; //問題枠に表示する document.getElementById("waku").innerHTML = mondai; } //キー入力を受け取る関数 function typeGame(evt) { var kc; //入力されたキーコードを格納する変数 //入力されたキーのキーコードを取得 if (document.all) { kc = event.keyCode; } else { kc = evt.which; } //入力されたキーコードと、問題文のキーコードを比較 if (kc == kcode[ rnd[cnt] ]) { //以下、キーコードが一致した時の処理 //最初の1文字が入力された時間を記録する if (cnt==0) { typStart = new Date(); } //入力されたセルの文字色を灰色にする var idName = "word"+cnt; document.getElementById(idName).style.color="#dddddd"; cnt++; //カウント数を+1にする //全文字入力したか確認 if ( cnt == 200) { //全文字入力していたら、終了時間を記録する typEnd = new Date(); //終了時間-開始時間で掛かったミリ秒を取得する var keika = typEnd - typStart; //1000で割って「切捨て」、秒数を取得 var sec = Math.floor( keika/1000 ); //1000で割った「余り(%で取得できる)」でミリ秒を取得 var msec = keika % 1000; //問題終了を告げる文字列を作成 var fin=" GAMECLEAR GAMESET 時間:"+sec+"秒"+msec; //問題枠にゲーム終了を表示 document.getElementById("waku").innerHTML = fin; } } } </script> <style type="text/css"> <!-- table.Q td { width:20px; height:20px; font-size:18pt; text-align:center; } --> </style> </head> <body onload="gameSet()" bgcolor="#ffffff" text="#000000" link="#0000ff" alink="#ff0000" vlink="#800080"> <h1></h1> <div id="waku"></div> <form> <input type="button" value="問題初期化" onclick="gameSet()"><br> <input type="button" value="好きなことを入力" onclick="location.href='ここに自分のURLを入力'"><br> </form> </body> </html> <!DOCTYPE html> <html lang="ja"> <head> 上記で、シンプルすぎるタイピングゲームを作ってみました いかがでしょう まだまだ、記事や、質問を、投稿するので、フォローをお願いいたします フォローをしてくれたら、 私も、フォローさせていただきます
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【React】イベントハンドラプロパティ一覧【JavaScript】

はじめに  本記事は、プログラミング初学者が、学習を進めていて疑問に思った点について調べた結果を備忘録も兼ねてまとめたものです。  そのため、記事の内容に誤りが含まれている可能性があります。ご容赦ください。  間違いを見つけた方は、お手数ですが、ご指摘いただけますと幸いです。 イベント属性一覧 Reactで、イベント処理はタグ内にonClickなどのイベントハンドラ用の属性を指定することで定義できます。 Reactでのイベント処理の記述には以下の特徴があります。 イベントは小文字ではなく camelCase で名付けられる イベントハンドラとして文字列ではなく関数を渡す イベント処理を記述する際のイベント属性について以下にまとめます。 // クリック関連 onClick // 要素やリンクをクリックした時に発生 onDblClick // 要素をダブルクリックした時に発生 onMouseDown // マウスでクリックした時に発生 onMouseUp // クリックしたマウスを上げた時に発生 // フォーム関連 onSubmit // フォームを送信しようとした時に発生 onReset // フォームがリセットされた時に発生 onBlur // ページやフォーム要素からフォーカスが外れた時に発生 onFocus // ページやフォーム要素にフォーカスが当たった時に発生 onChange // フォーム要素の選択、入力内容が変更された時に発生 // テキスト関連 onSelect // テキストが選択された時に発生 // キー関連 onKeyUp // 押していたキーをあげた時に発生 onKeyDown // キーを押した時に発生 onKeyPress // キーを押してる時に発生 // 画像読み込み関連 onAbort // 画像の読み込みを中断した時に発生 onError // 画像の読み込み中にエラーが発生した時に発生 onLoad // ページや画像の読み込みが完了した時に発生 // ウィンドウ関連 onUnload // ウィンドウを閉じた時、他のページに切り替えた時、ページをリロード(更新)した時に発生 // マウス関連 onMouseOut // マウスが離れた時に発生 onMouseOver // マウス乗った時に発生 onMouseMove // マウスを動かしている時に発生
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む