- 投稿日:2020-10-26T23:56:15+09:00
Riot.js フォームの扱い
Riotでのフォームの扱い方を紹介します。
DOM要素に直接アクセス
おそらく一番簡単でわかりやすい方法です。フォームがちょっとでも複雑になるとコードがカオスになりがちなので実務ではあまり使いません。
サッと簡単なフォームを作る時にはこれで十分ですね。<app-form> <form onsubmit="{ handleSubmit }"> <input type="email" name="email" placeholder="メールアドレス" /> <input type="password" name="password" placeholder="パスワード" /> <input type="checkbox" id="password_visible" onchange="{ handleCheckChange }"> <label for="password_visible">パスワード表示</l1abel> <button>送信</button> </form> <script> export default { handleCheckChange(e) { this.$('[name=password]').type = e.target.checked ? 'text' : 'password' }, handleSubmit(e) { e.preventDefault() const email = this.$('[name=email]').value const password = this.$('[name=password]').value console.log({ email, password }) } } </script> </app-form>form要素から値を取得
送信するだけのフォームならおすすめです。
DOMを検索しない分上の方法よりパフォーマンスはいいのですが、誤差ですね?<app-form> <form onsubmit="{ handleSubmit }"> <input type="email" name="email" placeholder="メールアドレス" /> <input type="password" name="password" placeholder="パスワード" /> <button>送信</button> </form> <script> export default { handleSubmit(e) { e.preventDefault() const fields = e.target.elements const email = fields['email'].value const password = fields['password'].value console.log({ email, password }) } } </script> </app-form>stateにフォームの値を持つ
冗長だけど凝ったことをするならこれ一択ですね。
自分はフォームを作るとき大体あとから複雑になってくるので、最初から全部この方法で統一しています。<app-form> <form onsubmit="{ handleSubmit }"> <input type="email" name="email" placeholder="メールアドレス" oninput="{ handleEmail }" value="{ state.email }" /> <input type="{ state.passwordType }" name="password" placeholder="パスワード" oninput="{ handlePassword }" value="{ state.password }" /> <input type="checkbox" id="password_visible" onchange="{ handleCheckChange }"> <label for="password_visible">パスワード表示</l1abel> <button>送信</button> </form> <script> export default { state: { email: '', password: '', passwordType: 'password' }, handleEmail(e) { this.state.email = e.target.value this.update() }, handlePassword(e) { this.state.password = e.target.value this.update() }, handleCheckChange(e) { this.state.passwordType = e.target.checked ? 'text' : 'password' this.update() }, handleSubmit(e) { e.preventDefault() console.log(this.state) } } </script> </app-form>さすがにフィールドごとにイベントハンドラー
handle...
を用意するのは冗長すぎるので、普段は一つのハンドラーで工夫しています。- <input type="email" name="email" placeholder="メールアドレス" oninput="{ handleEmail }" value="{ state.email }" /> - <input type="{ state.passwordType }" name="password" placeholder="パスワード" oninput="{ handlePassword }" value="{ state.password }" /> + <input type="email" name="email" placeholder="メールアドレス" oninput="{ handleChange }" value="{ state.email }" /> + <input type="{ state.passwordType }" name="password" placeholder="パスワード" oninput="{ handleChange }" value="{ state.password }" /> ... - handleEmail(e) { - this.state.email = e.target.value - this.update() - }, - handlePassword(e) { - this.state.password = e.target.value - this.update() - }, + handleChange(e) { + this.state[e.target.name] = e.target.value + this.update() + },その他
name属性がないフィールドも扱う
<awesome-color-picker value="" on-change="" />
という感じのname属性のないカスタムなコンポーネントがある時 + なるべくhandleChange
一つにまとめたい<app-form> <form onsubmit="{ handleSubmit }"> <awesome-color-picker on-change="{ color => handleChange('color', color) }" value="{ state.color }" /> <input type="text" oninput="{ e => handleChange('text', e.target.value) }" value="{ state.text }" /> </form> <script> export default { state: { text: '', color: '#ffffff' }, handleChange(name, value) { this.state[name] = value this.update() }, handleSubmit(e) { e.preventDefault() console.log(this.state) } } </script> </app-form>
{ e => handleChange('text', e.target.value) }
← 好みの問題ですがこれが「なんか気持ち悪い...」なら- <awesome-color-picker on-change="{ color => handleChange('color', color) }" value="{ state.color }" /> - <input type="text" oninput="{ e => handleChange('text', e.target.value) }" value="{ state.text }" /> + <awesome-color-picker on-change="{ handleChange('color') }" value="{ state.color }" /> + <input type="text" oninput="{ handleChange('text') }" value="{ state.text }" /> ... - handleChange(name, value) { - this.state[name] = value - this.update() - }, + handleChange(name) { + return e => { + this.state[name] = e.target ? e.target.value : e; + this.update(); + } + },こっちの方がすっきりする気がします。
フォームが複雑になってくるとイベントハンドラ一つでカバーできないときもあるので、無理に一つにまとめずに複数のイベントハンドラを使いましょう。自分は単純なものは上にあったような
handleChange
を使い、それ以外のものは個別にイベントハンドラを作ります。最後に
質問などがあれば気軽にコメントしてください!(^^♪
- 投稿日:2020-10-26T23:25:57+09:00
アニメ情報のWebアプリ開発してみたけど上手くいかず、、(要改善)
出来たもの
「検索」で、指定した年度・クールごとのアニメ番組一覧を表示してくれるWebアプリ。
※実際に動くものはコチラにアップしてます。
利用ライブラリ
・Vue.js
CDN:https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.min.js
・Bootstrap
CDN:https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js
CDN:https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.3/js/bootstrap.min.js
・axios
CDN:https://cdnjs.cloudflare.com/ajax/libs/axios/0.21.0/axios.min.js
・ShangriLa Anime APIやりたかったこと
新アニメが始まった時にとりあえず1話見てみて、減らしていくことが多い。(1話すら見ないこともあるが。)
始まってすぐだと、タイトルだけだと分からないことが多いので、自分用で優先順位を管理できるようなWebアプリを作ってみたかった。
・年度、クールでアニメ番組を取得して取捨選択。
・優先順付けて並び変え。または削除。
みたいなことをやりたかった。出来なかったこと
四苦八苦の様子、参考にしたURLなどは自分用メモとして保管してます。
Webサイトのサムネイル画像を取得して表示したかったが、上手くいかず。。
色々調べて試してみて、最終的にはWebページのOGPイメージ(og:image)を取得すれば良い考えにシフトしたが時間が足りなくイメージ画像の取得が上手くいってません。改善点(今後に期待)
今回時間なくて断念したが、色々改造したい。
・ちゃんとサムネイル画像を表示できるようにしたい。
・ビジュアルをもっとかっこよくしたい。
・番組の曜日、時間、PV再生など追加したい。
・検索結果の保存。
・カードの並び変えや削除。コード
html<!-- 全体をVue.js有効にする --> <div class="container text-center text-white bg-dark" id="app"> <!-- タイトル行 --> <div class="row my-3"> <div class="col-sm-6 mx-auto"><h1>ANIME Watch</h1></div> </div> <!-- 検索フォーム --> <div class="form-inline justify-content-center"> <input v-model:value="Year" placeholder="2020" class="form-control"> <label class="col-sm-1">年</label> <select v-model:value="Cours" class="custom-select"> <option>春</option> <option>夏</option> <option>秋</option> <option>冬</option> </select> <div class="col-sm-2"> <button v-on:click="Search" class="btn btn-primary">検索</button> </div> </div> <!-- 全てのタスクをクリアするボタン --> <div class="row my-3"> <div class="col-sm-6 mx-auto"> <button v-on:click="clearAll" class="btn btn-danger">検索結果のクリア</button> </div> </div> <!-- タスク追加されると表示される部分 --> <div class="flex-container"> <p v-for="Anime in AniData">{{Anime.Title}}<br> <a v-bind:href="Anime.WebUrl" target="_blank"> <img v-bind:src="Anime.ImgUrl" width="250" height="150"></img> </a> </p> </div> </div>jsconst app = new Vue({ el: '#app', // Vueが管理する一番外側のDOM要素 data: { // Vue内部で使いたい変数は全てこの中に定義する Year: '2020', // 年 Cours: '冬', // クール Animes: '', // APIで取得したアニメ情報JSON AniData: [], // 表示するアニメ情報配列 }, methods: { // 関数はココに記述 Search: async function() { // 検索時の関数 try { // クール値を取得 let CoursNo=4; switch (this.Cours){ case '春': CoursNo=1; break; case '夏': CoursNo=2; break; case '秋': CoursNo=3; break; case '冬': CoursNo=4; break; } // ShangriLa Anime API Server let response; response = await axios.get(`https://api.moemoe.tokyo/anime/v1/master/${this.Year}/${CoursNo}`); this.Animes = response.data; // アニメ情報表示用配列作成 this.AniData = []; for (var item in this.Animes) { var data = {Title: this.Animes[item].title, WebUrl: this.Animes[item].public_url, ImgUrl: ""}; this.AniData.push(data); } /* // OGP取得 上手くいかないからあきらめ。 const CORS_PROXY = 'https://cors-anywhere.herokuapp.com/' for await (var item of this.Animes) { await fetch(CORS_PROXY + this.Animes[item].public_url) .then((res) => res.text()) .then((text) => { const el = new DOMParser().parseFromString(text, 'text/html') const headEls = el.head.children Array.from(headEls).map((v) => { //console.log(v) const prop = v.getAttribute('property') if (!prop) return if (prop == "og:image") { //console.log(prop, v.getAttribute('content')) var ogimg = v.getAttribute('content') } }) var data = {Title: this.Animes[item].title, WebUrl: this.Animes[item].public_url, ImgUrl: ogimg}; this.AniData.push(data); }) }*/ } catch (error) { console.error(error); } }, clearAll: function() { // 表示クリア時の関数 this.AniData = []; console.log('クリア'); }, }, });css.flex-container { display: -webkit-flex; display: flex; -webkit-justify-content: center; justify-content: center; -webkit-align-items: center; align-items: center; flex-wrap: wrap; }感想
Web開発は初でしたが、色々勉強にはなったかな。。
経験積んで、技術力を上げたいと思う。(Web開発は非常に興味あるので。)
- 投稿日:2020-10-26T23:19:03+09:00
デバックの方法 〜初学者向け
はじめに
まだ苦手意識があるJS。コンソールのエラーがなかなか読み取れない。そこで、本日の学習でデバックのやり方が少し身についたので、記録しておく。
基本パターン
debugger
をコードに入れておけば、そこで強制的に処理を止めてくれる。Railsで言うbinding.pry
のようなもの。
どの辺りでエラーが出ているのか、エラー文を見ればわかるが、debugger
を使えば、行ごとに細かく検証していくことができる。変数定義ができているかの確認
JSでDOMを操作するときはとにかく変数に入れることが多いと感じる。その時々で、ちゃんと変数に意図したものが入っているのか確認する必要がある。そんなときは、
cosole.log(変数名)
でブラウザのコンソールに出力させる。そのときに、nilと出れば、変数定義されていないことに気付くことができる。最後に
本日の学習では、この2つのパターンを使って、エラーを解決することができた。ファイルの読み込みはできているのか、イベント発火は正常かなど、細かく検証していくことが大切だと感じた。
- 投稿日:2020-10-26T23:00:27+09:00
JSエコシステムぶらり探訪(4): npmとコマンドライン
前回に続きnpmの機能について扱います。今回はnpmとコマンドラインツールとの関わりを中心に見ていきます。
注意: Windowsとそれ以外では、npmのフォルダ配置は異なります。Windowsでの挙動についてはnpm-foldersを参照してください。
グローバルインストール
npmは通常、Node.jsの配布物に同梱されていますが、yarnは同梱されていません。yarnを使う場合は次のようなコマンドを実行します。
npm install -g yarnこれによって以下のような効果が発生します。
$PREFIX/lib/node_modules/yarn
以下にyarnの中身がインストールされる。$PREFIX/lib/node_modules/yarn/node_modules
以下にyarnの依存関係がインストールされる。$PREFIX/bin
にシンボリックリンクyarn
,yarnpkg
が生成される。どちらも../lib/node_modules/yarn/bin/yarn.js
を参照している。
- これはyarnの
package.json
の "bin" フィールドの記述に基づいて生成される
$PREFIX/bin
にはNode.jsの実行バイナリ (node
) も入っているので、Node.jsが使えている時点でここにPATHは通っていると仮定してよさそうです。
$PREFIX/lib/node_modules/yarn/bin/yarn.js
は実行可能属性が付与されていて、冒頭は以下のようになっています。1#!/usr/bin/env node /* eslint-disable no-var */ /* eslint-disable flowtype/require-valid-file-annotation */ 'use strict';つまり、nodeにパスが通った状態で
yarn
を実行するとnode $PREFIX/bin/yarn
が実行されます。Node.jsはモジュール解決前にシンボリックリンクを解決する2ので、これはnode $PREFIX/lib/node_modules/yarn/bin/yarn.js
と同じ意味になります。 (yarn.js
を起点にrequire
が解決される。)
npm install -g
のインストール先は$PREFIX/lib/node_modules
であって$PREFIX/lib/node
ではありません。Node.jsの探索ルールに含まれているのは前者ではなく後者です3から、これによってライブラリをインストールしてもrequire
から使われることはありません。yarnの場合
npm install -g
のかわりにyarn global add
を使います。- インストール先はnpmとは異なり、バイナリは
~/.yarn/bin
に、パッケージ本体は~/.config/yarn/global
にそれぞれインストールされます。そのため、npmと違い、node用のパスとは別にPATHを通しておく必要があります。- また、上記のインストール先はyarnでは変更可能です。
npm installの古い挙動
-g
をつけない場合、npm install
はローカルインストールの挙動になります。npm v4までは、npm installはデフォルトでは
./node_modules
への展開のみを行い、package.json
を更新しませんでした。そのため、npm install -S
と書くのが一般的でした。npm v5以降では-S
が自動的に仮定されます。アプリケーションのローカルインストール, yarn exec, npx
現代のJavaScript開発ではprettier, eslint, typescript (tsc), webpackなど多くのCLIツールを使います。これらはグローバルインストールすることもできますが、以下のような懸念があります。
- これらのツールのバージョンが開発者ごとにバラバラだと、再現性の低いトラブルに遭遇しやすくなる。
- eslintやwebpackはプラグインも含めて使うことが多く、これらを含めた全てのパッケージを個別にインストールさせるのはセットアップの手間につながる。
このため、プロジェクトで使うアプリケーションは
package.json
に指定してローカルインストールほうが主流になっています。方法は簡単で、ライブラリと同様にnpm install (-S)
またはyarn add
するだけです。グローバルインストール時には
$PREFIX/bin
以下にシンボリックリンクが作成されますが、ローカルインストールの場合は同様に./node_modules/.bin
以下にシンボリックリンクが作成されます。通常このディレクトリにはPATHは通っておらず、 ローカルインストールされたアプリケーションは、通常のコマンドと同様に呼び出すことはできないため、npm/yarnを経由して使います。以下のコマンドを経由して使われるのが一般的でしょう。
npx
(npm exec
) /yarn exec
npm run
/npm run-scripts
/yarn run
(run
が省略された場合も含む)yarn exec
yarn exec
はyarn共通のセットアップを行ったあと所与のコマンドを実行します。このセットアップにはPATH
の設定が含まれているため、ローカルインストールされたアプリケーションの実行が可能です。yarn exec prettier -w 'src/**/*.js'npx /
npm exec
npx
/npm exec
もyarn exec
と同様の目的で使用することができますが、ローカルインストールされたパッケージがない場合は自動的にnpmレジストリからパッケージを探し、一時的にインストールしてから実行します。npx prettier -w 'src/**/*.js'
prettier
がない状態で上記を実行すると、一時的なインストールが行われます。~/.npm/_npx/
以下にprettier
への依存が記述されたダミーパッケージが作られ、そこでnpm install
が行われてからローカルパッケージが実行されます。
npx
/npm exec
をサポートするバージョンは以下の通りです。
npm exec
はnpm v7以降に存在します。挙動はnpx
とほぼ同じです。npx
はnpm v5.2.0以降に同梱されていますが、独立したnpx
パッケージとしても提供されています。
- v5.2.0~v6に同梱されている
npx
の実装はlibnpx
パッケージを使っているため、npx
パッケージと共通です。- v7に同梱されている
npx
はnpm exec
のエイリアスです。yarn v2 (berry) にはこれに対応する
yarn dlx
が組み込まれていますが、本記事では詳しくは述べません。scripts
npm run
/npm run-script
/yarn run
はpackage.json
に記述されたスクリプトを実行します。つまり、 npm/yarnには簡易的なタスクランナーとしての機能があるといえます。package.json{ "scripts": { "build": "tsc", "test": "jest", "fmt": "prettier -w src/**/*.ts" } }
npm run
はnpm run-script
のエイリアスです。また、曖昧性がない場合はyarn run
のrun
は省略できます。 (yarn build
/yarn fmt
など)
scripts
内のスクリプトは./node_modules/.bin
にパスが通った状態で実行されるため、node_modules/.bin/webpack
のように明示する必要はありません。npm/yarnの管理下でコマンドが実行されるときは、PATH以外にも
NODE
やnpm_lifecycle_event
,npm_config_registry
などいくつかの環境変数がセットされます。これについてはnpm-run-script
やnpm-config
などのマニュアルを参照してください。
npm run
/yarn run
ともに、後続引数はスクリプト文字列の末尾に連結されます。たとえば、package.json{ "scripts": { "lint": "eslint 'src/**/*.ts'" } }という記述があるとき、
yarn lint --fix
はeslint 'src/**/*.ts' --fix
を実行します。ライフサイクルスクリプト
scripts
で定義されるスクリプトの中には特別な意味を持つものがあります。これらをライフサイクルスクリプト (lifecycle scripts) と呼びます。ライフサイクルスクリプトを使うとnpmの処理にフックをかけることができます。ライフサイクルスクリプトのうち重要なのは以下の2種類です。
- prepublish / prepublishOnly / prepare / prepack / postpack / publish / postpublish ... パッケージをレジストリに上げるときに呼ばれます。
- preinstall / install / postinstall ... パッケージがインストールされるときに呼ばれます。「依存関係として」「ローカルパッケージとして」「アプリケーションとして」の区別を問いません。
原則として、「preのついているフック」→「フック対象の処理」→「接頭辞なしのフック」→「postのついているフック」の順で呼ばれます。たとえばinstallの場合、以下の順番に呼ばれます4。
preinstall
フック- npmが行うインストール処理
install
フックpostinstall
フック上記の重要なライフサイクルスクリプトの関係をまとめたのが以下の図です。
ただし、prepublish以下のフックは様々な事情からサポート状況がまちまちです。以下の表を参照してください。
npm2 npm3 npm4 npm5 npm6 npm7 yarn prepublish (pack / publish) ○ ○ ○ ○ ○ ○※1 prepublish (git install) ○ prepublish (local install) ○ ○ ○ ○ ○ ○ ○ prepare (pack / publish) ○ ○ ○ ○※2 prepare (git install) ○ ○ ○ prepare (local install) ○ ○ ○ ○ ○ prepublishOnly ○ ○ ○ ○ ○ prepack / postpack (pack / publish) ○ ○ ○ ○ prepack / postpack (git install) ○ ○ × × (pre-, post-)shrinkwrap ○ ○ ※ バグと思われるものには×をつけている
※1 prepublishはyarn publish
では実行されるがyarn pack
では実行されない
※2 npm7では、pack/publish内のprepare
はprepack
の直前ではなく直後に実行されるこれらの状況を踏まえて、以下のようにスクリプトを配置するのがよいでしょう。
- トランスパイルが必要なパッケージではトランスパイルを
prepack
で行う。ただし、git依存関係のprepack
呼び出しは現時点でnpm/yarnともに盛大にバグっているので、将来的なバグ修正に期待するしかないでしょう。- ネイティブパッケージのビルドは
install
で行う。その他、npmが規定するライフサイクルスクリプトとして以下があります。
- preuninstall, uninstall, postuninstall ...
npm uninstall
にフックします。- preversion, version, postversion ...
npm version
にフックします。- preshrinkwrap, shrinkwrap, postshrinkwrap ...
npm shrinkwrap
にフックします。- pretest, test, posttest ...
npm test
のときに呼ばれます。- prestart, start, poststart ...
npm start
のときに呼ばれます。- prestop, stop, poststop ...
npm stop
のときに呼ばれます。- prerestart, restart, postrestart ...
npm restart
のときに呼ばれます。また、
npm run
/yarn run
も実際にはpre/postスクリプトを実行します。たとえばnpm run build
はprebuild
,build
,postbuild
の3つのスクリプトを実行することになります。 (preprebuild
などは実行しません) 上に挙げたうちtest/start/stop/restartは単にnpm run
のrun
を省略できるケースともみなせます。また、npmにはいくつか既定のスクリプトが存在します。
start
:node server.js
(server.js
というファイルがある場合のみ)install
:node-gyp rebuild
(binding.gyp
というファイルがあり、install
/preinstall
がどちらも定義されていない場合のみ)restart
:stop
してからstart
するのがデフォルトの挙動です。なお、yarn v2 (berry) ではライフサイクルスクリプトの扱いが大幅に整理されていて、使えるスクリプトも限定されているようです。詳しくはLifecycle Scriptsを参照してください。
npm link / yarn link
npm/yarnはデフォルトではシンボリックリンクを使いませんが、シンボリックリンク操作のためのコマンドとして
npm link
/yarn link
が存在しています。主に以下の2つの用途があります。
- 開発中のコマンドラインアプリケーションをグローバルに利用可能な状態にする (
npm link
のみ)- 開発中のライブラリを別のパッケージから利用可能な状態にする (
npm link
/yarn link
)アプリケーションのリンク
package.json
のあるディレクトリでnpm link
を無引数で実行すると$PREFIX/lib/node_modules
以下に作業中のパッケージ (カレントディレクトリ) へのシンボリックリンクが作成されます。また、$PREFIX/bin
に対応するシンボリックリンクが作成されます。これらのディレクトリはnpm install -g
が使用しているものと同じなので、実質的にローカルパッケージのコマンドをグローバルに利用可能な状態にしていることになります。無引数の
npm link
は「シンボリックリンクであること」以外はnpm install -g
と同じなので、npm uninstall -g <パッケージ名>
で元に戻せます。 (なお、npm unlink
はnpm uninstall
のエイリアスです)ライブラリのリンク (npm link)
npm link
にパッケージ名を引数にして実行すると、$PREFIX/lib/node_modules/$package_name
が指していたディレクトリへのシンボリックリンクが./node_modules/$package_name
として作成されます。 (元々./node_modules/$package_name
に展開されていたファイルは消滅します)このコマンドは通常、「無引数の
npm link
」と組み合わせて以下のように使うことが想定されています。cd /path/to/foo1 npm link cd /path/to/bar1 npm link foo1 # foo1 は/path/too/foo1/package.jsonに記載のパッケージ名 # 以降はbar1は /path/to/foo1のソースを参照するようになるこの操作の正しい取り消し方法はわかりませんが、以下のようにすると良さそうです。なお、
npm unlink
はnpm uninstall
のエイリアスであり、npm link
の逆を行ってくれるわけではありません。npm uninstall --no-save $package_name npm install --forceライブラリのリンク (yarn link)
yarn link
も同様の目的で使うことができます。
- 無引数の
yarn link
は~/.config/yarn/link/$package_name
というシンボリックリンクを作成します。- 引数つきの
yarn link $package_name
は./node_modules/$package_name
を消し、~/.config/yarn/link/$package_name
へのシンボリックリンクで置き換えます。
npm link
が作成するシンボリックリンクは直接参照ですが、yarn link
が作成するシンボリックリンクは間接参照になるようです。使い方は
npm link
と同じです。cd /path/to/foo1 yarn link cd /path/to/bar1 yarn link foo1 # foo1 は/path/too/foo1/package.jsonに記載のパッケージ名 # 以降はbar1は /path/to/foo1のソースを参照するようになる
yarn link
を取り消すには以下のようにします。 (npmとは異なり、yarn unlink
はlink
の逆をするためのコマンドです)yarn unlink
yarn link $package_name
を取り消すには以下のようにします。yarn unlink foo1 # foo1 はyarn linkしていた依存関係のパッケージ名 yarn install --forcelinkの問題点
linkを使うと、利用側パッケージの動作を確認しながらライブラリを編集できるようになります。しかしNode.jsの
require
の挙動上、linkした依存関係は通常の依存関係とは異なる挙動をすることがあります。これは以下の2つの理由によります。
- 依存元パッケージの
node_modules
を参照できないこと。- ライブラリ側の
node_modules
が優先されてしまうこと。上記の理由により、以下のような現象が発生する可能性があります。
- 間接依存関係のバージョンが一致しない。 (ライブラリ側が使うバージョンはライブラリ側の
package-lock.json
/yarn.lock
に基づいて決まるため)- peerDependenciesに書かれたパッケージが見つからない。 (peerDependenciesは依存元パッケージ側の
node_modules
に存在するため)- 間接依存関係のバージョンが同じで、巻き上げの条件を満たしていても、二重requireが発生する。
node_modules
を用いた古典的なパッケージ管理を使っている限り、これらを綺麗に解決するのは難しいですが、 1. については--preserve-symlinks
オプションを使うことで緩和できる可能性があります。Node.jsは通常シンボリックリンクを明示的に展開しますが、--preserve-symlinks
が指定されたときはこの挙動がスキップされます。これにより、../node_modules
や../../node_modules
を参照するときの親ディレクトリの計算結果が変化し、ライブラリ側から依存元パッケージのnode_modules
がrequireできるようになります。gulp / grunt
package.json
のscripts
では賄いきれないような複雑な処理 (タスク定義の共通化や依存管理) を定義したい場合は、GulpやGruntのようなタスクランナーを使うことができるようです5。ただし、JavaScriptのプロジェクトで行う必要があるタスクは典型的なもの (トランスパイルやバンドリング) が多く、TypeScriptやWebpackなどそれぞれのツールが依存管理を含めたパイプラインを提供しているため、これらで済んでしまうことも多いでしょう。まとめ
npm install -g
/yarn global add
を使うと、パッケージをグローバルにインストールし、CLIツールとして使うことができる。npm install
/yarn add
で追加したパッケージもnode_modules/.bin
にPATHを通すことでCLIツールとして使うことができる。npm
/yarn
の内部で呼ばれるコマンドはこのディレクトリにPATHが通った状態で呼ばれる。yarn exec
/npx
/npm exec
を使うと、任意のコマンドをnode_modules/.bin
にPATHが通った状態で実行することができる。また、npx
/npm exec
に存在しないコマンドを渡した場合は、自動インストールが行われる。npm run
(npm run-script
) /yarn run
を使うと、package.json
のscripts
に登録されたコマンドを実行できる。yarn run
のrun
は省略できる。scripts
の中には特別なコマンド名がいくつかあり、npm/yarnの特定の処理にフックすることができる。どのフックが呼ばれるかはバージョンによる挙動の違いが激しいので注意が必要。
- ネイティブ拡張のビルドが必要な場合は
install
かpostinstall
で行うのがよい。- トランスパイルは
prepack
で行うのがよいが、現状ではnpm/yarnともにバグがあってあまりうまく動かない。npm link
/yarn link
を使うと、別のディレクトリにあるパッケージを直接使うことができる。アプリケーションの動作を確認しながらライブラリの開発するのに有用だが、依存解決の観点からはlinkによって異なる挙動をする可能性があるため、注意が必要。npm run
/yarn run
は単なるスクリプト実行機能しかないので、Makefileのようなより複雑なタスク管理が必要ならGulpやGruntなどのタスクランナーを使うのがよい。ただし、トランスパイルやアセットのビルドなど典型的なものであれば、Webpackなどそれに特化したツールで目的を達成できることも多い。次回はモジュールバンドラーの基本的な役割と実装について、webpackを例に説明します。
- 投稿日:2020-10-26T22:45:53+09:00
アニメ番組管理のWebアプリ開発(自分用メモ)
Annict API の実装メモ
アニメ番組管理の自分用Webアプリとか作れないかな。(ぼんやり。)
新アニメとか、とりあえず1話見てみるってのが多いからな。
スタート直後はタイトルだけ見ても見てたかどうか分からんことが多いし。。アニメ番組情報を取れそうなAPI
・annict.js
・ShangriLa Anime API Server
・しょぼいカレンダー(json.php)Annict API(Annict.js) サインインできない
Annictは個人開発っぽい。番組表を自分で管理できるWebアプリの模様。そのままでも使えそう?
ただ、、メールアドレスを入れて「Send」してもメールが届かない?サインインできない。意味不明。
※追記:かなり遅れてメールが届いた。(時間帯?)ShangriLa Anime API Server
APIの仕様も使いやすそう。ただ放送時間は取れない。基本情報のみ。しょぼいカレンダー(json.php)
オタク系番組表。仕様が分かり辛い。放送時間を取れそうだけどxml形式。
・タイトル取得(例):http://cal.syoboi.jp/json.php?Req=TitleLarge
・番組時間取得(例):http://cal.syoboi.jp/db.php?Command=ProgLookup&TID=5766実装
エラー1:CodePenではformタグは使えない。
エラー2:axios読み込み忘れ。CodePen「Settings」の"JS"タブから追加。
リンク先Webページのサムネイル表示したい
link-prevueライブラリ
title、descriptionでサイトカードを生成しているっぽい。
・リンクのプレビュー機能を「link-prevue」を使って実装する
・link-prevue -GitHubリポジトリ
※上手く取得できないサイト多数。説明に表示された言語もバラバラだったので利用見送り。LinkPreview API
URLからサイトサムネイル画像のURLや簡単な説明を返してくれそう。よさげ。
・LinkPreview
※エラー423が返される場合がある。(リクエスト先Webページで拒否される場合。)
※エラー429が返される場合がある。(リクエスト上限がかなり低いっぽい。)そもそもWebページの画像って?OGPイメージなのでは?
APIだとなんか微妙なので、OGPイメージを取ればよいって考え方にシフト。
※取得はうまいことできそう。非同期の罠にはまる。→解決せず。
・JavaScriptでURLからOGP取得する - Qiitaimgが表示されない、、
・【Vue.js】なぜかimgが表示されない時の解決法とその理由
・Vue.js imgタグのsrc要素は指定の仕方によって読み込み方が違う -Qiita
・vueで画像が表示されない
※良く分からん、、とりあえず以下で上手くいった。(上手く表示しないイメージもあったけど。).html<img class="img" v-bind:src="urlを指定" width="200"> </img>カード表示で横並びにしたい
・よく使うタイル(カード)デザインを CSS のパターン別でご紹介
・フレックスボックス(フレキシブルボックス)とはなにか?その他参考
・Vue.jsを100時間勉強して分かったこと - Qiita
・Vue.jsでv-forをネストする - Qiita
・忘れやすい、複雑なJSONの要素をfor...in文で取り出す方法
- 投稿日:2020-10-26T22:36:17+09:00
【JavaScript】画像をランダムに表示させる方法
プログラミング勉強日記
2020年10月26日
何枚かの写真からJavaScriptを使ってランダムに1つ表示させる方法を紹介する。方法
表示候補の画像ファイルリストを事前に準備しておき、乱数を使って1つを選び出して表示させる。
具体的な手順
1. 表示させる可能性のある画像ファイル名をすべて配列に入れる
2. その中からアクセスされるたびに乱数を使って1枚選ぶ
3. 選んだ画像1つを表示させるサンプルコード
JavaScriptconst imageArea = document.getElementById('imageArea'); const images = ['【画像パス1】', '【画像パス2】', '【画像パス3】']; const imageNo = Math.floor( Math.random() * images.length) imageArea.src = images[imageNo];HTML<img src="【画像パス】" id='imageArea'>参考文献
画像をランダムに表示する方法!JavaScriptで切り替え
JavaScriptで文字列や画像をランダムに表示する方法を現役エンジニアが解説【初心者向け】
- 投稿日:2020-10-26T22:04:37+09:00
娘とあと何日お風呂に入れるか計算するWebアプリ作ったら泣けてきた
娘とあと何回一緒にお風呂入れるだろう?
「もう一緒に入りたくない」と言われる前に自ら娘とのお風呂は卒業したいもの。とはいえ、可能な限り一緒に入りたいというのが、父親の心情。あと何回一緒に入れるだろうかと考えたら、今日の1回も特別に思えるはず。そんな思いから、娘とあと何日一緒にお風呂に入れるか計算するWebアプリを作ってみました。
作ったWebアプリはこちらあと何日一緒にお風呂に入れる?
あとこれしかない。。泣けてきた。。
娘の「パパ風呂」卒業のタイミングは、小学校3~4年生頃が多いようです。
娘の9歳の誕生日を卒業する日と定めると...
2020年10月26日時点で、あと、2608日
2日に一回だとしたら1304日
一週間に一回だとしたら372日...
泣けてきた環境
コーディング
CodePen:Webブラウザ上でHTML/CSS/JavaScriptなど、主にフロントエンド言語のコーディングができるサービス
使用したライブラリ
vue.js
splitting.js:テキストアニメーションが実装できるライブラリソース
index.html<!-- 全体をVue.js有効にする --> <div class="container text-center text-white" id="app"> <!-- タイトル行 --> <div class="row my-3"> <div class="col-sm-15 mx-auto"><div data-splitting><h1>あと何日一緒にお風呂入れる?</h1></div> </div> </div> <img src="https://4.bp.blogspot.com/-YUk507i8b7s/UfIJFj6AMQI/AAAAAAAAWc0/KzQO-AiH6Jg/s800/dakko_papa_girl.png" width="30%"/> <div class="form-group"> <label for="lastday">卒業する日</label><input class="form-control col-sm-6 mx-auto" type="date" id="lastday" onChange="calc();"/> <label for="today">今日の日付</label><input class="form-control col-sm-6 mx-auto" type="date" id="today" onChange="calc();"/> </div> <div class="form-group"> <label for="days">一緒にお風呂に入れる日数</label><input class="form-control col-sm-6 mx-auto" type="text" readonly id="days"/> </div> <div data-splitting><label for="days">卒業のその日まで、有意義に過ごしてほしい。小さい娘を持つ全てのパパへ。</label></div> <br> </div> <!-- 全体ここまで -->style.css@import url(https://fonts.googleapis.com/css?family=Kanit:600); html { height: 100%; display: flex; } body { margin: auto; } html, body { background: #00043C; color: #FFF; font: normal 600 1.5vw/1.5 Kanit, sans-serif; } .splitting .char { animation: slide-in 1s cubic-bezier(.5, 0, .5, 1) both; animation-delay: calc(60ms * var(--char-index)); } @keyframes slide-in { from { transform: translateY(-1em) rotate(-.5turn) scale(0.5); opacity: 0; } }script.jsSplitting(); function calc() { lastday = new Date($('#lastday').val()); today = new Date($('#today').val()); console.log(lastday.getTime()); console.log(today.getTime()); var days = Math.floor((lastday.getTime() - today.getTime()) / (1000 * 60 * 60 *24)); $('#days').val(days); } function today() { $('#today').val(formatdate()); } function formatdate(date) { var toTwoDigits = function (num, digit) { num += '' if (num.length < digit) { num = '0' + num } return num }; date = date ? date : new Date() var year = date.getFullYear() var month = date.getMonth() + 1 var day = date.getDate() var yyyy = toTwoDigits(year, 4) var mm = toTwoDigits(month, 2) var dd = toTwoDigits(day, 2) var ymd = yyyy + "-" + mm + "-" + dd; return ymd; } $(function() { $('#lastday').val(formatdate()); $('#today').val(formatdate()); }());はじめてのWebアプリケーション
プログラミング初心者の私でもCodepenと便利なライブラリを駆使して、割と簡単に実装することができました。今後は音を入れるとか、もう少しリッチな見た目とか、スマホ用に便利な画面とか、作れるようになったらより楽しいだろう。時間を見つけて、色々と試作してみたいです。
おまけ
あまりに早く成長してしまうことが悲しいと思うこともありますが、我が子の成長はやはり嬉しいものです。一緒にお風呂に入れなくなっても、いつか娘に一緒とプレモルが飲めることを楽しみに頑張ります
- 投稿日:2020-10-26T22:03:47+09:00
random関数でランダムな値を生成する
以下のコードで0〜5の中からランダムな値を生成できる
Math.floor(Math.random() * 6);
*6
の意味がわからなかったため調べたことを残しておく。Math.random()
random関数
は0以上、1未満の浮動小数点の擬似乱数を生成する関数console.log(Math.random()); // 0.3538826537319486 ← 0以上、1未満 // 1未満のため最大でも0.999999999999・・・
floor
メソッドは引数として与えた数以下の最大の整数を返すためMath.floor(Math.random());
とすると0しか返ってこないことになる。
返ってくる値の個数を増やしたいのであればMath.random()
の値を大きくすればいいため*n
として最大値を大きくする。
そしてMath.random()
にかける数を3倍, 4倍, 5倍と増やしていくごとに、得られる数値の数も3個, 4個, 5個と増えていくため欲しい数値分掛け算をすればいい。初めの疑問に戻ると6倍することで乱数の最大値を5.9999・・・として0〜5の間でランダムな値を生成しているというのが今回の疑問に対する答え。
応用編 最小値を0以外にする
今までの方法は最小値を0として最大値を設定していたが以下の式によって最小値を0以外にすることも可能。
Math.floor(Math.random() * ( 最大値 - 最小値 + 1 ) + 最小値);例えば5〜10でランダムの値を取りたい場合、上記の式に当てはめると
( 最大値 - 最小値 + 1 )
の部分は6になる。
そして、もし+最小値
の式を入れなかった場合取れる値は0〜5になる。
0〜5の値を5〜10にするためにはどうすればいいかというと最小値を足せばいい。0, 1, 2, 3, 4, 5 5, 6, 7, 8, 9, 10 //上段の値に5(最小値)を足すと下段の値になる5〜10に限らずどの範囲であっても上の式に当てはめることで範囲を指定できます。
以上、random関数についてでした!
- 投稿日:2020-10-26T22:03:47+09:00
Javascript random関数について
以下のコードで0〜5の中からランダムな値を生成できる
const number = Math.floor(Math.random() * 6);
*6
の意味がわからなかったため調べたことを残しておく。流れは以下のとおり。
1.floor
メソッドの引数としてMath.random() * 6
を指定する。2.
random関数
は0以上、1未満の浮動小数点の擬似乱数を生成する関数console.log(Math.random()); // 0.3538826537319486 ← 0以上、1未満→random()で生成された擬似乱数を*6することで0以上6未満の乱数が生成される。
(上の例でいうと0.3538826537319486
に6をかける)
3.floor
メソッドは引数として与えた数以下の最大の整数を返してくれるため0〜5の中からランダムな値が出来上がる。以上、random関数についてでした!
- 投稿日:2020-10-26T22:02:36+09:00
JavaScript学習 OutPut part1 JavaScriptとは??
はじめに
こんにちは。のりべんと申します。
この度プログラミング学習のoutputの場(兼文書作成の練習)を設けるために
Qiitaを開設しました。
自分の学習内容が後の初学者のお供になれるような、
誰が見ても分かりやすい記述
を心がけていこうと思います。よろしくお願いします。投稿主詳細
- (一応)理系大学院卒
- システムエンジニア1年目
- 後々はマネジメントに携わるより永遠とプログラム組んでスペックを上げたい
- paiza:Aランク(確かCで取ったけどコーディングはお察し)
- python使って画像処理したりunityでc#かじったり(鼻くそ程度)
JavaScriptの振り返り
ここからは教材で学習した内容をoutputしていきます。
使用した教材はこちら
それでは以下常体。JavaScriptって何?
簡潔に言うとHTMLやCSSだけでできないことを補うブラウザ操作のためのプログラム言語。
webページは基本的にHTMLとCSSで構成される。
しかしHTMLとCSSだけでは静的(一度ブラウザに読み込まれたら変化しない)なwebページとなる。
webページをその場で書き換えて動的(リアルタイムに書き換えて動きをつける)にすることを可能にするのがJavaScriptなのである。キーワード
- ブラウザを操作することができる
- HTMLやCSSだけではできないことを補うために使う
- HTMLやCSSをリアルタイムに書き換えられる
↑この小計が
↑数量を変更した時、ページ読み込み無しで表示が変化するのが動的なwebサイトと言えるJavaScriptでHTMLやCSSを書き換える
では具体的にどのような書き換えを行っているのか?
HTMLやCSSの書き換えには大きく分けて4パターンある。
これらの書き換えはブラウザの表示に即座に反映される。
(ページの再読み込みは必要ない。)
これにより
ホームページではない、アプリらしい動きのwebページを作ることができる。パターン1 タグに囲まれたテキストの書き換え
例)タグ内の書き換え
<p>こんにちは</p>↑これを
<p>さようなら</p>↑にJavaScriptが書き換えてくれる
パターン2 要素の追加、削除
例)タグの追加
<ul> <li>こんにちは</li> </ul>↑これに
<ul> <li>こんにちは</li> <li>元気ですか?</li> </ul>↑liタグで「元気ですか?」とJavaScriptが追加してくれる
例)タグの削除
<ul> <li>おはようございます</li> <li>寒くなってきましたね</li> </ul>↑このliタグの寒くなってきましたねを
<ul> <li>おはようございます</li> </ul>↑JavaScriptで削除できる
パターン3 タグの属性を変更
例)srcタグの属性の値を変更
<img src = "noriben.jpg">↑この場合noriben.jpgというファイル名がsrcタグの属性の値となる。これを
<img src = "karaben.jpg">↑JavaScriptでkaraben.jpgに値の変更ができる
パターン4 CSSの値を変更
例)CSSのの背景色の変更
body{ background:#ffffff; }↑CSSでwebサイトの背景色を設定しているところを
body{ background:#fff100; }↑JavaScriptで中身を変更することができる
JavaScriptの基本的で重要な役割
JavaScriptの重要な役割は次の2点
- ブラウザに表示されているHTMLやCSSを書き換える
- ブラウザに表示されているHTMLやCSSから情報を読み取る
上記では書き換えに関する内容を説明したが、実際には情報の読み取りも可能である。
例)住所などの入力フォームに入力された内容の読み取りなどJavaScriptの仕組み
では、実際にJavaScriptがどのような書き換えを行っているのかを具体的な例で見ていきます。
例)ネットでポケモンカード拡張パックを買う場合(消費税は考慮しない)
※ポケモンカードは1パック150円とする。
ネット通販なんかで購入しようとするとおそらくこのようなフォームが想像できるでしょう。
(数量はユーザーが書き換え可能)品名 |単価 |数量 |小計 ポケモンカード拡張パック| | | 列空の覇者 |150 |1 |150これは単価と数量によって小計が変化するため、JavaScriptでは単価と数量を取得する。
そこから取ってきた値を掛け合わせた数を小計として出力していく。品名 |単価 |数量 |小計 ポケモンカード拡張パック| | | 列空の覇者 |150 |3 |450 ↑単価と数量をJavaScriptで取得して小計を出力しているこの処理は4つのステップに分けることができる。
1. 単価をHTMLから取得
2. 数量をHTMLから取得
3. 単価×数量で小計を計算する
4. 計算結果を使ってHTMLを書き換える1、2に関しては必要なデータを取得するこのステップはインプットのステージ
3に関してはインプットされたデータを加工して結果を得るステージ
4に関しては加工して得られた結果を出力するアウトプットのステージ
ということができる。
JavaScriptでは
インプット → 加工 → アウトプット
という流れが共通する処理の流れとなる。JavaScriptのイベント
インプット → 加工 → アウトプットはJavaScriptの処理の一連の流れである。
ではこの処理はどのタイミングで発生するのか?
今回の例であれば「パックの数量が変更された時」である。
数量の変更されたタイミングで
単価と数量がHTMLから取得され(インプット)
→単価と数量が掛け合わされ(加工)
→小計として合計値が出力される(アウトプット)
が行われ、数量を変更するたびに描画が繰り返される。
この処理のきっかけのことをJavaScriptではイベントと呼ばれている。終わりに
今回はJavaScriptがどのような場面で使われるか、どのような働きをするか、その仕組みについて取り上げていきました。
次回からはJavaScriptのアウトプットについて触れていきます。
以上となります。お疲れ様でした。
- 投稿日:2020-10-26T21:37:45+09:00
formタグは1つのまま、1つの要素クリックで複数の関連するnameだけを送信(post)させる方法
どうも7noteです。綺麗に書きたいがあまりちょっと無理やり作りました。
(※データを送信するだけならhtmlとjavascriptでできますが、受け取ってその後利用するにはphpの知識が必要です!)
例えば都道府県のように地域(関東とか)と都道府県名の2種類のデータを個別にpostさせたい時に使える方法です。
普通、複数のデータを送る時はinputのname属性を配列にする方法が一般的です。
一般的に複数のデータを送信する例)
<form action="./" method="post"> <input type="checkbox" name="pref[]" value="tokyo"> <input type="checkbox" name="pref[]" value="osaka" > <input type="submit" value="送信"> </form>※ 受け取り側はpostを受け取れるようphpで作成してください。
この方法で、東京と大阪をpostすることはできましたが、同じ方法でエリアを送信してしまうと
pref['kanto', 'tokyo']
のようにエリア名と都道府県名が1つの配列内に混ざって送信されてしまいます。今回はこれを↓のように分けて送信する方法を書きます。
area ⇒ "kanto" pref ⇒ "tokyo"都道府県ごとに、エリアと都道府県情報をpostさせる方法
※jQueryを使用しています。
index.html<form action="./" method="post" name="prefform"> <input type="hidden" name="area" value=""> <input type="hidden" name="pref" value="" > </form> <ul> <li area="kanto" pref="tokyo">東京</li> <li area="kanto" pref="kanagawa">神奈川</li> <li area="kansai" pref="osaka">大阪</li> </ul>script.js$(function(){ $("ul li").on("click", function(e){ // li要素がクリックされたとき area = $(this).attr("area"); // li要素のarea属性の値を取得 pref = $(this).attr("pref"); // li要素のpref属性の値を取得 $("#input_area").attr("value",area); // inputのvalue値を変数areaに置き換え $("#input_pref").attr("value",pref); // inputのvalue値を変数prefに置き換え document.forms.prefform.submit(); // submit(送信)する。 }); });とび先は、form要素のactionにURLやディレクトリを記述してください。
説明するほどのことはしていないのですが、クリックされた要素の属性値、それぞれprefとareaを取得します。
サブミット(送信)する前に、inputの中のvalue値に値を入れます。
値を入れた後、サブミットすることでエリアと都道府県をそれぞれ個別で送信することができます。
もしとび先の修正などが入った場合でも、formタグのactionを1箇所修正するだけ済むので、管理が楽になるかと。まとめ
もっとよい方法や綺麗な書き方などあるかもしれませんが、ひとまずこれで十分の機能ははたせるかなと思います。
javascriptは使わず、htmlだけでもできなくはないですが、何度も何度もformタグやinputタグを書くとなるとソースが見にくく管理もしにくくなるので、何かしらで対応できるような作りの方がいいかなと思います。おそまつ!
~ Qiitaで毎日投稿中!! ~
【初心者向け】HTML・CSSのちょいテク詰め合わせ
- 投稿日:2020-10-26T21:18:13+09:00
【JavaScript】開発を行う前に整理しておきたい言葉の定義
「言語」、「フレームワーク」、「ミドルウエア」、「ライブラリー」、「テンプレートエンジン」など様々な言葉には意味がある。
今回は「JavaScript」と「Node.js」について整理した。■JavaScriptとNode.jsについて
JavaScript:JavaScriptはブラウザ上で動くために開発されたプログラミング言語。
Node.js:イメージはサーバサイドのJavaScript。正確にはNode.jsはサーバサイドでJavaScriptを実行できるようにしてくれるプラットフォーム。■Node.jsの特徴
・サーバーサイドのJavaScript
・非同期
⇢I/O(Input/Output)の処理結果を待たず処理を進める。
・ノンブロッキングI/O
⇢I/Oの結果を待たないで処理をすすめる。I/O処理が終了したらコールバック関数を実行。
・イベントドリブン (何かしらのキッカケで動き始める)
⇢https://qiita.com/hththt/items/aefbcc6eb191588dadff
・シングルスレッド
⇢メモリ消費が少ない、仕事切り替えが少ないので速い
・JavaScript エンジンが Google の V8 で速い
⇢V8は、Googleが開発するオープンソースのJIT Virtual Machine型のJavaScriptエンジン。■定義と使用区分の振り分け
・言語:Javascript、Node.js
⇢PCに下す命令言語
・フレームワーク:Express、React、jQuery、AngularJS、Vue
⇢JavaScriptを使用してWebサイト開発やWebアプリケーションを開発する際の土台として機能するソフト
・ミドルウェア:PostgreSQL
⇢OS(オペレーティングシステム)とアプリケーションソフトの中間役割を担うソフト
・ライブラリー:express-session、express-validator
⇢使用頻度の高い機能や効果などのプログラムをまとめたもの
・テンプレートエンジン:ejs
⇢テンプレートと呼ばれるHTMLのひな形を元にプログラムで加工し、画面に出力するためのライブラリ。■変数の定義
・「const」や「var」、「let」で変数を定義。何らかの値を変数に代入して使用する。【例】
// 数値 const numValue = 100; // 文字列 const strValue = "私は値です!"; // 真偽値 const boolValue = true; // 配列 const arrayValue = [1, 2, 3]; // 連想配列 const objValue = { key: 'value' };■データの型
var:変数を宣言し、ある値に初期化することもできる。
let:スコープのローカル変数を宣言し、ある値に初期化することもできる。
const:スコープで読み取り専用の名前付き定数を宣言する。■MDN 文法とデータ型
https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Grammar_and_types■スコープ
JavaScriptでは関数の中で定義された変数やオブジェクトは関数の外からアクセスすることができない。
関数の中で定義された変数やオブジェクトを操作したい場合は同じ関数の中で処理を記述する必要がある。【例-1】
function hoge(){ var x = 0; } hoge(); console.log(x);⇢この場合console.log(x);でエラーとなる。変数xはhoge関数の中で定義されているため。
【例-2】
function hoge(){ var x = 0; console.log(x); } hoge();⇢この場合、エラーとならない。
■関数の定義
・関数の定義を行い、定義した関数を使用する。// 関数を定義する function 関数名(仮引数){ 実施したい処理内容 } // 関数を使用する 関数名();【例】
// add関数が定義される function add(a, b) { return a + b; } // add関数を出力する console.log(add(1, 2)); // この場合「add関数」と「log関数」が使用されている。・javascriptでは関数を変数に代入することができる。
つまりjavascriptでは関数も値。// addFunction変数にadd関数を代入 const addFunction = function add(a, b) { return a + b; } // addFunction変数を出力 console.log(addFunction(1, 2)); // 定義した関数を変数に入れることも出来る const addFunction = add;・Javascriptで関数は値。関数を複数回使用することもできる。
関数を受け取る関数を「高階関数」と呼ぶ。// 関数を2回実行する関数の作成 function toDoTwin(func) { func(); // 1回目の関数 func(); // 2回目の関数 } // Hello Worldが2回呼び出される toDoTwin(function() { console.log('Hello World'); });【例題】
配列を受け取って配列の末尾に数値3を加える関数を作る。
※配列に追加する関数は[].push(数値)で入れられる。【例】
var arr = [1,2] // 関数は動詞。キャメル型を使用。 function addNum(arr) { arr.push(3) return arr; }; addNum();↓修正中
■コールバック関数とは
シンプルに言うと「高階関数に渡すための関数」。
【例】setTimeout(function() { console.log('Hello World'); }, 2000);⇢この場合、2000ミリ秒後に「Hello World」と出力させる
■非同期処理とイベントとコールバック関数
非同期処理は「書いた順に動く」というプログラムの基本とは違う動きになる。「書かれているコードを今は飛ばして後で実行して」という矛盾した状況になる。JavaScriptの多くの非同期処理は、これを以下のような方法で実現。
・非同期処理関数はコールバック関数を受け取る高階関数にする
・利用者は「終わったら実行したい処理」をコールバック関数として渡す
・非同期処理関数は処理が終わったらコールバック関数を呼び出す非同期処理はコードを複雑化させてしまうため、非同期処理を簡単に扱うことができる、Promiseやasync/awaitという機能がある。
【例】
setTimeout() => { console.log('hello'), 500); console.log('world!'); };「world」が先に表示され、500ミリ秒が経過してから「hello」が表示される。
非同期処理では、実行順序はコード通りにはならない。
- 投稿日:2020-10-26T20:56:35+09:00
_.debounce と _.throttle は何が違うのか
Vue.js 公式ガイドにて学習をしていたところ、
lodash
の_.debounce
を使っている箇所があり、
以下のように記載されていた。
// _.debounce (とその親戚である _.throttle ) についての詳細は // https://lodash.com/docs#debounce を見てください。 this.debouncedGetAnswer = _.debounce(this.getAnswer, 500)
参考URL先のドキュメントを読んでみたのですが
_.debounce
と_.throttle
の違いがいまいち分からず(英語苦手....)挙動としては以下の感じの実装です。(ソースはこちら)
文字を連続で入力したときに
getAnswer
の関数が何度も呼ばれないようにしているみたいです。
調べてみると以下の違いのようでした。
_.debounce
:連続して呼び出しても指定された時間以内なら処理は実行しない_.throttle
:連続して呼び出しても指定された時間以内に1回しか実行しない
なるほど...(わからん)
ということでどっちも実装して違いを見てみました。
_.debounce
の場合以下のように実装。
(2000ミリ秒で設定)this.debouncedGetAnswer = _.debounce(this.getAnswer, 2000)これで一定の間隔で文字を入力してみます。
入力する間隔が2000ミリ秒以内だと
getAnswer
の処理が呼ばれない
=「連続して呼び出しても指定された時間以内なら処理は実行しない」
_.throttle
の場合以下のように実装
(2000ミリ秒で設定)this.debouncedGetAnswer = _.throttle(this.getAnswer, 2000)こちらも先程と同じ間隔くらいで文字を入力してみます。
連続して入力しても2000ミリ秒に1回しか
getAnswer
の処理が呼ばれない
=「連続して呼び出しても指定された時間以内に1回しか実行しない」
...ということでやっと違いが理解できました!
やはり実際に動かすだけで頭に入りますね。
ちなみにlodash
を_
としてるのは
lodash
=low(低い) + dash(-)
=_
だからとかそんな理由らしいです。
引き続き勉強がんばります。
- 投稿日:2020-10-26T20:32:25+09:00
[lodash] [async.js] jsのいろいろなforEachを試してみた
はじめに
javascriptでforEachを書くパターンは色々あります
使用していて「このループを書くならこっちのほうがいいな」「このforEachって非同期処理のときどうなるんだっけ」と思い返すことが多々あったので記事にまとめておこうと思いました。
今回取り上げるのは以下です
・ Array.prototype.forEach
・ lodash forEach
・ async.js each
・ async.js eachSeriesサンプルコード内で非同期関数
asyncFunc
,arr
を呼び出していますが、これはそれぞれconst arr = [1, 2, 3]; // 一秒後に引数の関数を実行する関数 const asyncFunc = i => { setTimeout(() => { console.log(`output: ${i}`); }, 1000); }このように定義しています。
Array.prototype.forEach
Array.prototype.forEach documentation
arr.forEach(element => { asyncFunc(element) }); /** * 一秒後にまとめて結果が返ってくる output: 1 output: 2 output: 3 */
Array.prototype.forEach
はまさにノンブロッキングの形になっていて、forEach内の要素が順にイベントキューに積まれて行くといったイメージでしょうか
ちなみに、Array.prototpye.forEach
はcontinueは可能(returnするだけ)ですが、breakは不可能です
また、要素を同期的に実装するのも厳しいです。(自分の知る限りでは)lodash forEach
const _ = require('lodash'); _.forEach(arr, element => { asyncFunc(element) }); /** * 一秒後にまとめて結果が返ってくる output: 1 output: 2 output: 3 */こちらも
Array.prototype.forEach
と同様に要素がすべてイベントキューに積まれていく形です。
ただちょっと違うのは、 breakができる という点ですconst _ = require('lodash'); _.forEach(arr, element => { console.log(`start: ${element}`) asyncFunc(element) if (element === 1) return false; }); /** * 1だけ出力してbreakされている start: 1 output: 1 */このように、イベントキューに1,2,3それぞれの非同期処理が積まれていても、1の処理でbreakされれば後続の処理はされずに終了します。
また、Array.prototype.forEach
と同様に同期的に実行するのも厳しいです
小ネタとしてはdocumentにも書かれていますがObjectに対しても実行可能です。_.forEach({ 'a': 1, 'b': 2 }, function(value, key) { console.log(`${key}:${value}`); }); /** * objectに対しても利用可能 a:1 b:2 */async.js each
async.each(arr, (elem, next) => { asyncFunc(elem) next(); }, (err) => { console.log(err); }); /** * 一秒後にまとめて結果が返ってくる output: 1 output: 2 output: 3 */こちらも同様に要素がすべてイベントキューに積まれていく形です。
breakの機能はありませんが、callbackにエラーを投げることが出来ます。// 実行要素の途中でエラーが発生した場合 async.each(arr, (elem, next) => { console.log(`start: ${elem}`) asyncFunc(elem) if (elem >= 2) return next('err occured'); else return next(); }, (err) => { if (err) console.log(err) }); /** * エラーが発生したタイミングでcallbackが呼び出されるが、asyncFuncは全て実行される start: 1 start: 2 err occured start: 3 1 2 3 */ // 実行要素がすべてエラーを返さなかった場合 async.each(arr, (elem, next) => { console.log(`start: ${elem}`) asyncFunc(elem) return next(); }, (err) => { if (err) console.log(err) else console.log('error not occured') }); /** * すべての処理をキューに詰め込んだあとでcallbackが呼び出される start: 1 start: 2 start: 3 error not occured 1 2 3 */↑のように、イベントキューに積まれている非同期処理はその途中でエラーが発生(nextの第一引数にエラー内容を指定)しても関係なくすべて実行されます。また、エラーが発生した際はその直後にcallback関数(第三引数)が呼び出されます。
一度もエラーが発生しなかった際は、すべての処理をイベントキューに詰め込んだあとでcallbackが呼び出されます。
ちょっと特殊っぽい。async.js eachSeries
async.eachSeries(arr, (elem, next) => { asyncFunc(elem) return next(); }, (err) => { if (err) console.log(err) }); /** * 一秒後にまとめて結果が返ってくる output: 1 output: 2 output: 3 */先程の
async.js each
の同期的バージョンです。each
では処理の順番は保証されていませんでしたが、eachSeries
では実行順が保証されています。またそのような性質から このように
next
を活用することで同期的にすることも可能です。const _asyncFunc = (i, cb) => { setTimeout(() => { console.log(i); return cb(); }, 1000); } async.eachSeries(arr, (elem, next) => { _asyncFunc(elem, next) }, (err) => { if (err) console.log(err) }); /** * 一秒ごとに出力される output: 1 output: 2 output: 3 */まとめ
まとめてみると、意外とそれぞれで違いがあることがわかりました。
それでは
- 投稿日:2020-10-26T20:15:06+09:00
JavaScriptの関数について学んでみた
Javascriptの関数の初歩的な部分です!
Rubyを先に学んだので、Rubyとの比較などが多くなります!関数定義(Rubyでいうところのメゾット)
Rubyでメソッドを定義する際はdef メソッド名 ~ endと記述しました。
JavaScriptではfunction 関数名(){ 処理 }と記述することで関数を定義することができます。functionの使い方
hoge.jsfunction sayHello(){ console.log("やっほー!") } sayHello()//=>やっほー!が出力されます//*超基礎的な文章です!
戻り値について
Rubyの場合
hoge.jsdef calc(num1,num2) num1*num2 end num1 = 5 num2 = 9 puts calc(num1,num2)//メソッドの戻り値である45が表示される//JavaScriptの場合
hoge.jsfunction calc(num1,num2){ return num1*num2 } const num1 = 5 const num2 = 9 console.log(calc(num1,num2))//45が表示される//*戻り値をreturnを用いて明示する必要があるところがいちばんの大きな違いです!
いろいろな関数定義について
関数式と関数宣言の違い
関数宣言は上記のfunctionの使い方で記述したやり方のことを言います。
関数式は
変数 = function( 引数 ){
// 関数内の処理
}
と記述します。違いとしては読み込まれるタイミングが異なります。hoge.jshello() const hello = function(){ console.log('hello') //Uncaught ReferenceError...というエラーが出ます!// }理由としては1行目の時点で関数helloは定義されていないためです。
これを関数宣言の書き方に直してあげるとhoge.jshello() function hello(){ console.log('hello')//helloが出力されます// }JavaScriptにおいては関数宣言は先に読み込まれるので、このような事象が発生します。一方で、関数式であれば先に読み込まれることはありません。コードを書く上での実害はあまり無いかもしれませんが、このような特徴があるということを覚えておきましょう!
名前の無い関数
無名関数
hoge.jsconst calc = function(num1,num2){ return num1*num2 } const num1 = 5 const num2 = 9 console.log(calc(num1,num2))関数名なしで関数を定義することができるのでより簡潔なコードが記述できるというメリットがあります!
簡潔なってるかな?と思ったんですけど記述が増えれば増えるほどその恩恵が感じるのかなと感じています。
関数名の重複を避けることができますしね。即時関数
hoge.js//無名関数// const countNum = function(num) { console.log(num) } countNum(4) // 即時関数// (function countNum(num) { console.log(num) })(4)()の中にfunctionからはじまる関数定義そのものを配置することで、その関数を即実行するということができるようになります。その結果、関数を呼び出すという手間が省けるというメリットがあります!
アロー関数
hoge.js// 無名関数 const 変数名 = function(){ 処理 } // アロー関数 const 変数名 = () => { 処理 }functionの記述を省略し、その代わりに() => という記述によって関数を定義する構文です。無名関数または即時関数において、より省略した記述をしたい時に使用します!
まとめ
正直みて覚えられないなーと感じると思います。僕もそうでした。何回も書いて、考えて使うことによって覚えられるよう一緒に頑張りましょう!
- 投稿日:2020-10-26T19:12:18+09:00
TypeError: Failed to execute 'fetch' on 'Window'について
fetch apiを使おうとして躓いたのでメモ
問題
createItems() { var opt = { "method": "POST", "headers": {"Content-Type": "application/json"}, "body": { "title": "テストタイトル", "content": "テストコンテンツ" } } fetch("/create", JSON.stringify(opt)) .then((res) => res.json()) .then((res) => alert("ok")) .catch((err) => alert(err)); }TypeError: Failed to execute 'fetch' on 'Window': parameter 2 ('init') is not an object.解決方法
"init"はfetch関数の第2引数のことである。
見ると引数の値がobjectではなくstringになっていた。
なので正しい書き方はfetch("/create", opt)である。Content-Typeがjsonなのでoptもjsonにしなければいけないと勘違いしていたことが原因。
- 投稿日:2020-10-26T18:29:48+09:00
JavaScriptの超基礎的な文法を覚えておこう
変数定義の代表3つ const, let, varについて
constとは
後から書き換えることができない変数を定義する書き方です。constの特徴として、再代入、再定義ともに不可という制約があります。
その分、一番保守性が高く3つの中で一番使われる変数と言えます!letとは
後で書き換えることができる変数を定義する書き方です。letの特徴として、再代入は可能ですが、再定義は不可という制約があります。
constの次に使われており、どうしてもconstではダメなときだけ使います。あくまでconstが最優先です。varとは
再定義、再代入可能な古い書き方です。varの特徴として、再代入、再定義ともに可能です。現在は開発現場においてvarという書き方はあまり使われないです。使ったら負け!と思うぐらいでいいと思います!
配列の繰り返し処理をする関数
forEach関数
配列に格納されている要素1つひとつに対して、繰り返し処理を行う場合に用いられる関数です。なお、「関数」とはRubyでいうとメソッドと同様で思っていれば大丈夫です。
sports = ["soccer", "sumou", "baseball"]
sports.forEach( function(item) {
console.log(item) // 配列に格納されている要素の数だけ実行されます
})
上記のコードをコンソール上で実行すると、すべての要素が順番に出力されます。
引数itemには、1回目の繰り返しで「soccer」、2回目で「sumou」、3回目で「baseball」が代入されます。
そして、要素の数だけ繰り返し処理を実行すると、この繰り返し処理は終了します。
結果はこんな感じです。
soccer
sumou
baseball
テンプレートリテラルについて
テンプレートリテラルは、JavaScriptの構文です。ダブルクォートやシングルクォートの代わりにバッククォートで囲むことで、文字列内に挿入することができます。記述が圧倒的に見やすくなるので必ずJavaScriptを勉強していくなら覚えましょう!
テンプレートリテラルを使うとできることまとめ
文字列の中に変数を埋め込むことができる
改行を入れることができる
HTMLの要素を作成することができる使った場合と使わなかった場合を見比べてください
使用しないパターンcard.jsconst name = "Entaku" const age = 23 const introduction = "私の名前は" + name + "、" + age + "歳です" console.log(introduction) // => 私の名前はEntaku、23歳です と出力される }使ったパターン
card.jsconst name = "Entaku" const age = 23 const introduction = `私の名前は${name}、${age}歳です` console.log(introduction) // => 私の名前はEntaku、23歳です と出力されるテンプレートリテラルを用いることで、記述量が少なくなったことがわかります。開発では、記述量の大小はプロダクトの質に大きな差を生む事になるので、テンプレートリテラルを積極的に使用するようにしましょう!!
まとめ
JavaScriptで変数定義をする場合は、原則constとletを使用します!
変数に値を定義する際にテンプレートリテラルを使用することで、文字列の中に変数を含めることができます!
JavaScriptにおいて、配列の繰り返し処理を行う場合は、for文またはforEach()関数を使用します!
- 投稿日:2020-10-26T16:59:06+09:00
ソフトウェアやパッケージとバージョン管理に関するセンテンス
PATH
PATHとは、「環境変数」と呼ばれるOS用の変数のこと。PATHには、複数の絶対パスの情報が保存されています。
コマンドが入力されたときに、シェルはPATHに記述されたパスのディレクトリ内のファイルを検索します。つまり、PATHに絶対パスを保存してアプリケーションのありかを示せば、どこからコマンドを実行してもアプリケーションのコマンドを打つことができます。# rbenvのパスを通す % echo 'eval "$(rbenv init -)"' >> ~/.zshrc # MySQLのパスを通す % echo 'export PATH="/usr/local/opt/mysql@5.6/bin:$PATH"' >> ~/.zshrcechoコマンドは、>>に続けてファイル名を指定することで、ファイルに文字を追加できるLinuxコマンドです。.zshrcにrbenvの設定を反映するためのコマンドを記述することで、PATHを通しています。
コマンドとアプリケーションの関係
コマンドが実行されると、シェルがそれを読み取ってOSに指示を出す。
OSに初めから入っていてすぐに動作できるアプリケーションとは別に、後からPCに追加する必要があり、よく利用されるアプリケーションは、コマンドラインツールとしてまとめられています。コマンドラインツール
コマンドで操作するアプリケーションのまとまりです。
コマンドラインツールを導入することで、OSが初めからコマンドで操作できるアプリケーション以外のアプリケーションをPCにインストールできます。Command Line Tools
macOS専用のコマンドラインツールのことです。
macOSでは、元々Linuxコマンドで操作できるアプリケーションや機能を標準搭載しています。Linuxコマンド以外で操作するアプリケーションの多くはCommand Line Toolsのインストールによって、まとめてPCに導入できます。パッケージとバージョンの管理
パッケージ管理
パッケージとは、プログラムや処理をひとまとめにしたもののことです。ライブラリとも言えますが、パッケージは複数のライブラリをまとめていることもあります。
パッケージ管理とは、パッケージやパッケージが持つライブラリなどの依存関係を考慮してインストールやバージョンアップを行う管理のことです。
1つのパッケージを利用したい場合、そのパッケージと依存関係にあるパッケージも合わせてインストールしてくれます。パッケージ管理ツール
Homebrew(macOSのパッケージ管理ツール)
Yarn(JavaScriptのパッケージ管理ツール)パッケージ
Gem(Rubyのパッケージ)
Node.js(サーバーサイドで利用できるJavaScriptのパッケージ)バージョン管理
rbenv(Rubyのバージョン管理ツール)
- 投稿日:2020-10-26T16:58:09+09:00
画面で入力された注文数をグラフに反映するWebアプリ(仮)
入力された注文数をグラフに反映してみた
今日の注文数を入力したらすぐ反映されますね!
DBとか使ってなくてすぐ表示させてるだけだから!URLはこちらです!→今日までの売上を可視化しよう
使い方
一日の終わりに、今日注文された数を入力
→こんだけ増えたよって可視化される苦労した点
![]()
今回は、裏のロジックというより簡単な情報をうまく表示するところを意識しました。
・グリッドの理解をしないままbootstrapを使い始めて、表が右に行ったり、めちゃくちゃ高さが低くなったり、小さくなったり。
それもあって、ちゃんと理解をするためにこちらのサイトで勉強させていただきました。↓
bootstrapの構造について学ぶ・最初Chart.jsを使おうとしていましたが、new Chart.jsをするところで、
Vue.jsから呼び出したかったが、どう記述すればよいのかわからなかったので今回はgstaticを使いました。今回やりたかったけどできなかったこと
![]()
・DBを使ってデータの出し入れ
・月を選ぶ。今回のは10月にしか追加されない。。。
・「数値をクリア。」どこのだよ!と思うのを解消する。 今は10月の数値が根こそぎ消える。
・目標の数値の設定や、そことの差の描画
・描画方法の選定 絶対もっときれいでおしゃれなやつあるやろ!環境
エディタ:codepen
CSS:bootstrap
使用ライブラリ
vue.js
loader.js gstaticソース
HTML部分はこちら↓
<!DOCTYPE html> <html lang="en" > <head> <meta charset="UTF-8"> <title>CodePen - chart</title> <link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.0/css/bootstrap.min.css'> </head> <body> <!-- partial:index.partial.html --> <head> <script src="https://www.gstatic.com/charts/loader.js"></script> </head> <!-- 全体をVue.js有効にする --> <div class="container text-center text-white bg-dark" id="app"> <!-- タイトル行 --> <div class="row my-3"> <div class="col-sm-6 mx-auto"><h1>一日の終わりに注文数を入力</h1></div> </div> <!-- タスク入力行 --> <div class="row my-3"> <div class="col-sm-6 mx-auto"> <input v-model:value="task" placeholder="注文数を入力" class="form-control"><br> 直前に追加した注文数:{{ previous_num }} <button v-on:click="addTask" class="btn btn-primary">追加</button> </div> </div> <!-- 全てのタスクをクリアするボタン --> <div class="row my-3"> <div class="col-sm-6 mx-auto"> <button v-on:click="clearAll" class="btn btn-danger">数値をクリア</button> </div> </div> <!-- タスク追加されると表示される部分 --> <div class="row my-3"> <div class="col-sm-6 mx-auto"> </div> </div> <div class="col-lg-10 mx-auto" id="stage"></div> </div><!-- 全体ここまで --> <!-- partial --> <script src='https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.3/js/bootstrap.min.js'></script> <script src='https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.js'></script> <script src='https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.min.js'></script> <script src='https://cdnjs.cloudflare.com/ajax/libs/vue-chartjs/3.5.1/vue-chartjs.min.js'></script><script src="./script.js"></script> </body> </html>JS部分はこちら↓
//必要なパッケージの読み込み google.charts.load('current', {packages: ['corechart']}); // google.charts.setOnLoadCallback(drawChart); const app = new Vue({ el: '#app', // Vueが管理する一番外側のDOM要素 data: { // Vue内部で使いたい変数は全てこの中に定義する task: '', todoList: [['月', '数量'], ['1月', 65], ['2月', 59], ['3月', 80], ['4月', 81], ['5月', 56], ['6月', 55], ['7月', 55], ['8月', 55], ['9月', 55], ['10月', 0], ['11月', 0], ['12月', 0]], // これは配列 chart:"", previous_num:0, }, methods: { // 関数はここ addTask: function() { console.log('次のタスクが追加されました:', this.task); // 配列の先頭に現在のタスク内容を追加する(最後尾の場合はpush) this.todoList[10][1] = Number(this.todoList[10][1]) + Number(this.task); console.log('現在のToDo一覧:', this.todoList); this.previous_num = this.task; this.drawChart(); }, // 以下を追加、関数名はなんでもよい clearAll: function() { this.todoList = [['月', '数量'], ['1月', 65], ['2月', 59], ['3月', 80], ['4月', 81], ['5月', 56], ['6月', 55], ['7月', 55], ['8月', 55], ['9月', 55], ['10月', 0], ['11月', 0], ['12月', 0]]; console.log('全てのToDoが消去されました'); this.drawChart(); }, drawChart: function() { console.log('drawChart'); //オプション設定 var options = { 'title': '注文数', }; //月別データ var array = this.todoList; var data = google.visualization.arrayToDataTable(array); var stage = document.getElementById('stage'); //グラフの種類を設定 var chart = new google.visualization.ColumnChart(stage); //データとオプションを設定 chart.draw(data, options); } }, });
- 投稿日:2020-10-26T16:42:32+09:00
VSCodeでファイル保存時にPrettierを走らせる方法
はじめに
macOSを新しく買ってVsCodeをインストールし直した時にファイル保存時にPrettierを走らせる設定方法を忘れてしまい半日以上溶かした。
ググってみたけど体系的にまとまった情報がなくてなかなか時間を溶かしたので
はじめての方でも、この記事を見れば「VSCodeユーザーなら誰でもファイル保存時にPrettierを走らせることができる」ようにいちから丁寧に記事を書いた。
対象読者
- VSCodeユーザー
- ファイル保存時にPrettierが走らない人
目次
- PrettierをVSCodeにインストール
- defaultFormatterの設定を変更する
- Format On Saveにチェックを入れる
- Settings及びPluginを反映させる為にいったん画面をReloadする
1. PrettierをVSCodeにインストール
VSCodeからインストールする方法とブラウザからインストールする方法がある。
VSCodeを立ち上げて、Prettier -Code formatter の拡張機能タブが表示されたら、[インストール]ボタンをクリックする。これでPrettierが有効になります。
VSCodeからではなく以下のリンクから「install」ボタンをクリックしてもいけます。
Prettier下の画像のように、VSCodeのインストール済みのところにあればOK。
2. defaultFormatterの設定を変更する
まず、VSCodeの設定画面を開く
開くには画面左下の
アイコンから「Settings」を選択すればいい
ちなみにショートカットキーを使えば一発で開けるので参考まで
(macOSの場合 : 「 command + , 」 windowsの場合 : 「 ctrl + , 」)
最後に「Default Formatter」を「null」から「esbenp.prettier-vscode」に変更する
3. Format On Saveにチェックを入れる
次に「Format On Save」にチェックマークを入れる
4 Settings及びPluginを反映させる為にいったん画面をReloadする
これをやらないと設定が反映されないから注意!
「command + shift + P」でコマンドパレットを開き
「Reload Window」をクリックして画面をリロードさせる(windowsの場合「ctrl + shift + P」でコマンドパレットを開ける)
まとめ
これでファイル保存時にPrettierが走るはず。Just do it!
参考文献
Vscode上でファイル保存時にPrettierを走らせる
デフォルト整形ツールにPrettierを使う
Prettier入門 ~ESLintとの違いを理解して併用する~
- 投稿日:2020-10-26T16:37:55+09:00
Tabulatorを使ってみた
AM送信所マップを作ってみたのjsonをTabulatorで表にしてみました。
ローカルファイルからgistのrawデータを読むとCORSのエラーが出るのでTabulatorのajaxは使わず、一旦jqueuryでデータを取得してから、Tabulatorに渡すようにしてみました。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>AM DX LIST</title> <script src="https://code.jquery.com/jquery-3.1.1.min.js"></script> <link href="https://unpkg.com/tabulator-tables@4.4.3/dist/css/tabulator.min.css" rel="stylesheet"> <script type="text/javascript" src="https://unpkg.com/tabulator-tables@4.4.3/dist/js/tabulator.min.js"></script> <script> function init() { $.getJSON("https://gist.githubusercontent.com/yamori813/16065bbff4473e8ec3430570fcf7da7f/raw/radio.json", null, function(data,status){ //取得成功したら実行する処理 var tableData = data.radio; var table = new Tabulator("#example-table", { data: tableData, columns: [ { title: "略称", field: "name" }, { title: "会社", field: "corporation" }, { title: "コールサイン", field: "callsign" }, { title: "周波数", field: "frequency" }, ] }); }); }; </script> </head> <body onload="init()"> <div id="example-table"></div> </body> </html>周波数でソートできるのは便利です。
- 投稿日:2020-10-26T16:06:53+09:00
【JS】やっと分かった、クロージャー。
はじめに
【対象】
・クロージャーについて何度も調べて、実践しているが、なかなか理解できない人・グローバル変数とローカル変数の違いはわかる人
・グローバル変数を出来るだけ使わないようにするのは分かるけど、やり方が分からない人
そもそも、クロージャーとは?
クロージャは、関数と、その関数が宣言されたレキシカル環境の組み合わせです。
MDNより要は、
「関数を囲むスコープにある変数を参照できる関数」の事。
クロージャーの特徴
①関数が呼ばれるたびに結果が変わる事
②グローバル変数を減らすことで、他のプログラムからの干渉を受けずらく出来る
③処理回数が減らすことが出来る(※重要)
④レキシカルスコープの言語で使うクロージャーの特徴について説明する前に。
まずは、レキシカルスコープとダイナミックスコープの違いからの説明です。
(分かる人は飛ばしてください。)・レキシカルスコープとダイナミックスコープ
①レキシカルスコープ
→関数を定義した時点でスコープが決まる。
↓コードで説明
sample.jsvar x = 10; function A(){ console.log(x); } function B(){ var x = 1000; A(); } A(); // 10 B(); // 10
function A(){}
として関数定義した時点で参照していたxが代入されている。・メジャーな言語(JSなど)で採用される。
②ダイナミックスコープ(Perl等の言語)
実行時>定義時
→関数定義時にもスコープは決まるが、実行時のスコープ優先。
sample.jsvar x = 10; function A(){ console.log(x); } function B(){ var x = 1000; A(); } A(); // 10 B(); // 1000クロージャーについて1からの説明
先程、記載した通り、
クロージャーとは、
関数を囲むスコープにある変数を参照できる関数の事です。コードで説明すると、
sample.jsfunction outer() { let place = '大阪'; console.log(place); function inner() { alert(place); } return inner; } let Func = outer(); Func();上から順に説明していきます。
(基本的な所まですべて記述します)・
let place
:outer(){}
のローカル変数。(※outer()
実行時以外は参照できない)・
console.log(place);
:outer();
で実行される・
function inner() {}
:これが、クロージャーです。・
alert(place);
:Func();
で実行される。・
let Func = outer();
:ここで、outer();
が実行され、また、inner()
がクロージャーとなって、代入されている。ここで分かった、クロージャーの性質は、
outer()が実行されていないのに、outer()内の変数placeが参照される事です。
【上記コード:ここまでの流れのまとめ】
let Func = outer();
とFunc();
で関数の実行を行っている
↓
let Func = outer();
の定義でのみ、outer()
が実行され、console.log(place)
が実行される
↓
let Func = outer();
の定義でinner()
がクロージャーとして代入される
↓
Func();
でinner()
の中身を実行【特徴①】関数が呼ばれるたびに結果が変わる事について
~【今回行う事】~
関数を呼び出すたびに、数が増えていく処理を行います。通常の関数では?
【通常】
sample.jsfunction outer() { let count = 1; count++; console.log(count); } outer(); // 2 outer(); // 2 outer(); // 2上記のコードでは、
outer();
を何度実行しても呼び出されるたびにcountには1
が代入されるため同じ結果しか得れません。【クロージャー使用】
sample.jsfunction outer() { let count = 1; console.log(count); function inner() { count++; console.log(count); } return inner; } let sum = outer(); // 1 sum(); // 2 sum(); // 3 sum(); // 4実現できました。
【特徴②】グローバル変数を減らすことで、他のプログラムからの干渉を受けずらく出来るについて
【特徴①】のコードと数字の増えるプログラムで説明すると、
下のようなコードでも動くのでは?
sample.jslet count = 1; console.log(count); function outer() { count++; console.log(count); // 1 } outer(); // 2 outer(); // 3 outer(); // 4
let count = 1;
を関数の外で定義しています。グローバル変数として定義した場合も、思い通りの処理が完成しました!
しかし、
これでは、クロージャーを勉強している意味はありません。
そもそも、クロージャーを使う目的の一つとして
グローバル変数を使わないようにすることで、他のプログラムからの干渉を受けずらくという事があげられます。
グローバル変数を使うことで、変数名が被った際に参照先の違いで思わぬエラーが発生する可能性もあります。
上記のコードでは、グローバル変数
count
にアクセスしていますそれをしないために、クロージャーを使ってカプセル化を行います。
【クロージャー使用】
sample.jsfunction outer() { let count = 1; console.log(count); function inner() { count++; console.log(count); } return inner; } let sum = outer(); // 1 sum(); // 2 sum(); // 3 sum(); // 4何となくメリットが分かってきたような??
【特徴③】処理回数を減らす
→【特徴】の部分でも記載した通り、クロージャーを使うことで、処理回数を減らすことにもつながります。
「クロージャーについて1からの説明」にあるコードを少し変えたのコードで説明します。
【クロージャーなし】
sample.jsfunction outer() { let place = '大阪'; let word; // console.log(place); if(place === '大阪') { word = 'せやな!'; } else { word = 'ちゃうやん'; } window.alert(word) } outer();上記のコードだと、
outer();
が呼び出されるたびに毎度ifで処理しないといけません。しかし、、、
【クロージャーを使うと?】
sample.jsfunction outer() { let place = '大阪'; let word; // console.log(place); if(place === '大阪') { word = 'せやな!'; } else { word = 'ちゃうやん'; } function inner() { window.alert(word) } return inner; } let Func = outer(); Func();
let Func = outer();
で一度if分の条件分岐の処理を行った後は、Func();
を何度実行しても呼び出されるのは、inner()
内部だけです。見事に、クロージャーの使用で処理回数を減らすことを実現できました!
【おまけ】これは無理なん?と思ったもの
①returnではなく、関数定義内で関数実行
sample.jsfunction outer() { let count = 1; console.log(count); // 1 function inner() { count++; console.log(count); } inner(); // 2 } outer(); // 1 2 outer(); // 1 21 2 1 2上記のコードでは、
outer()
実行時にouter()
内でinner()
が実行されてしまっています。関数を実行するたびに
count = 1
にcount++;
しているだけです。②少し書き方をかえると?
sample.jsfunction outer() { let count = 1; console.log(count); return function inner() { count++; console.log(count); } } let sum = outer(); // 1 sum(); // 2 sum(); // 31 2 3何が変わったか?・・・
return
を移動させて、function inner()
の前に付加しただけです。勿論、変わらず動きます。
続いてこちら、
sample.jslet outer = (function() { let count = 1; console.log(count); return function inner() { count++; console.log(count); } })(); outer(); // 2 outer(); // 39行目の最後の
()
でouter
を実行。その後、
outer()
でinner()
を実行しています。こちらも、
outer()
と`inner()
で切り離して実行できます。まとめ
クロージャーを使うことで、
・グローバル変数を減らすことで、他のプログラムからの干渉を受けずらく出来る
・処理回数が減らすことが出来る
参考
- 投稿日:2020-10-26T15:29:22+09:00
[Java] 配列からランダムに値を取得する
- 投稿日:2020-10-26T14:07:43+09:00
babel-loader、eslint-loader、ts-loader比較
webpackを使ってJavascriptとTypescriptのどちらも自由に使える開発環境を作ろう!となったとき、この3つのローダーは機能が重複していたりして「どう使い分けたら…」と悩んだため比較しました。
欲しい機能
- .ts、.jsファイルそれぞれlintしてほしい
- TSをJSにコンパイルしてほしい
- ECMAScript5に変換してほしい
結論から言うと
eslint-loader(2020年10月現在非推奨。代替としてeslint-webpack-pluginを推奨)で
- .jsファイルの静的コード分析ts-loaderで
- JavascriptとTypescriptをECMAScript5にコンパイル
- .tsファイルの静的コード分析以上2つのローダーを使用することにしました。
ローダーの特徴を比較
babel-loader
- JavascriptのES2015、ES2016、ES2017、ES2019、ES2020の構文をECMAScript5に変換
- プリセット「@babel/preset-typescript」によってTypescriptもコンパイル可能
eslint-loader(eslint-webpack-plugin)
- Javascriptを静的コード分析
ts-loader
- TypescriptをECMAScript5に変換
- Typescriptの静的コード分析
- tsconfigで"allowJs":trueとした場合Javascriptもあわせてコンパイル(ECMAScript5に変換)可能
導入の際に迷った要素を太字にしました。
こう見ると、ts-loaderとbabel-loaderどちらを選んでも機能の差をあまり感じない気がします。(あくまでTSとJSどちらも使用したい、という環境構築が目的の場合)各設定のコードはこんなかんじ。
webpack.config.jsmodule.exports = { module: { rules: [ { test: /\.(js|ts)$/, //ts-loaderでは拡張子.js、.tsどちらも監視 exclude: /node_modules/, loader: "ts-loader" }, { test: /\.(js)$/, exclude: /node_modules/, loader: 'eslint-loader', }, }, resolve: { extensions: [ '.ts', '.js', ], }, };tsconfig.json{ "include": [ "src/scripts/**/*" //対象にしたいディレクトリを指定 ], "compilerOptions": { /* Visit https://aka.ms/tsconfig.json to read more about this file */ /* Basic Options */ "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ "module": "es2015", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ "lib": [ "es2018", "dom" ], /* Specify library files to be included in the compilation. */ "allowJs": true, /* Allow javascript files to be compiled. */ // "checkJs": true, /* ここをtrueにするとTypescriptのlintが.jsにもかかるので注意。Report errors in .js files. */ "sourceMap": true, /* Generates corresponding '.map' file. */ "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ /* Strict Type-Checking Options */ "strict": true, /* Enable all strict type-checking options. */ /* Source Map Options */ "inlineSources": true /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ } }.eslint.json{ "extends": ["eslint:recommended"], "plugins": [], "parserOptions": { "sourceType": "module", "ecmaVersion": 2015 }, "env": {"browser": true}, "globals": {}, "rules": {} }重要なのは
tsconfig.json
のallowJs: true
と、webpack.config.js
でeslint-loader
でjsをlintしてからts-loader
が走るような順番で記述することだと思います。
eslintの設定は好みに応じて変更してください。完成してから思ったのは、babelは開発が活発そう、@babel/preset-typescriptも安心して使えそう、ということでした。。
とはいえ上記組み合わせでも十分求めていた動きをしてくれたので、試しに使ってみてください!JS初学者が試行錯誤の末行き着いた結果です。色々ご容赦いただければと思います。
- 投稿日:2020-10-26T13:19:57+09:00
ShortcutsによるiOSのSafari向けブラウザ拡張機能作成
概要
iOSでもBookmarkletによってSafariで閲覧中のページのDOMなどにアクセス可能なことはよく知られていますが、Shortcutsでも似たようなことが可能ですので、Bookmarkketと比較した場合のメリット・デメリットと併せて、簡単なサンプルを紹介します。
Bookmarkletとの比較
メリット
- 外部アプリとの連携が可能
- JavaScriptの実行だけに留まらず、Shortcutsに対応している様々なアプリケーションとの連携が可能です
- 配布が容易
- 共有リンクなどを利用して、作成したShortcutを他のユーザに配布することが出来ます
- Safariの共有メニューから実行可能
- Bookmarkの一覧からではなく、一般的なアプリと同様に共有メニューから選択して実行することが出来ます
- Safariだけでなく、TwitterやDiscordなどの内蔵ブラウザ(WebView?)からでも実行可能
デメリット
- Shortcutsアプリのインストールが必要
- 閲覧中のページ内JSで定義された変数へアクセスできない? (DOMへのアクセスは可能ですが、ページ内のJSとは別のスコープで実行されているのかも知れません)
※ 適宜追記します
準備
- Shortcutsアプリをインストールしていない場合はAppStoreからインストールする。
- 自身が作成したShortcut以外を実行する場合は、信用されていないShortcutの実行を事前に許可する
実践
Safariで閲覧中のWebページのタイトルとURLをTwitterへ投稿するShortcutを作成してみます。
- Shortcutsアプリを開き右上の「+」をタップ
3. 「Show in Share Sheet」をタップし、ブラウザの共有メニューから実行可能にする
4. 「Share Sheet Type」から「Safari web pages」のみを選択して、右上の「Done」をタップ
5. [+ Add Action]をタップし、「Run JavaScript on Web Page」を選択
6. 「Web Page」をタップし、「Shortcut Input」を選択let result = {}; result.title = document.title; result.href = document.location.href; completion(result);
- 「+」をタップして「Twitter」を選択
- 作成したShortcutのタイトルを設定して「Done」をタップ
12. My Shortcutsの一覧に保存されたことを確認する
13. Safariで任意のページを開き、共有ボタンをタップし、作成したShortcutを選択
- 初回実行時にページへのアクセス許可を求められるので許可する
- 閲覧中ページのタイトルとURLが入力された状態のツイート画面に遷移する
まとめ
- ShortcutsアプリからでもBookmarkletの様に、閲覧中のWebページに対してJavaScriptの実行が可能
- 外部のアプリケーションと連携したブラウザ拡張機能を、iOS端末単体で作成可能
- 投稿日:2020-10-26T11:09:27+09:00
DOM操作系 まとめ
DOM(Document Object Model)とは、マークアップ言語(HTML,CSS)で書かれたドキュメントにアクセスするための標準的な仕組み。
DOMではドキュメントを文書ツリー(ドキュメントツリー)と言う、ツリー構造として扱う。1つ1つの要素をノードと呼び、要素ノード、属性ノードなど種類別に呼称する。あるHTMLのdivタグの文章を変えたいとなると
- 要素ノードを取得
- 直接取得
- 文書ツリー間の行き来
- イベントドリブンモデル
- 属性値やテキストを取得・設定
- 取得・設定
- フォームタグ
- ノードを追加・置換・削除
と言う順序をもって、HTMLに対して更新していく。
要素ノードの取得
取得のためには、id,タグ名、class,セレクター方式があり、取得するデータが単数か複数かで扱い方やメソッドが複数になるかが変わるので注意!
直接取得
メソッド 概要 getElementById(id) id値をキーとして要素を取得 querySelector(selector) セレクター※後述参照でより複雑な条件で検索する。戻り値は1つで、複数ある場合は一致した最初の値を返す。 querySelectorAll(selector) querySelectorの複数版、一致した全ての要素を返す getElementsByTagName(name) タグ名をキーとして一致したものを返す。複数出る可能性があるので複数形になっている メンバー:length(要素数),item(i)(i番目の要素),namedItem(name)(id,name属性が一致する要素) getElementsByClassName(class) class値をキーとして要素を取得複数ある場合があるため複数形
セレクター 概要 * 全ての要素を取得 #id 指定したid要素を取得 .class 指定したclass要素を取得 * 全ての要素を取得 など多くあるので、都度調べた方がいいと思います。
getXxxxxとqueryXxxxxメソッドの違い
getXxxxxは高速、queryXxxxxは低速と言う処理速度の違いはあるものの、試行回数が多い場合にしか差は出てこず、場合によってはqueryXxxxxの方が簡潔に記述できるので、都度必要に応じて使い分ける。
文書ツリー間の行き来
文書全体から指定のノードを探すことはパフォーマンスの低下になります。そこでDOMではある起点から相対的な位置で探すことができます。これがノードウォーキングと言われるノード間を移動していくやり方です。
コードは長くなりますが、小回りが効くので
getXxxxx/queryXxxxxで特定した後、近接するノードはノードウォーキングで取得する
ことが一般的である。基準となるノードに対して
プロパティ 概要 parentNode 親ノード previousSibling/nextSibling 兄/弟ノード previousElementSibling/nextElementSibling 兄/弟の要素オブジェクトを返す firstChild/lastChild 子の最初のノードから最後のノードを順次に取得する firstElementChild/lastElementChild 子の最初の要素オブジェクトをから最後の要素オブジェクトを順次に取得する childNodes 子のノード郡を返す Elementが付いていないものは要素以外の改行や空白のテキストノードも取得してしまう。
そのため、 nodeType プロパティで調べる必要がある。nodeTypeの返り値の数値と対応表
戻り値 概要 戻り値 概要 1 要素ノード 7 処理命令ノード 2 属性ノード 8 コメントノード 3 テキストノード 9 文書ノード 4 CDATAセクション 10 文書型宣言ノード 5 実体参照ノード 11 文書の断片 6 実体宣言ノード 12 記法宣言ノード イベントドリブンモデル
HP上では、イベントを基準として特定の処理を開始する。このモデルのことをイベントドリブンモデルと言う。イベントには、click,load,scrollなど多くの種類がありこのイベントが処理の発火基準となる。そして、このイベントをもとに発火される処理のことをイベントハンドラー・イベントリスナーと呼ぶ。違いは書き方で以下参照
定義の仕方は以下の手順となる。
- どの要素で発生した
- どのイベントを
- どのイベントハンドラー・イベントリスナーに紐付けるか
となり、書き方は以下のよ3つがある
- タグ内に直接記入 (イベントハンドラー)
- 要素オブジェクトのプロパティとして宣言 (イベントハンドラー)
- addEventListenerメソッドを使う (イベントリスナー)
タグ内に直接記入
タグ内に直接記入するのは、本当に簡単な処理のみの場合となるが、基本的にコードの可読性から「ページ構成と処理とは明確に分離させる」と言う考えからあまりしない方がいい。
例<input type="button" value="ダイアログ表示" onclick="window.alert('ボタンが表示されました。');"/>イベントをonイベント名="JSのコード" と書く。
要素オブジェクトのプロパティとして宣言
HTMLとJSのファイルに分けて、ページ構成と処理を分離させる。
例<input id="btn" type="button" value="ダイアログ表示" />window.onload = function(){ document.getElementById('btn').onclick = function(){ window.alert('ボタンがクリックされました'); }; };getElementByIdにおいてid指定で要素を取得、onclickでクリックイベントに =function で処理の関数と定義している。
onloadはページが全て読み込まれた際に実行されるイベントハンドラーを登録している。addEventListenerメソッドを使う
上記まででかけるのでは?addEventListenerは何のためにあるのか?と思うが、その違いは
・onxxxxは同一要素/同一のイベントに対して、複数のイベントハンドラーを紐付けられない
・addEventListenerは複数のイベントリスナーを紐付けられる
と言う違いがあります。イベントに複数のイベントリスナーを定義したい場合はこちらを使う。
書き方は、少し変わってくるので注意<input id="btn" type="button" value="ダイアログ表示" />document.addEventListener('DOMContentLoaded',function(){ document.getElementById('btn').addEventListener('click',function(){ window.alert('ボタンがクリックされました'); },false); },false);となる。「DOMContentLoaded」はonloadと同じだが、
・onloadは全てのページを読み込んでから処理を実行
・DOMContentLoadedはコンテンツ本体がロード(画像のロードを待たない)されたところで実行
と言う違いがあり、後者の方が処理が早くなる。基本は後者を使う。addEventListener('イベント名','処理','イベントの方向')と書く。
以上が、DOMにおいての要素の特定方法となる。これをもとに次は値の取得や設定を行う。
→ 次回:属性値やテキストの取得
- 投稿日:2020-10-26T10:03:24+09:00
Transform Feedbackの勉強の一環で、弊社ロゴをパーティクルにしてみた。
初めに
初めまして。ディップ株式会社に20新卒で入社したWebフロントエンドエンジニアの@tato_lolです。
さて、皆さんは弊社の公式サイトを見たことがあるでしょうか?
https://www.dip-net.co.jp/
サイトにアクセスすると、真っ先に目に入るのが、パーティクルで形成されたディップのロゴマークだと思います。実はこのサイトは皆さんもおなじみのWebGL総本山で紹介されたこともあるサイトで、独特の粘性のあるパーティクルを持ち、websocketを利用して利用者が動かしたパーティクルの座標が他の利用者の画面にも反映されるようになっています。
現状でも中々に魅力的な実装だと思いますが、
僕みたいな頭空っぽマンは
「パーティクルいっぱい!!!」とか
「すっごい動く!!!」とか
「60FPS!!!」
みたいな分かりやすくてパワーみのある指標が欲しいので(???)、
WebGL2から追加されたTransform Feedbackを使っていい感じに弊社のロゴを動かしてみようと思います。Transform Feedback とは?
僕が説明するまでもなく、諸先輩方が素晴らしい解説・サンプルを残してくださっているので、
まずはこちらをご覧になっていただくのが良いと思います。
- wgld.org | WebGL2: Transform Feedback の基礎 |
- サンプルで理解するWebGL 2.0 - Transform Feedbackによるパーティクル表現 - ICS MEDIA
自分なりの説明
私の説明は、「とりあえず記事を読むためになんとなくの概要だけ教えてくれ!」という方向けの説明にとどめます。
まず、ざっくり説明すると、
Transform Feedback =「GPUの計算結果を使い、頂点データを更新することが出来る機能」です。これがどういうことなのかというと、今までWebGLにおけるレンダリングの流れは一方通行で
以下のような形になっていました。従来のWebGLにおけるレンダリング1. CPUからGPUに頂点データを送信 2. 頂点シェーダ―で頂点データの計算 3. 計算結果をラスタライズ(ピクセルに起こす) 4. フラグメントシェーダでピクセル計算これが、Transform Feedbackを使うことにより、
以下のような形になりました。WebGL2におけるTransformFeedbackを使ったレンダリング1. CPUからGPUに頂点データを送信 2. 頂点シェーダ―で頂点データの計算 3. 頂点データを更新 4. 計算結果をラスタライズ(ピクセルに起こす) 5. フラグメントシェーダでピクセル計算さらに、頂点データ更新以降の処理をスキップできるようになったため、
このような形にもできます。WebGL2におけるTransformFeedbackを使ったレンダリング(短縮)1. CPUからGPUに頂点データを送信 2. 頂点シェーダ―で頂点データの計算 3. 頂点データを更新Transform Feedbackを使うメリット
従来までは、頂点データは最後まで一方通行に描画されたグラフィックスを更新する形で処理を行う必要がありました。
まず、これがラスタライズ以降の処理をスキップできるようになったことで描画を行わず計算のみを行うことができ、より効率的に処理できるようになりました。
加えて、ここでは深く説明しませんが、VBOの中身を直接GPUで変更できるようになったため、よりシンプルに頂点を扱えるようになりました。本題
では、実際に作成したものがこちらになります。
DEMO:https://yoheisuda.github.io/my-transform-feedback-sample/こちらは、h_doxasさんのwgld.org | WebGL2: Transform Feedback で GPGPU |を参考に作成したものです。
Transform Feedbackを使うことにより、Intel UHD Graphics 620という
クソザコGPUの私のPCでも、
60FPSを保ちつつ、160,000パーティクルを飛ばすことが出来ました。実装
参考にさせていただいたサンプルとそこまで変わりません(大きな違いとしては座標のリセットを加えた部分ぐらいかと思います)が、
var VBOArray = [ create_vbo(position), create_vbo(velocity), create_vbo(color), create_vbo(resetPos) ];このようにVBOを定義し、
set_attribute(VBOArray, attLocation, attStride); gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, VBOArray[0]); gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 1, VBOArray[1]); gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 2, VBOArray[2]); gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 3, VBOArray[3]); gl.enable(gl.RASTERIZER_DISCARD); gl.beginTransformFeedback(gl.POINTS); gl.uniform1f(uniLocation[0], nowTime); gl.uniform2fv(uniLocation[1], mousePosition); gl.uniform1f(uniLocation[2], mouseMovePower); gl.uniform1f(uniLocation[3], resetFlg); gl.drawArrays(gl.POINTS, 0, imageWidth * imageHeight); gl.disable(gl.RASTERIZER_DISCARD); gl.endTransformFeedback(); gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, null); gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 1, null); gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 2, null); gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 3, null);render関数の中で、Transform Feedback を実行し、
処理が終わった後、閉じるという形で実装しています。より詳しい中身については、下記のサンプルを見て頂ければと思います。
https://github.com/YoheiSuda/my-transform-feedback-sampleまとめ
Transform Feedback使うと、軽量に多くのパーティクルを動かせるので良いですね。
まだまだ自分で理解できていない部分も多いため、これからも勉強していきます。お読みいただきありがとうございました。
- 投稿日:2020-10-26T09:22:15+09:00
連想配列をJavaScriptで要素を簡易的に追加する
メモ用。
連想配列のに要素をforEach等で配置するconst arr = [
{name: 'aaa', image: "aaa.JPG", disc: 'text~'},
{name: "bbb", image: "bbb.JPG", disc: 'text~'},
];function viewList(content, cls) {
const list = document.createElement('li');
const img = document.createElement('img');
if (cls === 'toImage') {
img.classList.add(${cls}
)
img.src = content;
} else {
list.classList.add(${cls}
);
list.textContent = content;
}
list.appendChild(img);
ul.appendChild(list);
}arr.forEach(ar => {
viewList(ar.name, 'class名');
viewList(ar.image, 'class名');
viewList(ar.disc, 'class名');
})
- 投稿日:2020-10-26T08:05:07+09:00
JSONをconsole.logで整形して表示する(JSON.stringifyでインデント付き展開)
はじめに
JSONデータをインデントと改行で整形して
console.log()
で出力します。
方法は、JSON.stringify()に3つの引数を指定するだけで簡単です。
- PHPのvar_dumpやprint_rのようなことをしたい。
のような場合に便利に使えます。
JSON.stringify()を使う
構文JSON.stringify(JSONオブジェクト, null, インデント数);まず、JSON.stringify()で指定できる3つの引数を簡単に確認しておきましょう。
第1引数:jsonオブジェクトを指定します。
第2引数:replacerといってコールバックを指定できますが、今回は整形用にnullを指定します。
第3引数:数値を指定すると、指定数の空白文字でjsonオブジェクトをインデント整形します。サンプル
インデントで整形
javascript// JSONオブジェクト var obj = { "name": "taro", "date": "2020-10-25 12:30:18", "item": [ "ラーメン", "チャーハン", "餃子" ] } // 空白2文字でインデントして整形出力(インデントの個数:2) console.log(JSON.stringify(obj, null, 2));インデントの個数は「2」にしています。
console.log(){ "name": "taro", "date": "2020-10-25 12:30:18", "item": [ "ラーメン", "チャーハン", "餃子" ] }
タブで整形
javascript// JSONオブジェクト var obj = { "name": "taro", "date": "2025-10-20 12:30:18", "item": [ "ラーメン", "チャーハン", "餃子" ] } console.log(JSON.stringify(obj, null, '\t'));第3引数に
'\t'
と指定すれば、タブによるインデントも可能です。console.log(){ "name": "taro", "date": "2020-10-20 12:30:18", "item": [ "ラーメン", "チャーハン", "餃子" ] }
整形をしない場合
第1引数のみ指定// JSONオブジェクト var obj = { "name": "taro", "date": "2020-10-25 12:30:18", "item": [ "ラーメン", "チャーハン", "餃子" ] } // 第1引数のみ指定 console.log(JSON.stringify(obj)); // 出力結果 {"name":"taro","date":"2020-10-25 12:30:18","item":["ラーメン","チャーハン","餃子"]}整形の必要がない場合は、第1引数のみで指定OK。
オブジェクトの中身を確認したい
javascriptvar obj = { "name": "taro", "date": "2020-10-25 12:30:18", "item": [ "ラーメン", "チャーハン", "餃子" ] } console.dir(obj);[object Object]で出力される、オブジェクトの中身を確認したい場合は
console.dir()
を使うと便利です。console.dir()Object date: "2020-10-25 12:30:18" item: Array(3) 0: "ラーメン" 1: "チャーハン" 2: "餃子" length: 3 __proto__: Array(0) name: "taro" __proto__: Object
コンソールで展開して、このように表示できます。
参考
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
- 投稿日:2020-10-26T07:19:46+09:00
windowオブジェクトを超ミニマムに解説してみる
超ミニマムシリーズとは
様々な事柄に関して超短く解説するシリーズです。
これを読んであなたの興味が沸き、その飽くことのない知識欲を満たすことを願っています。windowオブジェクトとは
「ブラウザに標準で用意されているグローバルなオブジェクト」
意識していないだけで必ずwindowオブジェクトは使っている
皆さんが何気なく使っている関数やメソッドは、windowオブジェクトの中のものを使っている場合が多いです。
例えば次のコードmain.jsalert('hello');↑の
alert()
は文字通り、ブラウザ上で警告文を出すためのメソッドです。
実はこのalert()
の先頭には隠れてるコードがあって、それがwindow
オブジェクトです。
つまり、main.jswindow.alert('hello');↑のように書いても同じ結果になります。
普段はこのwindow.
の部分を省略してるということですね。main.jsconsole.log(window);試しに
console.log(window)
でwindowオブジェクトを見てみると
このように多くの関数やプロパティなどが出てきます。その中にalert
もあります。おまけ(グローバルなオブジェクトとは)
「どこからでもアクセスできるオブジェクト」
windowオブジェクトはどこからでもアクセスできるので省略して書けるということです。