20191008のJavaScriptに関する記事は30件です。

Android版Chrome(ver77)でブラウザのcomfirmダイアログが消える原因

現象

フォームの入力画面において、ボタンをタップするとwindow.confirmダイアログが一瞬表示されたのちに消える。
→ダイアログのOKボタンでformのPOST送信処理を実行しているので送信できない!
確認した端末:Android(6,7,8)版chrome(ver77)。

※iOS版は未確認。
Android版chrome(ver76)では発生しませんでした。

原因はFacebook Pixel

こちらの記事と同じ条件で発生しました。
Facebook Pixel CodeとGoogle Chrome75の相性が良くない件について

ボタンをクリックした時にFacebook PixelのPOSTが悪さをしています。
Facebook Pixelとは

Facebook Pixelはページ内のどのjsが呼び出しているのか?

ページ内の管理担当外のどこかに埋め込まれた<script>タグが怪しいのでChrome Developer Toolsを使ってつきとめます。
マーケティング担当領域の計測関連のjsが呼び出していました。
developer.png
1. [Network]パネルを開き、左のFilterとある入力欄にfbevents.jsと入力
2. Initiator列を見る。(fbevents.jsの呼び出し元が表示されている)
3. 呼び出し元のjsがHTMLの<script src="~.js">に記述されていなければ、更にそのjsのInitiatorを確認
※ページのソース内の<script src="~.js">にたどり着くまで繰り返す

対処方法

  1. そのページだけfbevents.jsを呼び出さないように修正する
  2. Facebook Pixelのコードをカスタマイズする。(特定のボタンだけイベント追加させるなど)
    対応方法参照:Facebook ピクセル のコード埋め込みについてメモ Facebook Pixel Advanced
  3. confirmのOKボタンを押した後のPOST送信処理を修正する
    対応方法参照:Facebook Pixel CodeとGoogle Chrome75の相性が良くない件について

参考

この記事は以下の情報を参考にしました。大変お世話になりました。
- Facebook Pixel CodeとGoogle Chrome75の相性が良くない件について

- Facebook ピクセル のコード埋め込みについてメモ

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScript Arrow Function

This tutorial help to understand arrow function of EcmaScript 6.The arrow function is an anonymous function, that does not have function and return keyword.

https://www.es6tutorials.com/javascript-arrow-function/

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

10分でわからるVue.js-超入門

はじめに

皆さん、こんにちは!Webシステム開発エンジニアの蘭です!
今日はVue.jsについて語りたいと思います。

昔Webシステム開発技術が始まった時、バックエンドではPHPやRubyを使い直接OracleやMySQLの内部のデータベースにSELECT,INSERT,UPDATE,DELETEを実行してた時代でした。

それが今はSaasの時代になり、内部データを直接弄るだけではなく、
フロントバックエンドの合化、外部連携の柔軟性が整ってる便利なREST APIファースト開発が主になり、フロントで「サイト更新の速度」や直感的なリ「アルタイムの更新」がサイト品質に関してもはや欠かせない物になりました。
 参考:APIファーストで開発する7つのメリット

やりたいこと:【サイト更新速度の向上、直感的なアルタイムの更新】

バックエンドではサーバーに対するリクエストはAPIでプロパティを渡し、
フロントではJavascriptを使い、最小限の範囲で非同期にVirtual DOMを更新する事が現在APIファーストの開発では重要な事です。

 参考:
   JavaScript初心者でもすぐわかる!DOMとは何か?
   VirtualDOMの仕事ってなに?表示速度がはやい理由

何故Vue.js

理由は比較的に簡単

・Javascriptがあまり分からない初心者でも学べるJavascriptフレームワーク
・単一ファイルコンポーネントで、HTML、CSS、Javascriptが同一のファイルで管理できる。
alt

もちろん、自分に合ったJavascriptフレームを選択するのが一番ですね。  
参考:
   JavaScript: フレームワーク React/Vue/Angularについて
   Vue・React・Angularのパフォーマンス比較検証

始めよう!Vue.js

Vue.jsって何?

・Webアプリケーションでユーザーインターフェースを構築するため、オープンソースのJavascriptフレームワーク。
・Axios等他のJavascriptライブラリが導入できる。
・高機能なシングルページアプリケーション(SPA)を構築することができる。
・vue-routerやvue-validation,vuex等組み合わせることで、大規模なWebアプリ開発のニーズまでサポートする統合的な環境を提供し、作者Evan氏の「Progressive Framework」の概念を活かす。
・ECMAScript 5をベースに、現在のブラウザーではほぼ使える。
参考:
   作者Evan氏のVue.js Progressive Framework
   ECMAScript 5
   ES5とES6の違いをまとめてみた

Vue.jsのインストール

こちらについては以下の公式記事を参考してください。
   Vue.jsのインストール

実際の開発ではnpmでインストールしますが、練習用はCDNでもできます。

Vue.js_cdn
 <script src="https://cdn.jsdelivr.net/npm/vue@2.6.0"> 
 </script>

ドキュメント

Vue.jsは日本語版で、内容は充実。
 Vue.jsの公式マニュアル

1.Hello World

【以下のコードはこちらの記事を引用してます。】


See the Pen
Vue_Hello World
by Uramaya (@uramaya)
on CodePen.


2.テンプレート

v-if / v-else-if / v-else

See the Pen Vue_Template by Uramaya (@uramaya) on CodePen.

See the Pen Vue_Template_V-if_2 by Uramaya (@uramaya) on CodePen.

v-show

See the Pen Vue_Template_V-Show by Uramaya (@uramaya) on CodePen.

繰り返し:v-for

See the Pen Vue_Template_V-for by Uramaya (@uramaya) on CodePen.

3.クラスとスタイル

HTMLクラス

See the Pen Vue_Template_V-HTMLClass by Uramaya (@uramaya) on CodePen.

style属性

See the Pen Vue_Template_V-Style by Uramaya (@uramaya) on CodePen.

4.フォーム入力

テキストボックス、エリアに文字入力

See the Pen Vue_Template_V-From-text by Uramaya (@uramaya) on CodePen.

セレクトボックス

See the Pen Vue_Template_V-SelectBox by Uramaya (@uramaya) on CodePen.

チェックボックス

See the Pen Vue_Template_V-From-checkbox by Uramaya (@uramaya) on CodePen.

ラジオ

See the Pen Vue_Template_V-From-radio by Uramaya (@uramaya) on CodePen.

ファイル

See the Pen Vue_Template_V-From-file by Uramaya (@uramaya) on CodePen.

その他

See the Pen ExxaOXz by Uramaya (@uramaya) on CodePen.

5.イベントとmethods

タブ -click

See the Pen Vue_Template_V-Click by Uramaya (@uramaya) on CodePen.

フォーム -submit

See the Pen Vue_Template_V-submit by Uramaya (@uramaya) on CodePen.

ファイルプレビュー -change

See the Pen Vue_Template_V-Change by Uramaya (@uramaya) on CodePen.

6.算出プロパティ

computed に定義した関数は、関数内部で参照しているプロパティが更新された時に自動的に呼ばれます。こちらではbirthday プロパティの値に変更があるたびに呼ばれています。

See the Pen Vue Computed by Masahiro Harada (@MasahiroHarada) on CodePen.

See the Pen Vue_Template_V-Calculate by Uramaya (@uramaya) on CodePen.

5.ウォッチャ

機能としてはcomputed と変わりません。

See the Pen Jjjoevo by Uramaya (@uramaya) on CodePen.

まとめ

いかがでしょうか。
今回はVue.jsについての簡単な紹介をしました。
こちら説明を入れる時間がなくてすみません。
Vue.jsが好きなっていただければ、嬉しいです。:D
(ちょっと現場の仕事で時間が足りなく、土日も...また説明を加えます。)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

10分で基礎がわからるVue.js-入門

はじめに

皆さん、こんにちは!Webシステム開発エンジニアの蘭です!
今日はVue.jsについて語りたいと思います。

昔Webシステム開発技術が始まった時、バックエンドではPHPやRubyを使い直接OracleやMySQLの内部のデータベースにSELECT,INSERT,UPDATE,DELETEを実行してた時代でした。

それが今はSaasの時代になり、内部データを直接弄るだけではなく、
フロントバックエンドの合化、外部連携の柔軟性が整ってる便利なREST APIファースト開発が主になり、フロントで「サイト更新の速度」や直感的なリ「アルタイムの更新」がサイト品質に関してもはや欠かせない物になりました。
 参考:APIファーストで開発する7つのメリット

やりたいこと:【サイト更新速度の向上、直感的なアルタイムの更新】

バックエンドではサーバーに対するリクエストはAPIでプロパティを渡し、
フロントではJavascriptを使い、最小限の範囲で非同期にVirtual DOMを更新する事が現在APIファーストの開発では重要な事です。

 参考:
   JavaScript初心者でもすぐわかる!DOMとは何か?
   VirtualDOMの仕事ってなに?表示速度がはやい理由

何故Vue.js

理由は比較的に簡単

・Javascriptがあまり分からない初心者でも学べるJavascriptフレームワーク
・単一ファイルコンポーネントで、HTML、CSS、Javascriptが同一のファイルで管理できる。
alt

もちろん、自分に合ったJavascriptフレームを選択するのが一番ですね。  
参考:
   JavaScript: フレームワーク React/Vue/Angularについて
   Vue・React・Angularのパフォーマンス比較検証

始めよう!Vue.js

Vue.jsって何?

・Webアプリケーションでユーザーインターフェースを構築するため、オープンソースのJavascriptフレームワーク。
・Axios等他のJavascriptライブラリが導入できる。
・高機能なシングルページアプリケーション(SPA)を構築することができる。
・vue-routerやvue-validation,vuex等組み合わせることで、大規模なWebアプリ開発のニーズまでサポートする統合的な環境を提供し、作者Evan氏の「Progressive Framework」の概念を活かす。
・ECMAScript 5をベースに、現在のブラウザーではほぼ使える。
  ※ES6で書くと、動かない場合があります。(特にIE)
参考:
   作者Evan氏のVue.js Progressive Framework
   ECMAScript 5
   ES5とES6の違いをまとめてみた

Vue.jsのインストール

こちらについては以下の公式記事を参考してください。
   Vue.jsのインストール

実際の開発ではnpmでインストールしますが、練習用はCDNでもできます。

Vue.js_cdn
 <script src="https://cdn.jsdelivr.net/npm/vue@2.6.0"> 
 </script>

ドキュメント

Vue.jsは日本語版で、内容は充実。
 Vue.jsの公式マニュアル

1.Hello World

【以下のコードはこちらの記事を引用してます。】


See the Pen
Vue_Hello World
by Uramaya (@uramaya)
on CodePen.


2.テンプレート

v-if / v-else-if / v-else

See the Pen Vue_Template by Uramaya (@uramaya) on CodePen.

See the Pen Vue_Template_V-if_2 by Uramaya (@uramaya) on CodePen.

v-show

See the Pen Vue_Template_V-Show by Uramaya (@uramaya) on CodePen.

繰り返し:v-for

See the Pen Vue_Template_V-for by Uramaya (@uramaya) on CodePen.

3.クラスとスタイル

HTMLクラス

See the Pen Vue_Template_V-HTMLClass by Uramaya (@uramaya) on CodePen.

style属性

See the Pen Vue_Template_V-Style by Uramaya (@uramaya) on CodePen.

4.フォーム入力

テキストボックス、エリアに文字入力

See the Pen Vue_Template_V-From-text by Uramaya (@uramaya) on CodePen.

セレクトボックス

See the Pen Vue_Template_V-SelectBox by Uramaya (@uramaya) on CodePen.

チェックボックス

See the Pen Vue_Template_V-From-checkbox by Uramaya (@uramaya) on CodePen.

ラジオ

See the Pen Vue_Template_V-From-radio by Uramaya (@uramaya) on CodePen.

ファイル

See the Pen Vue_Template_V-From-file by Uramaya (@uramaya) on CodePen.

その他

See the Pen ExxaOXz by Uramaya (@uramaya) on CodePen.

5.イベントとmethods

タブ -click

See the Pen Vue_Template_V-Click by Uramaya (@uramaya) on CodePen.

フォーム -submit

See the Pen Vue_Template_V-submit by Uramaya (@uramaya) on CodePen.

ファイルプレビュー -change

See the Pen Vue_Template_V-Change by Uramaya (@uramaya) on CodePen.

6.算出プロパティ

computed に定義した関数は、関数内部で参照しているプロパティが更新された時に自動的に呼ばれます。こちらではbirthday プロパティの値に変更があるたびに呼ばれています。

See the Pen Vue Computed by Masahiro Harada (@MasahiroHarada) on CodePen.

See the Pen Vue_Template_V-Calculate by Uramaya (@uramaya) on CodePen.

7.ウォッチャ

機能としてはcomputed と変わりません。

See the Pen Jjjoevo by Uramaya (@uramaya) on CodePen.

8.コンポーネント

内容は以下を引用
  Vue.jsでSPAへの移行-コンポーネントを使ってみよう
  Vue.js「コンポーネント」入門

コンポーネントとは簡単に説明すると、UI(ユーザーインターフェース)を作成する要素がまとまったものです。HTML、データ、ロジック、CSSを要素としてコンポーネントに含むことができます。そのコンポーネントを組み合わせることで、Webアプリケーションを作成することができます。作成したコンポーネントには名前が付けられます。その名前を登録し呼び出すことで、必要な時に何度でもアプリケーション内で使用することができます。

以下の利点があります。

・再利用が可能:
作成したコンポーネントは、必要なだけ何度でも再利用することができます。例えば、入力フォームのコンポーネントを作成すれば、そのフォームが必要なページにコンポーネントを登録し、HTML内にタグを追加することでフォームが追加されます。同じ構造や機能を開発し直すコストを軽減することができ、開発効率向上。
・コンポーネント単位で開発を行うことが可能:
コンポーネントごとに構造や機能が振り分けられているため、コンポーネント単位で複数人での開発を並行して進めることが可能です。また、Webアプリケーション内で何か問題が発生した際に、コンポーネント単位で切り分けて問題を対処することができます。

alt
alt

コンポーネントの構造

基本的にこのvueファイル一つで一つのコンポーネントを構成します。

vueファイルは主に
・templateタグ:コンポーネントのhtml要素を埋め込む
・scriptタグ:javascriptを記載する
・styleタグ:cssを記載する

xx.vue
<template>
<!-- ここにhtmlを記載します -->
</template>


<script>
// ここにjavascriptを記載します
</script>


<style>
/* ここにcssを記載します */
</style>

コンポーネントを作成してみよう

Header.vue
Header.vue
<template>
    <div>
        <h1>{{ title }}</h1>
        <p>{{ text }}</p>
    </div>
</template>

<script>
export default {
    data(){
        return {
            title: "Header",
            text: "Hello Vue.js!"
        }
    }
}
</script>

<style scoped>
div{
    border: 1px solid blue
}
h1{
    color: blue
}
p{
    color:blue
}
</style>
Body.vue
Body.vue
<template>
    <div>
        <h2>{{ title }}</h2>
        <p>{{ text }}</p>
    </div>
</template>

<script>
export default {
    data(){
        return {
            title: "Body",
            text: "Have a good day!"
        }
    }
}
</script>

<style scoped>
div{
    border: 1px solid red
}
h2{
    color: red
}
p{
    color: red
}
</style>
App.vue

先ほど作成したHeader.vueとBody.vueをApp.vueからまとめて呼び出します。

App.vue
<template>
  <div>
    <Header></Header>
    <Body></Body>
    <Body></Body>
  </div>
</template>

<script>
import Header from './Header.vue'
import Body from './Body.vue'

export default {
  components: {
    Header,
    Body
  }
}
</script>
イメージとしては以下になります。

alt

コンポーネント間のデータ受け渡し

1.親→子

【親→子】親側のデータ渡し口(タグ属性)
App.vue
<template>
  <div>
  //★【親→子】親側のデータ渡し口(タグ属性)
    <Header :username='name'></Header>
    〜略〜
  </div>
</template>

<script>
〜略〜

export default {
  data(){
    return {
      name: "kiyokiyo"
    }
  },
  〜略〜
}
</script>
【親→子】子側のデータ受け取り口(props)

 子コンポーネント側ではpropsを使ってデータを受け取ります。

Header.vue
<template>
    <div>
        〜略〜
        <p>Welcome! {{ username }}!</p>
    </div>
</template>

<script>
export default {
  //★子コンポーネント側ではpropsを使ってデータを受け取ります。
    props: {
        username: String
    },
    〜略〜
}
</script>
イメージとしては以下になります。

alt

2.子→親

App.vue
<template>
  <div>
    <Header :username='name'></Header>
    //★親側のデータ受け取り口(イベントと関数引数)
    <Body @add="add1"></Body>
    <Body @add="add2"></Body>
    <p>total : {{ totalcount }} </p>
  </div>
</template>

<script>
import Header from './Header.vue'
import Body from './Body.vue'

export default {
  data(){
    return {
      name: "kiyokiyo",
      count1: 0,
      count2: 0,
      totalcount: 0
    }
  },
  components: {
    Header,
    Body
  },
  methods:{
    add1(count){
      this.count1 = count;
      this.totalcount = this.count1 + this.count2;
    },
    add2(count){
      this.count2 = count;
      this.totalcount = this.count1 + this.count2;
    }
  }

}
</script>
Body.vue
<template>
    <div>
        <h2>{{ title }}</h2>
        <p>{{ text }}</p>
        <p><button @click="increment">+1</button> {{ count }} </p>
    </div>
</template>

<script>
export default {
    data(){
        return {
            title: "Body",
            text: "Have a good day!",
            count: 0
        }
    },
    methods: {
        increment(){
            this.count += 1;
            //★子側のデータ渡し口($emit)
            this.$emit("add",this.count);
        }
    }
}
</script>
イメージとしては以下になります。

alt

8.VueでREST API通信

VueでAPI通信はAPIでJsonデータを取得する際に使われます。
こちらに関しては以下の記事を見てくださいね。

 10分でわかる:Vue.jsとaxios を利用した API の使用-初心者向け

9.Vueのライフサイクルフックについて

Vueインスタンスが作成の際に、フックが実行されるタイミングがわかり、メソッドを実行する時どのフックを使えばいいか理解できます。

ライフサイクルダイアグラム

・以下の記事を参考してください。
  Vueのライフサイクルについて
  ライフサイクルダイアグラム

まとめ

いかがでしょうか。
今回はVue.jsについての簡単な紹介をしました。
こちら説明を入れる時間がなくてすみません。
Vue.jsが好きなっていただければ、嬉しいです。:D
(ちょっと現場の仕事で時間が足りなく、土日も...また説明を加えます。)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

FireStoreにデータを投入する時に、値がundefinedのpropertyがあると怒られる

掲題の通り。
undefinedを含むオブジェクトをaddやsetで渡すとエラーを投げる。
fireStoreのNull型に自動変換とかはしてくれないし、
そのプロパティだけ自動で省くといったような気の利いたことはしてくれない。
スキーマレスとは言っても受け入れられないものはある。

typescriptで言うところの

type HOGE = {
  fuga?:someType 
}

のようなプロパティがundefined可能性もあるオブジェクトを投入する場合は注意。
(なお、上記の場合fugaプロパティ自体が存在しなければセーフ。
fugaプロパティが存在してかつundefinedが入っているとアウト。)

対応策

  1. undefinedの場合はフィールドを消す(deleteを使う)
  2. undefinedの場合はnullに変換する(nullならfirestoreのNULL型になる)
  3. update系の場合ならfirebase.firestore.FieldValue.delete()に変換する(フィールド自体をfirestore上に残したくない場合) ただし、create処理でfirebase.firestore.FieldValue.delete()を使うとこれまたエラーを吐かれるので注意
  4. Typescriptを使った上で、そもそもundefinedをpropに持ちうるような型定義をしない
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

next.jsでフォントの読み込みがおかしい時の処方箋

node.jsでnpmパッケージとかのフォントファイルを読み込んでくれない(´・ω・`;)
そんなときの処方箋メモ。

ディレクトリ構成は以下がベースです。
With Firebase Hosting and Typescript example

1. staticフォルダにフォントファイルだけ手動設置

  • dev環境の場合は/src/app/staticに設置
  • serve & deploy環境は/src/public/staticに設置するか、package.json(一部抜粋)を以下のように調整
    • dev環境のstaticフォルダと共通じゃないので泣く泣く重複設置。他にいい方法あったら教えてください(´・ω・`;)
package.json
{
  "scripts": {
-    "build-public": "cpx \"src/public/**/*.*\" \"dist/public\" -C",
+    "static-to-public": "cpx \"src/app/static/**/*.*\" \"src/public/static\" -C",
+    "build-public": "npm run static-to-public && cpx \"src/public/**/*.*\" \"dist/public\" -C",
  },
}

2. フォントファイルの読み込み部分をコピペ&調整(ファイルパスをフォントファイルを設置したパスに変更)して、適当な部分でimport

以下、importサンプル。

sample.css
@font-face {
  font-family: 'sample';
  src: url("/static/fonts/sample/sample.eot") format("embedded-opentype"),
  font-weight: normal;
  font-style: normal;
}
sample.js
import "./sample.css"
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

フォトショになりたい Part2. 色調補正

色調補正

  • HSV
    • 色相(Hue)
    • 彩度(Saturation)
    • 明度(Value/Brightness)
    • 自然な彩度
  • ホワイトバランス
    • 色温度(temperature)
    • 色被り補正(deviation)

HSV

RGBとHSVは一つの色を別の座標空間で表現しているだけ。
変換式はRGBとHSV・HSBの相互変換ツールと変換計算式より。丸め誤差を除けば一応全単射なはず。
(以下の計算は、それぞれ0 to 255に正規化しています)。

色相

RGBによって貼られる平行六面体を$r+g+b$ベクトルから見たときの偏角
(詳しくはRGB正六面体 → HSL円柱を参照)

0-360度にするとImageData型(Uint8ClampedArray)に入りきらないので、0から255に納めている。

calcHue.js
function calcHue(r, g, b) { // 0 to 255
  const MAX = Math.max(r, g, b);
  const MIN = Math.min(r, g, b);
  if (MAX === MIN) {
    return 0;
  } if (MIN === b) {
    const h = 42.5 * ((g - r) / (MAX - MIN)) + 42.5;
    return h > 0 ? h : h + 255;
  } if (MIN === r) {
    const h = 42.5 * ((b - g) / (MAX - MIN)) + 127.5;
    return h > 0 ? h : h + 255;
  }
  const h = 42.5 * ((r - b) / (MAX - MIN)) + 212.5;
  return h > 0 ? h : h + 255;
}

彩度

RGBの最大値と最小値の比。

calcSaturation.js
function calc(r, g, b) { // 0 to 255
  const MAX = Math.max(r, g, b);
  const MIN = Math.min(r, g, b);
  return (MAX - MIN) / MAX * 255;
}

明度

RGBの最大値。

calcBrightness.js
const calcBrightness = (r, g, b) => Math.max(r, g, b);

まとめると

hsvCvt.js
function rgb2hsv(img) { // H: 0~255, S: 0~255, V: 0~255
  for (let i = 0; i < img.data.length; i += 4) {
    const r = img.data[i];
    const g = img.data[i + 1];
    const b = img.data[i + 2];
    const MAX = Math.max(r, g, b);
    const MIN = Math.min(r, g, b);
    img.data[i] = calcHue(r, g, b);
    img.data[i + 1] = (MAX - MIN) / MAX * 255;
    img.data[i + 2] = MAX;
  }
  return img;
}

function hsv2rgb(img) {
  for (let i = 0; i < img.data.length; i += 4) {
    const h = img.data[i];
    const s = img.data[i + 1];
    //MAX = v
    const MAX = img.data[i + 2];
    const MIN = MAX - ((s / 255) * MAX);
    if (h < 42.5) {
      img.data[i] = MAX;
      img.data[i + 1] = (h / 42.5) * (MAX - MIN) + MIN;
      img.data[i + 2] = MIN;
    } else if (h < 85) {
      img.data[i] = ((85 - h) / 42.5) * (MAX - MIN) + MIN;
      img.data[i + 1] = MAX;
      img.data[i + 2] = MIN;
    } else if (h < 127.5) {
      img.data[i] = MIN;
      img.data[i + 1] = MAX;
      img.data[i + 2] = ((h - 85) / 42.5) * (MAX - MIN) + MIN;
    } else if (h < 170) {
      img.data[i] = MIN;
      img.data[i + 1] = ((170 - h) / 42.5) * (MAX - MIN) + MIN;
      img.data[i + 2] = MAX;
    } else if (h < 212.5) {
      img.data[i] = ((h - 170) / 42.5) * (MAX - MIN) + MIN;
      img.data[i + 1] = MIN;
      img.data[i + 2] = MAX;
    } else {
      img.data[i] = MAX;
      img.data[i + 1] = MIN;
      img.data[i + 2] = ((255 - h) / 42.5) * (MAX - MIN) + MIN;
    }
  }
  return img;
}

自然な彩度

彩度にトーンカーブをかける
→すでに彩度が高いところはそのままで、低いところを上げたい
→とりあえず両対数スケールで実装
(詳しくはスケール対数曲線をトーンカーブとする画像補正を参照)

calcSaturation.js
const natural_s = (s, k) => log_log_scale(s, k);

HSV系全体の流れ

  1. RGBからHSVに変換
  2. HSV空間でいじる
  3. HSVからRGBに変換
editHSV.js
function editHSV(img, h_rotation, s_magnification, natural_s, v_magnification) {
  rgb2hsv(img);
  hsvCvt(img, h_rotation, s_magnification, natural_s, v_magnification);
  hsv2rgb(img);
  return img;
}

ホワイトバランス

こちらはRGB空間を弄る。
RGBそれぞれの感度の違いを再現するので、普通にRGBそれぞれを定数倍すればいいだけだと思う。

ただ、Photoshopには以下のスライダーがあったのでそれだけ実装した。

色温度

基本がわかる!色かぶりの補正【1】ホワイトバランスと色温度
多分青いか黄色いかという話なので、とりあえず$B$チャンネルをk倍した。

色被り補正

Photoshopの色被り補正は緑-マゼンタの軸で補正しているように見えるので、$G$チャンネルを定数倍した。
理論上これと露出をいじれば全パターン再現できているはず。

まとめ

  • HSV系は変換がめんどくさいが、HSV空間に持ち込んで色々いじった後RGBに戻す
  • 色温度・色被り補正はホワイトバランスをいじることに相当する
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Node.js】指定したディレクトリ以下のファイル群をコピーする

指定したディレクトリ以下のファイルをコピーする

指定したでディレクトリ配下のファイルをコピーし、
コピー先にファイルがない場合にのみコピーを行う処理を行うモジュールが
必要であったため自作したものを備忘録としてあげておきます。

また、取得する関数の紹介ばかりで、
同期処理など含めておらず実用的でない記事が多かったため、
この記事を書きました。

記事を読むために

  • node npm の環境構築が可能
  • ES6 が理解できる
  • async await (同期処理/非同期処理)を理解できる

コード

まずfsモジュールのreaddirSync()を用いて該当ディレクトリ配下にある、
ディレクトリ、またはファイル名を取得する処理を書いていきます。
readdir():非同期処理
readdirSync(): 同期処理
これらを用いることで引数に渡したディレクトリ配下の
ディレクトリ名やファイル名を取得することができます。

関数の処理が非同期であると戻り値が担保されないため、
async awaitとthen()を利用します。

import fs from 'fs'

const getFileNameList = async (originFilePath) => {
  // fileListがreturnされるまで待機
  return await fs.readdirSync(originFilePath, (err, fileList) => {
     if (err) throw err
     return fileList
  })
}

次にfsモジュールのcopyFileSync()を利用し、
取得したファイル群を指定したディレクトリ配下にコピーしていきます。

import fs from 'fs'
import path from 'path'

const copyFilesToDir = (originDir, copyDir) => {
  getFileNameList(path.resolve(originDir) + '/')
  .then(list => { // 処理完了後に処理を実行し戻り値を担保
    const fileNameList = list.slice()
    fileNameList.forEach((fileName) => {
      try {
        // fs.constants.COPYFILE_EXCLをオプションに設定
        // コピー先に同名ファイルが存在した場合に例外を出す
        // 指定しない場合は上書き
        fs.copyFileSync(
          path.resolve(copyDir + fileName), 
          path.resolve(originDir + fileName), 
          fs.constants.COPYFILE_EXCL
        )
        console.log('copied:' + path.resolve(originDir + fileName))
      } catch(err) {
        // ファイルがすでに存在する場合 EEXIST
        // ディレクトリが存在しない場合 ENOENT
        console.log(err)
      }
    })
  })
}

汎用的にしたつもりですので、
カスタムなどして利用してみてもいいかもしれません。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vue.js: Vue I18nの公式ドキュメントに見当たらず悩んだふたつのこと

Vue I18nは、Vueアプリケーションを国際化(多言語対応)させるためのプラグインです。ページに表示するテキストを、ロケールに応じて切り替えられます。インストールから基本的な設定と使い方までは「Vue.js: Vue I18nでアプリケーションを多言語に対応させる」でご説明しました。本稿では、公式ドキュメントに解説が見当たらず悩んだことをふたつ紹介します。

01 プレースホルダーを多言語化する

実は、プレイスホルダーを使うことは推奨されないようです。そうはいっても、入力例を示すなど、使う場面は少なくないでしょう。ところが、つぎのように記述すると、式($t('placeholder'))がそのまま表示されてしまい、翻訳テキストが取り出せませんでした。

<input type="text"
    placeholder="$t('placeholder')">

Vue I18nサイトのドキュメントには見当たらず、英語でも情報は多くありません。Stack Overflowで見つけたのが、v-bind(省略記法:)を加えなければならないということです。たったひと文字で、プレースホルダーが多言語化できました。

<input type="text"
    :placeholder="$t('placeholder')">

02 t()メソッドに渡すパスに変数を含める

翻訳テキストを取り出す$t()メソッドの第1引数には、テキストが収められたプロパティのパスを渡します。ここに変数を含めるにはどうしたらよいかです。具体的には、v-forディレクティブで複数要素を変数からつくりたい場合でした。

<div id="app">
    <ul>
        <li
            v-for="city in cities"
            :key="city">
            <!-- message[city]のテキストを取り出したい -->
        </li>
    </ul>
</div>
const messages = {
    en: {
        message: {
            tokyo: 'Tokyo',
            newyork: 'New York',
            london: 'London'
        }
    },
    ja: {
        message: {
            tokyo: '東京',
            newyork: 'ニューヨーク',
            london: 'ロンドン'
        }
    }
}
// ...[中略]...
new Vue({
    i18n,
    data: {cities: ['tokyo', 'newyork', 'london']}
}).$mount('#app')

試したところ、つぎの記述で翻訳テキスト「東京」または「Tokyo」が表示されました。

{{ $t("message['tokyo']") }}

それならと、つぎのように書いてみると、また式が表れてテキストは取り出せません。

{{ $t("message[city]") }}

こちらは検索では見つけることができず、VueのForum(英語)で質問してみたところ回答が得られました。messagesオブジェクトの感覚で捉えていたのがよくなかったようです。文字列のパスと考えるべきでした。

{{ $t("message." + city) }}

ご参考までにテスト用のサンプルをCodePenに上げておきます。

サンプル001■ Vue I18n Test

See the Pen Vue I18n Test by Fumio Nonaka (@FumioNonaka) on CodePen.

Appendix TodoMVCを日英対応にする

Vue.js + CLI入門」は、公式サイト「TodoMVC の例」をVue CLIによる単一ファイルコンポーネント(vueファイル)でつくり直しました。さらに、これをVue I18nで日英対応にしたのが「Vue.js + Vue I18n: アプリケーションを多言語に対応(国際化)させる」の作例です。こちらはCodeSandboxに公開しています。興味がある方はリンクの解説をお読みください。

サンプル002■ vue-i18n-todo-mvc

FN1910002_007.png
>> CodeSandboxへ

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScript初心者に暗記してほしい構文 11選

先日「JavaScriptの本を写経しているけど正直身になっているか不安」という相談を受けました。
これ自体はプログラミング初心者なので仕方がないのですが、パラパラとページを捲りながら「じゃあとりあえず変数fooに文字列の”あいうえお”を入れようか」と言ったら手が止まってしまいました。過去にも別の人に「bazっていう関数を作って」と言ったらbuz{function[]}みたいなのが出てきて、「おぉ..」となりました。

なので英語の単語ドリルのように構文(書き方の形)だけを暗記することが、初心者にとって近道ではないかと思いました。

今回はJavaScriptのES5で書いていきます。
教えていてミスや質問が多かった部分などのコメントも書いたので、合わせて読んで貰えればと思います。

暗記ドリル

文字列の「あああ」、数字「12」、ブーリアンの「false」を適当な変数に入れて!

var str = 'あああ'; // 文字列はシングルコーテーションまたはダブルコーテーションで囲う。
var num = 12;
var bool = false;

適当につけた変数名「str」はstringの略です。stringは文字列という意味です。
変数名「num」はnumberの略です。numberは数字という意味です。
変数名「bool」はbooleanの略です。booleanはプログラミングでtrueかfalseという意味です。

空の配列と空のオブジェクトを適当な変数に入れて!

var arr = [];
var obj = {};

変数名「arr」はarrayの略です。arrayは配列です。
変数名「obj」はobjectの略です。objectはオブジェクトっていうものです。(今はそう覚えて!)

適当な変数に「5」を入れて、コンソールに出して!

var hoge = 5;
console.log(hoge);

hogeは日本のIT業界でよく一時的な変数の名前としてよく使われる単語です。意味のない単語なのでWebサイトを公開する時に残っていると偉い人に怒られます。

適当な名前の空の関数(ファンクション)作って!

// パターン1
function aaa() {}
// パターン2
var aaa = function() {}

パターン1とパターン2は厳密には違いがあるけど、一旦この2つの書き方がある事を覚えてください。

「あ〜お」の配列を作って、「う」をコンソールに出して!

var strs = ['', '', '', '', ''];
console.log(strs[2]);

配列の先頭は0から始まるので、strs[0]が「あ」、strs[1]が「い」、strs[2]が「う」になります。

Bookってオブジェクト作って、「title」ってプロパティに適当な名前を入れて!

var Book = {
  title: 'ワンピース'
}

titleの後ろは「:」です。「=」ではありません。

Carってオブジェクトに「run」ってメソッド作って!

var Car = {
  run: function() {}
}

Userってオブジェクトに「name」「tel」を作って適当な文字を入れて!

var User = {
  name: 'やまだ',
  tel: '090-xxxx-xxxx'
}

次のプロパティやメソッドを書くときは「,」を使います。 name: 'やまだ', ← これです。最後は入りません。

Userオブジェクトからnameをコンソールに出して!

var User = {
  name: 'やまだ',
  tel: '090-xxxx-xxxx'
}
// パターン1
console.log(User.name)
// パターン2
console.log(User['name'])

パターン1でも2でも、どちらでも構いません。

「id=‘btn’」のDOM取得して、適当な変数に入れてコンソールに出して!

// パターン1
var b = document.getElementById('btn');
console.log(b);
// パターン2
var b = document.querySelector('#btn');
console.log(b);

パターン1でも2でもどっちでも良いですが、DOMを取得と聞いたらパッとどちらも思いつくようにしましょう。

「id=‘btn’」にクリックイベントをつけて!

var b = document.getElementById('btn');
b.addEventListener('click', function() {});

まとめ

繰り返し書いて覚えている時はつまらないかもしれないけど、とりあえずここに書いてもらったものを暗記してもらえれば自分は説明しやすいです。
他にも覚えるべき構文などはたくさんありますし、「for」や「if」がないという人もいるかもしれませんが、そこの説明は楽なんですよね。そこまでたどり着く前に暗記しておいてもらえると、本当に助かると思ったものをピックアップしました。

これは知り合いを教えるためのテキストとして使用する目的で書きました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Promiseのメモ - その2: チェーン、例外

Promiseのメモ - その1: resolveとthen の続き。

チェーン

thenやcatchをいくつもつないで、「1つめの処理→2つめの処理」のような流れを作ることをプロミスチェーンと言います。

次の例は、2つめのthenを追加したものです。1つめのthenのコールバック関数で戻り値を返すと、その戻り値が2つめのthenのコールバック関数の引数になります。

function makePromise(num) {
  return new Promise((resolve, reject) => {
    if(num % 2 == 0)
      resolve('OK');
    else
      reject('NG');
  });
}

makePromise(2).then((x) => {
  console.log(`then1 callback: ${x}`);
  return x + x;
}).then((x) => {
  console.log(`then2 callback: ${x}`);
}).catch((r) => {
  console.log(`catch callback: ${r}`);
});
結果
then1 callback: OK
then2 callback: OKOK

makePromise(1)としてrejectすると、thenは2つともスキップされて、catchに渡した関数が実行されるように見えます。

結果
catch callback: NG

thenとcatchが返すPromise

MDNの説明でthenの仕様をチェックします。

The then() method returns a Promise.

thenはPromiseオブジェクトを返します。はっきり書いていませんが、新しいPromiseオブジェクトを作って返すということです。

  • returns a value, the promise returned by then gets resolved with the returned value as its value;
  • doesn't return anything, the promise returned by then gets resolved with an undefined value;

コールバック関数で戻り値を返すと、新しいPromiseオブジェクトは履行済みになり、履行済み結果の値はその戻り値になります。戻り値がないと、履行済み結果の値はundefinedになります。

次のようにチェーンをばらしてthenが返すPromiseを調べます。また、コールバック関数が実行されたあとの状態も調べます。

let promise = makePromise(2);
console.log(promise);
let promise_then1 = promise.then((x) => {
  console.log(`then1 callback: ${x}`);
  return x + x;
});
console.log(promise_then1);
let promise_then2 = promise_then1.then((x) => {
  console.log(`then2 callback: ${x}`);
});
console.log(promise_then2);
let promise_catch = promise_then2.catch((r) => {
  console.log(`catch callback: ${r}`);
});
console.log(promise_catch);

setTimeout(() => {
  console.log(promise);
  console.log(promise_then1);
  console.log(promise_then2);
  console.log(promise_catch);
}, 1000);
結果(chromeの場合)
Promise {<resolved>: "OK"}
Promise {<pending>}
Promise {<pending>}
Promise {<pending>}
then1 callback: OK
then2 callback: OKOK
Promise {<resolved>: "OK"}
Promise {<resolved>: "OKOK"}
Promise {<resolved>: undefined}
Promise {<resolved>: undefined}

makePromise関数が1つ、thenが2つ、catchが1つのPromiseオブジェクトを作っています。thenとcatchが作ったPromiseは非同期で自動的に保留中から履行済みに変わっています。

makePromise(1)としてrejectすると、次の結果になります。

結果(chromeの場合)
Promise {<rejected>: "NG"}
Promise {<pending>}
Promise {<pending>}
Promise {<pending>}
catch callback: NG
Promise {<rejected>: "NG"}
Promise {<rejected>: "NG"}
Promise {<rejected>: "NG"}
Promise {<resolved>: undefined}

thenやcatchはスキップされるわけでなく、「thenで登録したコールバック関数は棄却済みのときは実行されない」「catchで登録したコールバック関数は履行済みのときは実行されない」ということです。実行されないときは、履行/棄却済み結果の値は次のPromiseオブジェクトに引き継がれます。

catchもPromiseを返すので、catchのうしろにthenをつなげることができます。

makePromise(2).then((x) => {
  console.log(`then1 callback: ${x}`);
  return x + x;
}).catch((r) => {
  console.log(`catch callback: ${r}`);
  return r + r;
}).then((x) => {
  console.log(`then2 callback: ${x}`);
});
結果
then1 callback: OK
then2 callback: OKOK

この例はmakePromise(1)とすると、then2 callback: NGNG となります。

例外

rejectだけでなく、一般的な例外が発生したときも、catchで登録したコールバック関数が呼ばれます。コールバック関数の引数にはErrorオブジェクトが入ります。

function makePromise(num) {
  return new Promise((resolve, reject) => {
    if(num % 2 == 0)
      resolve('OK');
    else
      foo.bar();
  });
}

makePromise(1).then((x) => {
  console.log(`then1 callback: ${x}`);
}).catch((r) => {
  console.log(`catch callback: ${r}`);
});
結果
catch callback: ReferenceError: foo is not defined

コールバック関数で例外が発生したときも、次のcatchのコールバック関数が呼ばれます。

function makePromise(num) {
  return new Promise((resolve, reject) => {
    if(num % 2 == 0)
      resolve('OK');
    else
      reject('NG');
  });
}

makePromise(2).then((x) => {
  console.log(`then1 callback: ${x}`);
  foo.bar();
}).catch((r) => {
  console.log(`catch callback: ${r}`);
});
結果
then1 callback: OK
catch callback: ReferenceError: foo is not defined

catchがない場合

executorでrejectを呼んだ場合や、executorやコールバック関数で例外が発生した場合に、catchがないと例外が発生します(nodeではUnhandledPromiseRejectionWarningが出ます)。

function makePromise(num) {
  return new Promise((resolve, reject) => {
    if(num % 2 == 0)
      resolve('OK');
    else
      reject('NG');
  });
}

makePromise(1).then((x) => {
  console.log(`then1 callback: ${x}`);
});
結果(chromeの場合)
Uncaught (in promise) NG

Promiseで発生した例外をtry - catchで捕まえることはできません(asyncとawaitを使えばできます)。次の例は意味なしです。

try {
  makePromise(1).then((x) => {
    console.log(`then1 callback: ${x}`);
  });
}
catch(e) {
  console.log(e);
}

続く。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

React-memo

React

  • UIを構築するための宣言型で効率的で柔軟なJavaScriptライブラリ
  • 複雑なUIをコンポーネントと呼ばれる小さく独立した部品から組み立てる
  • コンポーネントはpropsと呼ばれるパラメータを受け取り、renderメソッドを通じて表示するビューの階層構造(React要素)を返す
  • この構造を簡単に記述できるJSXと呼ばれる構文を使用できる
  • Facebook 製のオープンソース
  • モバイルアプリ、デスクトップアプリ、VR
  • 仮想DOMで処理を行う
  • 旧来のDOM操作による状態管理をpropsやstateで抽象化
  • 関数型プログラミングの考え
  • あくまでもJavaScript
  • 薄いライブラリ
  • Reactは単方向データフロー
    • 親コンポーネントから子コンポーネントにpropsが渡される
  • VueやAngularはデータバインディング
    • テンプレートに埋め込まれた任意の変数が別のところに紐付けられていて、その変更がリアルタイムに反映される
    • アプリが複雑になりコンポーネントの階層がどんどん深くなっていくと、予期せずに値が書き換わる可能性がある

image.png

モダンなJS

  • ECMAScript
  • let/const
  • Class構文、コンストラクタ、インスタンスメソッド、継承
  • テンプレートリテラル
  • スプレッド構文
  • async/await
  • 分割代入
  • アロー関数
function plusOne(n) {
  return n + 1;
}

const plusOne = (n) => { return n + 1; };

const plusOne = n => n + 1;

const plusOne = (n: number): number => n + 1;

関数型プログラミング

  • コレクションの反復処理
    • map()、filter()、find()、every()、some()、includes()、reduce()、sort()
  • 無名関数
  • 変数に無名関数を代入することで命名できる
  • 高階関数
  • 部分適用
  • 複数の高階関数を合成できる
  • カリー化

TypeScript

  • 静的型付け
  • 型推論
  • Null安全性

Babel

  • トランスコンパイル(現行のブラウザ環境で正常に動作する形式に変換)

コンポーネント

  • 再利用可能なパーツ
  • 自分で自分の状態を管理
  • 基本的にComponentを作って組み合わせて アプリケーションを作っていく
  • JSXを使ったりして記述
  • Local state
  • 関数コンポーネント
  • Presentational Components
  • Container Components
  • Recompose
  • Stateless Functional Components
    • propsは不変のobject、引数に相当
    • stateは変更可能なobject、コンポーネント自身のみ
    • Stateの保持はReact.Componentを継承するクラスでしか使用できない
import React, { Component } from 'react';

// Class構文を使ってreactパッケージ内のComponentを継承している
class Hello extends Component {
  render() {
    return <div>Hello, world!</div>;
  }
}

export default Hello;
import Reat from 'react';

// 通常の関数構文のみで定義している
const Hello = () => {
  return <p>Hello, world!</p>;
}

export default Hello;

ライフサイクルメソッド

  • コンポーネントがMount、Update、Unmoutされるタイミングで呼ばれるメソッド

image.png

Atomic Design

image.png

Redux

  • React が扱うstate を一元管理するためのフレームワーク
  • アプリが大きくなってComponent同士が依存しあうようになると stateの管理をすることが大変になる
  • Reduxを使うことで、ReactのComponentではstateを管理せずにpropsだけを使うようにできる
  • SPAなど複雑化するReactステート管理を、 ルール(哲学)に従って書かせることで、フロントエンドの動きを人間にとって追いやすくする
  • 信頼できる単一の情報源、読み取り専用の状態(Actions)、純粋な関数(Reducers)によって変更される

redux.gif

HOC

  • HOC(Higher-order-components)コンポーネントを合成する仕組み
  • コンポーネントに関数を適応し、機能が合成されたコンポーネントを返す
  • propsを新しく加えたり、ライフサイクルメソッドを追加することも可能
  • コンポーネントに新たな機能を追加して使い回しやすくできる
  • material-ui などすでに作成されたコンポーネントにも柔軟に適応可能
  • HOC自体を他コンポーネントにも使いまわせる(ログイン必須コンポーネントなど)
  • 継承より合成やUIに徹した哲学
  • コンポーネント関数を適応し、機能が合成されたコンポーネントを返す

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

javascriptでDOMの一部を差し替える

経緯

多言語サイトの年齢認証モーダルで、モーダルの内容を選んだ言語に合わせて内容が変わるものが必要になった。
ブラウザ設定言語によって初回ロード時は各言語に振り分けしてるが、モーダル内の言語選択でも内容が変わらないとおかしいよねwww
プロマネに言われるまで気づかなかった(爆)

姑息な方法として各言語の内容をCLASSでONOFFすれば良いが、個人的に嫌というかダサいので違う方法を模索。
結果、以下の方法で実装することとした。

実装

デフォルト表示させるスタティックなHTMLを用意する

私は日本語をデフォルト表示とした。
jsによってID[modal]の内容が差し替わります。

default.haml
#modal
  %h1 こんにちは!
  %ul{onclick: 'loadModal(event)'}
    %li{data:{lang: 'en'}} EN
    %li.active{data:{lang: 'ja'}} JA
    %li{data:{lang: 'zh'}} ZH
    %li{data:{lang: 'fr'}} FR

各言語切り替え用モーダル部品を用意する

lang_ja.html
<h1>こんにちは!</h1>
<ul onclick='loadModal(event)'>
  <li data-lang='en'>EN</li>
  <li class='active' data-lang='ja'>JA</li>
  <li data-lang='zh'>ZH</li>
  <li data-lang='fr'>FR</li>
</ul>

lang_en.html
<h1>Hello!</h1>
<ul onclick='loadModal(event)'>
  <li class='active' data-lang-type='en'>EN</li>
  <li data-lang='ja'>JA</li>
  <li data-lang='zh'>ZH</li>
  <li data-lang='fr'>FR</li>
</ul>

lang_fr.html
<h1>Bonjour!</h1>
<ul onclick='loadModal(event)'>
  <li data-lang='en'>EN</li>
  <li data-lang='ja'>JA</li>
  <li data-lang='zh'>ZH</li>
  <li class='active' data-lang='fr'>FR</li>
</ul>

lang_zh.html
<h1>您好!</h1>
<ul onclick='loadModal(event)'>
  <li data-lang='en'>EN</li>
  <li data-lang='ja'>JA</li>
  <li class='active' data-lang='zh'>ZH</li>
  <li data-lang='fr'>FR</li>
</ul>

JS

クリックイベントでdata属性の値を取得し、その値を利用してロードするhtmlを制御します。

sample.js
function loadModal(e){
  var lang = e.target.getAttribute('data-lang');
  XHR = new XMLHttpRequest();
  XHR.onreadystatechange = checkingStatus;
  XHR.open("GET", "/modal_" + lang + ".html", true);
  XHR.send(null);
};
function checkingStatus(){
  if (XHR.readyState == 4 && XHR.status == 200){
    var target = document.getElementById("modal");
    target.innerHTML = XHR.responseText;
  }
}

CSS

簡易的なものなのでご自由に

sample.scss
#modal{
  width: 300px;
  box-sizing: border-box;
  color: #FFF;
  background-color: #000;
  border-radius: 5px;
  padding: 40px 20px;
  margin: 100px auto 0;
  h1{
    font-size: 30px;
    text-align: center;
    margin-bottom: 20px;
  }
  ul{
    display: flex;
    justify-content: space-around;
    li{
      display: inline-block;
      color: #B7B7B7;
      cursor: pointer;
      &.active{
        color: #FFF;
      }
    }
  }
}

こんなかんじ

スクリーンショット 2019-10-08 15.41.45.png

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AjaxはGoogleMapとかで使われている

概要

アプリ開発手法の一種であるAjaxについて簡単にまとめました。

と言っても、

A(Asynchronous)・・・非同期通信
ja・・・JavaScript
x・・・XML

このように分解した時に、つまりどういうこと?となるのはおそらく「非同期通信」ではないでしょうか。
それでこのタイトルをつけて簡単にまとめました。

Ajaxとは

アプリ開発手法の一つで、JavaScriptXMLを用いて非同期通信を実装する開発手法。

XMLはマークアップ言語の一種で、分かりやすく言うとHTMLのようなものです。
タグを使ってデータの構造を記述していくもので、プログラミング言語ではありません。

ちなみにデータ形式としてXMLを採用するメリットは、

  • 可読性が高い
  • 記述の順序に依存しない

などがあります。

XMLの例
<?xml version='1.0' encoding='utf-8'>
<root>
    <employee>
        <employ>
            <ID>111</ID>
            <Name>Mike</Name>
            <Country>USA</Country>         
        </employ>
        <employ>
            <ID>222</ID>
            <Name>Nancy</Name>
            <Country>Canada</Country>
        </employ>
    </employee>    
</root>

データ形式自体は他にも、CSVやJSONなどがよく使われるものとしてあります。
詳しい違いなどについては、こちらをどうぞ。

引用:【何が違う?】データ形式(CSV, XML, JSON)の特徴を知ろう


画面もいちいち消えないしずっと操作を受け付けているから便利

非同期通信を使えば、同期(画面の更新)することなくサーバからデータの取得ができます。
身近なものだとGoogleMAPなど地図アプリに使われているのが分かりやすいです。

例えばGoogleMapで地図を縮小すると建物、道、地形のディティールがアバウトになって代わりに都道府県、市区町村とか大きなエリアの情報が読み込まれて出てくると思います。

反対に拡大すると、先ほどの都道府県、市区町村とかの大雑把な情報が消えて建物、道、地形、店名、ランドマークとかのディティールが読み込まれて細かく表示されると思います。

GoogleMapでなくてもマップアプリならだいたい一緒です。

その時に、普段Googleで何か検索してWEBサイトを見るときのように、操作の受付・画面表示が中断(真っ白になる)して切り替わることってないですよね。
非同期通信を実装するとリアルタイムでデータを読み込むので、画面表示してる状態で操作も受け付けている状態で更新できます。

進むたびに操作を受け付けなく、画面が真っ白になって切り替わるナビがあったらとても使いづらすぎますね。

これが非同期通信の特徴でできることです。

逆に同期通信はWEBページを移動した時などに一瞬画面が白くなって切り替わるような通信方法で、その間は操作を受け付けません。

まとめ

AjaxのA(asynchronous)、非同期通信にとXMLについて簡単にまとめました。

今後、次世代通信規格である「5G」が民間向けに商用利用されるようになると、通信量が多くかつスピードも求められる非同期通信の活用の幅はさらに広がるので今後もアプリ開発をしていきたい人にとってはおさえておきたいですね。

参考

この記事は「CodeShip」内での実際の質疑応答や指導・アドバイスの一部を基に作成しています。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScript 覚えておくべき注意点!(4) switch文について 例 エアコンスイッチ

switch文を使うと、変数の値がどれと一致するかで複数に分岐する処理を書くことができます。

switch文は if ~ else if文で書くことができますが、switch文の方がプログラムを読みやすくすることができます。

switch.jp
switch (value) {
    case 100:
        変数が100の時に実行する処理
        break;
    default:
        どのケースにも該当しないときに実行する処理
}

例 運転が暖房の場合を書きます。
・case冷房をスキップします
・case暖房で等しいので、プログラムに進みます
・それ以降はブロックの外に出ます。

switch文を書くときは、breakは必ず必要です。

switch-2.jp
var 運転切り替え = 暖房;
switch (運転切り替え) {
  case 冷房:
    温度を下げます;
    break;
  case 暖房:
    温度を上げます;
    break;
  case 送風;
    風を送ります;
    break;
  default:
    自動で判断します;
}

参照 いちばんやさしいJavaScriptの教本

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Node.jsのコンソールから入力サンプル

はじめに

Node.jsにおいてコンソール(ターミナル)から値を入力するサンプルを掲載します。
例題として、基礎代謝量の計算例を示します。
1日の必要なカロリーを計算して、ダイエットにお役立てください。

前提

  • OS : Windows7以上
  • PoweShellのターミナルで実行
  • VSCodeでコード編集
  • node.js環境構築済み

基礎代謝量とは

生命を維持するために必要なエネルギー量を基礎代謝量(BMR)といいます。
ハリス・ベネディクト方程式(改良版)を使って基礎代謝量を計算します。
男性: 13.397×体重kg+4.799×身長cm−5.677×年齢+88.362
女性: 9.247×体重kg+3.098×身長cm−4.33×年齢+447.593

bmr.js

/**
 * 基礎代謝量(MBR)計算
 * @param {int} sex           - 性別 男=0 女=1
 * @param {float} weight      - 体重
 * @param {float} hight       - 身長 
 * @param {int} age           - 年齢
 */
const mbr = (sex,weight,hight,age) => {
    if (sex == 0 ) {
        var kcal = 13.397 * weight + 4.799 * hight - 5.677 * age + 88.362;
    } else {
        var kcal = 9.247 * weight + 3.098 * hight - 4.33 * age + 447.593;
    }
    return kcal;
}

/**
 * コンソール出力メッセージ
 * @param {int} index         - メッセージインデックス
 */
const outmsg = (index) => {
    var msg = '';
    switch (index) {
        case 0:
            msg = "性別"
            break;
        case 1:
            msg = "体重 Kg"
            break;
        case 2:
            msg = "身長 cm"
            break;
        case 3:
            msg = "年齢"
            break;
        default:
            msg = "???"
            break;
    }
    return msg;
}

var count = 0;             // メッセージカウンター
var msg = '';              // メッセージ
var buf = [];              // 一時バッファ 

var standard_input = process.stdin;

standard_input.setEncoding('utf-8');

console.log("性別 男性:0 女性:1");

standard_input.on('data', function (data) {
    var msg = outmsg(count);
    console.log(msg + " = "+ data);
    buf.push(data);
    count++;
    if (count == 4 ) {
        console.log("基礎代謝量 Kcal = " + mbr(buf[0],buf[1],buf[2],buf[3]));
        process.exit();
    }
    var msg = outmsg(count);
    console.log(msg);
});

説明

  • 関数 mbr 性別,体重,身長,年齢を引数として、基礎代謝量を返却します。
  • 関数 outmsg インデックスを引数として、対応するメッセージを返却します。
  • 標準入力はprocess.stdinでハンドルします。ハンドルはstamdard_inputで定義。
  • 標準入力のonイベントで入力をトラップします。
  • onイベントで入力した結果のdataをカウント順にバッファリングします。
  • カウンタが4になったら、mbr関数へバッファリングした値を引数として呼びだします。
  • mbr関数の返却値、つまり基礎代謝量を出力します。

実行方法

node mbr.js

実行結果

性別 男性:0 女性:1
0
性別 = 0

体重 Kg
69
体重 Kg = 69

身長 cm
168
身長 cm = 168

年齢
36
年齢 = 36

基礎代謝量 Kcal = 1614.615

まとめ

htmlの画面を作るまでもない、単純入力をコンソールから入力する場合、
process.stdinはonイベントでprocess.exitするまでコンソールからの入力を取得できます。
このやりかたをマスターすれば、色々応用できます。
ネットで検索すると、コンソール入力の色々な方法を見いだせます。
今回のやり方も参考にしてください。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Custom Vision でおさかな判別アプリを作成する

Custom Vision を使用して、おさかな判別アプリを作成する

Microsoft の Cognitive Services のひとつ、Custom Vision を使用して、おさかな自動判別アプリを作成します。Custom Vision API の説明は Microsoft の Document に記載がありますが、少し分かりにくかったので以下メモ代わりに残しておきます。

作成方法は超簡単で、以下 3STEP です。
1. Custom Vision リソースを作成し、Custom Vision の WorkSpace で 学習データを作成する
2. Azure App Services で アプリをデプロイする WebApp を作成する
3. Javascript コードを作成し、Custom Vision を連携させデプロイする

Custom Vision リソースを作成し、Custom Vision の WorkSpace で 学習データを作成する

Azure Portal の新規リソースの作成から Custom Vision を作成します。
デプロイしたリソースのページにCustom Vision に飛ぶことができるリンクがあるので、Custom Vision のポータルへ移動します。(.NET で学習データを作成する方法などありますが、今回は簡単さを求めています。)

Custom Vision Portal にて新しいディレクトリを作成し、学習データを作成します。
以下は Microsoft の Docs によくまとまっているので、この手順に沿って、Publish まで進みます。
https://docs.microsoft.com/ja-jp/azure/cognitive-services/custom-vision-service/test-your-model

Azure App Services でアプリをデプロイする

まずは、Web App を作成します。
※特に注意書きはないですが、Custom Vision と同じ region の方がコスト/速度は良いと思います。
以下GitHub にサンプルコードをアップロードしているのでローカルに保存してください。
https://github.com/komiyasa/FishRecognizerSample

ローカルに保存したファイルを FTP や Git などを用いて WebApp にデプロイしてください。

JavaScript で Custom Vision を扱う

サンプルコードの中の二か所の部分をいじるだけで、Custom Vision と連携させることができます。

$(function () {

    var uploadedImage;

    // 画像を画面に表示
    var showImage = function () {
        if (uploadedImage) {
            var blobUrl = window.URL.createObjectURL(uploadedImage);
            $("#ImageToAnalyze").attr("src", blobUrl);
        }
    };

    //画像の分析    
    var getFaceInfo = function () {

        // Custom Vision の Subscription Key と URL をセット
        // サブスクリプション画面に表示される URL および Key をコピーしてください
        var predictionKey = "<Custom Vision の Prediction Key を入力>";
        var endpoint = "EndPointのURLを入れる";

        // Custom Vision 呼び出し URL をセット
        var webSvcUrl = endpoint;       

        // 画面に表示するメッセージをセット
        var outputDiv = $("#OutputDiv");
        if(document.getElementById('imageFile').value == "")
        {
            // 初期設定
            outputDiv.text("画像を選択してください");
        }
        else{
            // 画像分析中
            outputDiv.text("分析中...");
        }

        // Face API を呼び出すためのパラメーターをセットして呼び出し
        var xmlHttp = new XMLHttpRequest();
        xmlHttp.open("POST", webSvcUrl, true);
        xmlHttp.setRequestHeader("Prediction-Key", predictionKey);
        xmlHttp.setRequestHeader("Content-Type", "application/octet-stream");
        xmlHttp.send(uploadedImage);
        xmlHttp.onreadystatechange = function () {

            // データが取得出来た場合
            if (this.readyState == 4 && this.status == 200) {

                let data = JSON.parse(this.responseText)

                // 判別結果を取得
                var predictions = data.predictions;

                var probability = [];
                var tagName = [];
                for ( var i = 0; i < predictions.length; i++ )
                {
                    probability[i] = predictions[i].probability;
                    tagName[i] = predictions[i].tagName;    
                }

                //小数点6位までを残す関数 (判別スコアの丸めに利用)
                function floatFormat( number ) {
                    return Math.round( number * Math.pow( 10 , 6 ) ) / Math.pow( 10 , 6 ) ;
                }

                var outputText =  "このおさかなは、<br>";
                outputText +=  tagName[0] + "<br>です!<br>" + "信頼度は、 "+ floatFormat(probability[0])*100+ "%";
                outputDiv.html(outputText);

            }
            else
            // データが取得できなかった場合
            {
                outputDiv.text("ERROR!");
            };
        };
    };

    // 画像が変更された場合(再度分析&表示)
    $("#imageFile").on('change', function(e){
        uploadedImage = e.target.files[0];
        showImage();
        getFaceInfo();
    });

});

以上です。
上手くいくと、以下のようにおさかな判定アプリが完成します。
image.png

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScript 覚えておくべき注意点!(3) 複数の条件を組み合わせた条件式の書き方 例 ピザ屋 && || !

if文やelse if文を組み合わせればたいていの条件を書くことができます。ただし、複数の条件をすべて満たす場合や、どれか1つでも満たす場合に何かをさせたい場合は、if文を組み合わせるよりも論理演算子を使った方がシンプルです。

論理演算子「&& || !」を使う

and_or.js
<!-- 両方とも真のときだけ真になる: &&なしで書いた場合 -->
if (ピザを注文) {
    if (コーラを注文) {
        50円割引
    }
}

// 両方とも真のときだけ真になる: &&で書いた場合 : AND &&
if (ピザを注文 && コーラを注文) {
    50円割引  //……セット割引
}

// どちらか真なら真になる : OR ||
if (ピザを注文 || コーラを注文) {
    50円割引  //……どちらも割引
}

// 条件の否定 : NOT !
if (!ピザを注文) {
    送料300円  //……ピザを注文していない場合
}

お腹の空き具合に応じて注文を変更する

app-1.js
var budget = prompt('所持金を数字で入力してください');
budget = parseFloat(budget);

var isHungry = confirm('お腹は空いていますか?'); /* 空腹か確認
confirmは確認ボタンの意 [OK]が「true」、[キャンセル]が「false」。*/
if (budget >= 1500 && isHungry) {
  alert('ピザを注文しました');// 「&& isHungry」を追加
} else if (budget >= 500) {
  alert('ポテトを注文しました');
} else {
  alert('節約、節約...');
}

※ 参照 いちばんやさしいJavaScriptの教本

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Java(while文)基本問題

もう一度基本を見直すために、過去にやったJavaのwhile文問題のアウトプット

問1

サイコロを2個ふるよぞろ目が何回目にでるかな?

[実行例]

1回目(2,3) 2回目(3,2) 3回目(4,4) 3回目にぞろ目がでました!

[解答例]
import java.util.*;
public class Main{
    public static void main(String[] args){
        Random rand=new Random();
        int count=0;
        while(true){
            count++;
            int dice1=rand.nextInt(6)+1;
            int dice2=rand.nextInt(6)+1;
            System.out.printf("%d回目(%d,%d)%n",count,dice1,dice2);
            if(dice1 == dice2){
                break;
            }
        }
        System.out.println(count+"回目にぞろ目がでました!");
    }
}


問2

以下の処理を実現せよ。

[実行例]

9
8
7
6
5
4
3
2
1
発射!

[解答例]

java
import java.util.*;
public class Main{
public static void main(String[] args){
int n=9;
while(n>0){
System.out.println(n);
n--;
}
System.out.println("発射!");
}
}


問3

1~999までの乱数を繰り返し生成し777が最初に出るまでの回数を表示せよ。

[実行例]

1:34 2:432 3:321 ..... 1034:777 1034回目に777がでました!

[解答例]
import java.util.*;
public class Main{
    public static void main(String[] args){
        Random rand=new Random();
        int num=-1;
        int count=0;
        while(num !=777){
            count++;
            num=rand.nextInt(999)+1;
            System.out.printf("%d:%d%n",count,num);
        }
        System.out.println(count+"回目に777がでました!");
    }
}


問4

[実行結果]
正の整数>20
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16
17
Fizz
19
Buzz

[解答例]
public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        System.out.print("正の整数>");
        int max=sc.nextInt();
        int i=1;
        String ans;
        while(i<=max){
            if(i %3 == 0 && i % 5== 0){
                ans="FizzBuzz";
            }else if(i % 3==0){
                ans="Fizz";
            }else if(i % 5==0){
                ans="Buzz";
            }else{
                ans=i+"";
            }
            System.out.println(ans);
            i++;
        }
    }
}

}

って認識です。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

webプログラミング演習ノート 3回目

webプログラミング演習 2019/10/8

復習から

/lesson3/form.phpにアクセスして formをつくり数字をいれて結果をresult.phpに出力する。/

  • 3の倍数の場合 Foo
  • 5の倍数の場合 Bar
  • 15の倍数の場合FooBar

と出力する。

わからない人は モジュル演算 phpとかで調べるといいよと言われました。

やり方がわからなかったのでリサーチして参考にしたのは何故かJSの記事草 ここ

result.phpにはこんな感じで書きました。

result.php
<?
$val = ['value']

    if( $val % 3 == 0 ){
        echo "Foo<br />";
    }
    if( $val % 5 == 0 ){
        echo "Bar<br />";
    }
    if( $val % 15 == 0 ){
        echo "FooBar<br />";
    }
?>  

こっちはform.php↓

form.php
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>webプログラミングむずいよ</title>
</head>
<body>
<form action="/lesson3/result.php" method="POST">
<input type="text" name="value1" value="0" />
    <button value='foobar'>ボタン</button>
</form>

</body>
</html>

絶対違うけどこれで動いてしまった、そして先生の模範解答は・・・

まずはform.phpの方から

form.php
<!DOCTYPE html>
<html><body>
<form action="/lesson3/result.php" method="POST"></form>
<input type="text" name="number">
<button>ボタン</button>    
</body>
</html>

そしてこっちがresult.php

result.php
<?
$num = $_POST['number'];
$msg = '';
if($num %3 == 0){
    $msg = 'Foo';
}
if($num %5 == 0){
    $msg = 'Bar';
}
if($num %15 == 0){
    $msg = 'FooBar';
}
?>

いきなり「はい、15分でやってくださーい」と言われて焦ったけどもなんとかそれっぽくできた!
まだ舞える

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

webプログラミング演習ノート 3回目(3限)

webプログラミング演習 2019/10/8

復習から

/lesson3/form.phpにアクセスして formをつくり数字をいれて結果をresult.phpに出力する。/

  • 3の倍数の場合 Foo
  • 5の倍数の場合 Bar
  • 15の倍数の場合FooBar

と出力する。

わからない人は モジュル演算 phpとかで調べるといいよと言われました。

やり方がわからなかったのでリサーチして参考にしたのは何故かJSの記事草 ここ

result.phpにはこんな感じで書きました。

result.php
<?
$val = ['value']

    if( $val % 3 == 0 ){
        echo "Foo<br />";
    }
    if( $val % 5 == 0 ){
        echo "Bar<br />";
    }
    if( $val % 15 == 0 ){
        echo "FooBar<br />";
    }
?>  

こっちはform.php↓

form.php
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>webプログラミングむずいよ</title>
</head>
<body>
<form action="/lesson3/result.php" method="POST">
<input type="text" name="value1" value="0" />
    <button value='foobar'>ボタン</button>
</form>

</body>
</html>

絶対違うけどこれで動いてしまった、そして先生の模範解答は・・・

まずはform.phpの方から

form.php
<!DOCTYPE html>
<html><body>
<form action="/lesson3/result.php" method="POST"></form>
<input type="text" name="number">
<button>ボタン</button>    
</body>
</html>

そしてこっちがresult.php

result.php
<?
$num = $_POST['number'];
$msg = '';
if($num %3 == 0){
    $msg = 'Foo';
}
if($num %5 == 0){
    $msg = 'Bar';
}
if($num %15 == 0){
    $msg = 'FooBar';
}
?>

いきなり「はい、15分でやってくださーい」と言われて焦ったけどもなんとかそれっぽくできた!
まだ舞える

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vue.jsを全く知らない状態から、とりあえず使ってみるまで

業務でVue.jsを使えないとメンテ出来ない事があるので、とりあえず使って概要を抑える
ことにしました。

とりあえず使えるようにする設定

インストール

Vue.js公式のインストールの項目に書いてある、CDNでのインストールを試します。

CDNでのインストールであれば、htmlのhead内に以下を書くだけで使用出来ました。

<head>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.6.0"></script>
</head>

vueインスタンスの生成

以下を追加する事でVue.jsインスタンスを作成する事が出来、実際に使用していく事が出来ます。

</body>
<script>
  var app = new Vue({
    // newしてvueインスタンスというものを作る。vueの処理はここに書いていく。
  })
</script>

今回はとりあえず使ってみる事が目的なので、Vue.jsの構文を</body>の下あたりに直接<script></script>で書いてしまいます。

データバインディング

データバインディングとは、データを同期させて表示に反映させる事。

まず、vueインスタンス内にel: '#id名'と書き、html内のidと紐づけてみます。

<body>
  <div id="app">
  </div>
</body>
<script>
  var app = new Vue({
    el: '#app' // id="app"を指定して、その配下のhtmlにVue.jsを反映させる
  })
</script>
</html>

データオプション作成とhtml内での展開

Vue.jsではvueインスタンス内にdataオプションでデータを定義した後、html内で{{ 展開したいdataのキー }}のように書く事でデータを展開して表示出来ます。

{{}}で囲って書く事をマスタッシュ構文と言います。

<body>
  <div id="app">
    {{ greet }}  // 3. 作ったデータをマスタッシュ構文で展開
  </div>
</body>
<script>
  var app = new Vue({
    el: '#app',
    data: {                 // 1. データオプションでデータを用意する
      greet: 'Hello Vue.js' // 2. greetというキーで'Hello Vue.js'というデータを作る
    }
  })
</script>
</html>

完成

最終的に以下のようになります。

<html>
  <head>
      <script src="https://cdn.jsdelivr.net/npm/vue@2.6.0"></script>
  </head>
  <body>
    <div id="app">
      {{ greet }}
    </div>
  </body>
  <script>
    var app = new Vue({
      el: '#app',
      data: {
        greet: 'Hello Vue.js'
      }
    })
  </script>
</html>

Vue.jsの基本構文

先ほどの完成形を以下のようにテンプレートとして使い、Vue.jsの基本構文を使ってみました。

<html>
  <head>
      <script src="https://cdn.jsdelivr.net/npm/vue@2.6.0"></script>
  </head>
  <body>
    <!--ここにhtmlとVue.jsの構文を書く-->
  </body>
  <script>
    // ここにVue.jsのデータを設定する
  </script>
</html>

v-bind

vueオブジェクト内に定義したdataオプションのキーをv-bind:valueに設定する事でデータを表示します。

  • html
<div id="app">
  <input type="text" v-bind:value="message">
</div>
  • Vue.js
var app = new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue.js!'
  }
})

v-if

dataオプションで設定した真偽値によって表示、非表示を切り替えます。
下記の例だとon_offが偽の場合、pタグごと表示を消します。

  • html
<div id="app">
  <p v-if="on_off">
    Hello
  </p>
</div>
  • Vue.js
var app = new Vue({
  el: '#app',
  data: {
    on_off: true
  }
})

v-show

v-showはv-ifの例のように表示、非表示を制御出来ますが、タグ毎非表示にするのではなく、
display: none;にします。

  • html
<div id="app">
  <p v-show="on_off">
    Hello
  </p>
</div>
  • Vue.js
var app = new Vue({
  el: '#app',
  data: {
    on_off: true
  }
})

v-for 繰り返し

要素の個数分繰り返して表示出来ます。
dataオプションで設定した配列colorsを1つずつcolorに入れて表示します。

  • html
<div id="app">
  <ol>
    <li v-for="color in colors">{{ color }}</li>
  </ol>
</div>
  • Vue.js
var app = new Vue({
  el: '#app',
  data: {
    colors: ['Red', 'Greeen', 'Blue']
  }
})

v-on イベント処理

クリックされた時の動作など、イベント処理を設定出来ます。

  • html
<div id="app">
  <button v-on:click="on_click">
    クリックボタン
  </button>
</div>
  • Vue.js
var app = new Vue({
  el: '#app',
  methods: {
    on_click: function() {
      alert('クリックされました');
    }
  }
})

v-model 双方向バインディング

データを共有してリアルタイムで変更を反映します。
1つ目のテキストボックスに入力すると、dataオプションのtextが更新され、2つ目のテキストボックスにもすぐに反映されます。

  • html
<div id="app">
  <p>
    <input type="text" v-model="text"> // 1つ目のテキストボックス
  </p> 
  <p>
    <input type="text" v-model="text"> // 2つ目のテキストボックス
  </p> 
</div>
  • Vue.js
var app = new Vue({
  el: '#app',
  data: {
    text: 'Hello'
  }
})

まとめ、感想

とりあえず使ってみて、なんとなくこんな感じか?というところはわかりました。
でもQiitaにあるVue.jsでゲーム作る記事とか見てると、まだ全体の1%くらいしか理解してない感じがする^^;
とりあえず何かアプリを作りたいところです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Nodeでスプシデータをcsv→jsonに変換して、条件に合う要素をリスト化する

スプシの大規模データを整理するときに楽になったので備忘録として残します。

この記事で扱うデータはフィクションです。実在の人物や団体などとは関係ありません。

※この記事のダミーデータはこちらからお借りしています。
テストデータ・ジェネレータ

スクリーンショット 2019-10-08 12.12.57.png
この記事の目標 : 住所が大阪の人をリストアップしてテキストデータに書き出す!

使用環境

OS: macOS
Node: v12.2.0
npm: 6.9.0

パッケージのインストール

Nodeとnpmの環境設定は省略しています。
まずはターミナルから適当なプロジェクトフォルダに必要なパッケージをインストールします。

$npm init -y
$npm i -D fs csvtojson js-beautify

csvtojsonがコンバータ

csv -> json の変換

スプシからcsvをダウンロード
スクリーンショット 2019-10-08 11.59.56.png

変換スクリプトを書く

csvjson_converter.js
let fs   = require('fs');
let csv  = require('csvtojson');
let beautify = require('js-beautify').js;

let csvFile = './checksheet.csv';


csv().fromFile(csvFile).then((jsonData)=>{
  fs.writeFile('checksheet.json', beautify(JSON.stringify(jsonData),{}), function(err) {
    if (err) console.log('error', err);
  });
});

スプシからダウンロードした[checksheet.csv]を[checksheet.json]に変換して
beautifyでインデントを追加して書き出す命令を記述。

$ node csvjson_converter.js

ターミナルからスクリプトを実行
スクリーンショット 2019-10-08 12.26.18.png
こんな感じのjsonが書き出されました。

必要な要素をリスト化してテキストデータに保存する。

条件を絞って、[.txt]データに書き出します。

checkitem.js
let fs   = require('fs');

// check item
let json = JSON.parse(fs.readFileSync("checksheet.json"));
let target_item = [];
json.forEach(function(value,index){
  if(value.住所.match(/大阪/)){
    // console.log(value.url);
    target_item.push(value.名前+" : "+value.住所+"\n");
  }
});

fs.writeFile('大阪の人.txt',target_item,function(err){
  let texts = fs.readFileSync('大阪の人.txt','utf-8');
  console.log(texts);
  fs.writeFile('大阪の人.txt',texts.replace(/\,/g,""),function(err){});
});

先ほど書き出した[checksheet.json]を読み込んで、[住所]の項目が[大阪]を含む値を判定。
条件に当てはまったデータを[大阪の人.txt]に書き出し。

$ node checkitem.js

ターミナルからスクリプトを実行

正しく出て来た。

スクリーンショット 2019-10-08 12.36.47.png

この記事で扱うデータはフィクションです。実在の人物や団体などとは関係ありませ

条件式の使い方次第で色々絞り込めます。
↓生年月日から20代を絞り込みの場合

checkitem.js
//if(value.住所.match(/大阪/)){
if(1998 >= value.生年月日.slice(0,4) && 1989 <= value.生年月日.slice(0,4)){

おわりに

スプシのフィルタ機能でカバーできない様な、痒いところに手が届いた気がしました。
スプシ1行目に空のデータがあると、自動で "field番号":[{値},{..}]が当て込まれるので注意です。

うまく書き換えて、ejsを使ったHTML書き出しにも使えそうです。

出典

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[初心者]Nuxt.jsビギナーズガイド Vue.js ベースのフレームワークによるシングルページアプリケーション開発

はじめに

noteのフロントエンドをNuxt.jsへ刷新します はもう昨年のことかと思いながら、Nuxt.jsを習得してみる。Universal Application、Progressive Web Applicationなど、これからのWebにとって当たり前の技術を身につける。

Nuxt.jsビギナーズガイド Vue.jsベースのフレームワークによるシングルページアプリケーション開発 を簡単にまとめてみた。JavaScript初心者の私でも非常に理解しやすく、Qiitaにいいねをつけていただいた上で、ご購入をおすすめします。

Nuxt.jsビギナーズガイド Vue.js ベースのフレームワークによるシングルページアプリケーション開発

1. Nuxt.jsの概要

01. 「モダンフロントエンド」のイマ

今日フロントエンドは非常に安定し停滞した状態が続いている。トラディショナルなサーバーがHTMLを返す時代から、SPAとAPIによるWebアプリケーションがデファクトスタンダードになった。当分はReact、Vue、Angularの寡占状態は変わることはなく、技術的にも枯れている。先進的な機能(Web Worker、Web Assembly)も追加されているが、実用段階まで民主化されてはいない。

モダンフロントエンドは、多種多様な選択肢があり柔軟な開発が可能。しかしそれは、アプリケーションの本質的な価値ではない領域と付き合い続ける必要があるともいえる。現在では、どの領域にも著名な技術がシェアを占めており、効率化することに妥当性を覚える段階では、開発者自身が技術を選定し続ける理由はない。

一部でしか使われていない技術(GraphQL)にも対応できるだけのアーキテクチャとエコシステム、コミュニティが求められている。Nuxt.jsは、その要件を満たしている。Vue.jsの記法や設計の資産をそのままに、負債となりやすい部分(webpack、モジュールの最適化、サーバーサイドレンダリング(SSR))までカバーしている。またサードパーティライブラリやVueプラグインによるアプリケーションのコア拡張も、ミドルウェアやプラグインといった独自システムによってメンタナリビリティの高い、統一的なアーキテクチャでの運用が可能。またVue.jsの範囲だけに限らず、Nuxt.js内に形成されたシンプルな拡張システムのもとにaxiosやJSON API、GraphQLサーバーへのリクエストなども可能。

02. Nuxt.jsとは

当初はVue.jsアプリケーション開発におけるSSRを支援することを目的として始まった。Next.jsはReactらしいUNIX文化を引き継ぎ、Nuxt.jsは規約をベースとしたAngularのようなフルスタックフレームワークの道を辿る。

2016年10月25日zeit.coのチームがReactアプリケーションをサーバーサイドレンダリングするためのフレームワークNext.jsを発表しました。その発表から数時間後、Next.jsと同じ方法で、Vue.jsアプリケーションをサーバーサイドレンダリングするアイディアが生まれました。すなわちNuxt.jsが誕生したのです。

※Zeit社は、ミニマルなNode.jsのサーバー構築ライブラリ microやElectron製のターミナル Hyper、Node.js/Dockerホスティングサービス Nowを開発、運用している企業である。

Nuxt.jsの特徴と機能

  • ビルドプロセスの隠蔽

Vue.jsによるSPA開発は、設定すべきビルド環境が多くwebpackを中心として多くのローダーやプラグインを導入、メンテナンスする必要がある。Nuxt.jsは、基本的にはすべての設定を所持、最適化した形でメンテナンスされており、webpackを意識する必要があるのはカスタマイズしたローダーやプラグインを追加したい場合だけ。

  • Vueのエコシステムとのインテグレーション

Vue.jsは、Vue Router、Vuex、Vue Server Renderer、vue-metaが密接に連携するように作られており、定型句をもとに個別設定する必要がある。Nuxt.jsは、すべてが設定されており、独自レイヤからも扱いやすいようにカスタマイズされている。

  • 独自レイヤの実装

独自レイヤは、Vue.jsの機能不足な部分を、Nuxt.jsが追加で実装した概念。例えば、middleware(アクセス時のフックとして機能する)は、内部で任意の処理やルーティングを改ざんすることが可能。SSR時は認証情報などに応じて柔軟に301/302リダイレクトを行う機能を提供し、SPAモードでは適切な初期データの格納などで利用できる。またVue.jsでは独自で設けるプラグイン領域は、pluginsディレクトリ内で包括的に管理できる。

03. Nuxt.jsがもたらすもの

Ruby on Railsは、規約の代表として広く知られている。暗黙知を大量に作ることを許容する代わりに、多くのWeb開発における頻出パターンを効果的に実装できる。同様にNuxt.jsは、Vue.js開発においての定型パターンを規約と定めている。例えば、「pagesディレクトリに置かれる.vueファイルはページを表す」という規約を守ることにより、開発者はVue Routerの煩雑な設定の記述とメンテナンスから開放される。また「data関数の代わりにasyncDataを利用する」という規約を守ることにより、簡単にSSRやアプリケーションとの連携に強いVueコンポーネントを開発できる。

つまり納得感のある、統一的な記述が守られる結果、多くのコスト(どちらでも良い設計の議論など開発におけるノイズから、単純なコードの記述量まで)を省略でき、効率的な開発に大きく寄与する。この規約に対する考え方は、Angularと近いものがある。両者は、JavaScript/TypeScriptらしさが好みなのか。他のエコシステムの資産を十分に活用して柔軟に対処したいのか、1つの設計の中ですべてを閉じて堅牢な形で運用したいのか程度の違いしかない。Nuxt.jsは比較的攻めの規約、Angularは守りの規約といえる。

04. Nuxt.jsがマッチするプロジェクトやシチュエーション

Vue.jsの中級者以上が1人でもいるVue.jsのSPAプロジェクトにはおすすめ。Vue.jsの柔軟さゆえに汎用性のない独自のアーキテクチャを考案・運用する代わりに、Nuxt.jsという1つのルールを中心に据えることで秩序のある開発が可能。またNuxt.jsでカバーできないものは、モジュールシステムを利用することでNuxt.jsのレールから逸脱しない。

メンバー間でVue.jsのレベル差が激しい場合にもおすすめ。Vue.jsは柔軟性ゆえバッドノウハウをつかみやすい。ベストプラクティスが分からない状況では、短期的な生産性の高い開発手法を選択してしまいがちだが、Nuxt.jsを利用することで短期的な生産性を落とすことなく効果的な設計を適用することが可能。

メンバー全員が初学者である場合とSPAでない場合はおすすめしない。規約によって整備されていて誰でも扱いやすいように見えるが、ミドルウェアやプラグインなど独自機能やVue.jsを拡張していることによる独自のライフサイクルなど、学習コストが高い。このような場合は、 Vue CLI を利用した開発をおすすめする。

2. Nuxt.jsによるシングルなアプリケーション開発

QiitaAPIを利用してNuxt.jsタグの投稿一覧を表示し、その投稿から投稿者のプロフィールと投稿一覧を表示するサービス。axiosを利用したHTTPリクエスト、動的なルーティングによるコンテンツの出し分け、SSR、SEO対策、Vuexストア(クラシックモード)を理解できる。

$ vue init nuxt-community/starter-template hoge

※サンプルアプリケーションの詳細な解説は、Nuxt.jsビギナーズガイドをご購入ください。

Nuxt.jsによるシングルなアプリケーション開発

3. Nuxt.jsの機能の活用

01. layoutsディレクトリによるレイアウトの共通化

Vue.jsでは共通化して効率化したいモチベーションと、共通化した際の編集コストや管理コストの増加という問題を天秤にかける。それに対してNuxt.jsは、簡単な切り分けや宣言的な記述方法によって、複雑な管理なしにレイアウトの共通化が可能。

default.vue をトップページ用に、個別ページを single.vue にした場合、すべてのコンポーネントに対して layout: 'single' を指定する必要があり適用忘れが生じる可能性が高い。トップページはLPやダッシュボードのサマリなど他のページとは大きく異なるデザインが多いため、トップページだけ layout: 'home' を指定することがベストプラクティス。大規模プロジェクトだと、default.vue を使わない方がわかりやすい場合もある。

※サンプルアプリケーションの詳細な解説は、Nuxt.jsビギナーズガイドをご購入ください。

c08fb065f34d44e2e6ee7b834fdf8cd9.gif

02. Nuxt.jsのライフサイクル

Nuxt.jsはアクセスがあった際に、次の図のようなライフサイクルを形成する。これらの処理が完了後、Vue.jsのライフサイクルが呼び出される。プラグインはさらに前に呼ばれる。ライフサイクルを意識することで、それぞれの責務を理解した開発が可能。

Nuxt.jsのライフサイクル

03. middlewareによるグローバルなフックの登録

middlewareは、機能面の追加としてもっとも強力な機能。グローバルを含めた任意のルーティングへのアクセス時の最初に読み込まれるため、SSR処理などが行われる前に様々な処理を行うことが可能。また default export によって、1つの関数を返すファイルにする必要がある。

今回は universal-cookie を用いて、簡単なログインを必要とするページを作成する。認証には contextオブジェクト を用いて、リクエストデータとrouteオブジェクトとredirect関数を受け取り実装する。

エンドポイント 認証の振り分け
http://localhost:3000/ 誰でもアクセス可能・それぞれのページへのリンクが存在する
http://localhost:3000/login 未ログインユーザーのみ・ログインしている場合は「/」へ
http://localhost:3000/authed-route ログイン済ユーザーのみ・ログインしているしていない場合は「/login」へ

※サンプルアプリケーションの詳細な解説は、Nuxt.jsビギナーズガイドをご購入ください。

middlewareによるグローバルなフックの登録

04. プラグインによるVue.jsプラグイン資産の有効活用

プラグインは、npmパッケージやVueプラグイン、特定の処理をグローバルに登録し再利用性を高めるために利用する。主にUIフレームワークやFirebase SDK、momentなど、必ずアプリケーション全体で利用するライブラリの導入時に利用する場合と、ルーティングフックや初期段階での外部CDNコードの読み込みなどの共通処理を実装する場合に利用する。メリットは、Nuxt.jsの規約の上で開発が可能なことと、SSR時に呼び出すかをオプションで簡単に切り替えることができること。

今回は、VueRouterのbeforeEachフック利用して、ページ遷移ごとにルーティングのパスをロギングしてみる。plugins: ['~/plugins/logger'] は、 plugins: [{ src: '~/plugins/logger', ssr: true }] と等価。実際の開発では、GoogleAnalyticsや mixpanel などの設定で利用する。

※サンプルアプリケーションの詳細な解説は、Nuxt.jsビギナーズガイドをご購入ください。

プラグインによるVue.jsプラグイン資産の有効活用

05. Vuexのモジュールモードを活用したオートローディング

  1. Nuxt.jsによるシングルなアプリケーション開発

で、Vuexストアのクラシックモードを利用した。自身でVuexを読み込み、ストアインスタンスを生成する形でVuexストアを構築する。本格的なアプリケーション開発ではモジュールモードを利用する。Vuexストア自体に関わるコードは一切記述せず、Vuexストア内で利用するモジュールのビジネスロジックのみ記述する。モジュールを規約に沿って記述しexportするだけで、自動的に名前空間付きのモジュールと解釈しVuexストアインスタンスを生成する。

モードと構造の判別は以下で行なっている。

  • index.jsはルートモジュールである
  • index.jsがオブジェクトをエクスポートしている、もしくは存在しない場合はモジュールモードで動作する。Vuexストアをインスタンスをエクスポートしている場合は、クラシックモードで動作する
  • index以外の名前を持つJavaScriptファイルは、ファイル名のスコープによるモジュールとして作用する

最終的に出力されるVuexストア構造は完全に同じであり、モジュールモードの方が構造について強く意識せずモジュールの記述に集中できる。

クラシックモード

store/users.js
new Vuex.Store({
  state: { isLoading: false },
  mutations: {
    setIsLoading(state, isLoading) {
      state.isLoading = isLoading
    }
  },
  modules: {
    users: {
      state: {
        list: []
      },
      mutations: {
        addUser(state, user) {
          state.list.push(user)
        }
      },
      actions: {
        addUser({ commit }, { user }) {
          commit('addUser', user)
        }
      }
    }
  }
})

モジュールモード

store/user.js
export const state = () => ({
  list: []
})

export const mutations = {
  addUser(state, user) {
    state.list.push(user)
  }
}

export const actions = {
  addUser({ commit }, { user }) {
    commit('addUser', user)
  }
}

4. 中規模以上の開発を意識したNuxt.jsによるWebアプリケーション開発

ブログサービスを作成する。バックエンドに Firebase Realtime Database を利用してAPIサーバを用意して、ユーザ情報と投稿といいねデータをやりとりできるようにする。フロントエンドでは、ElementUIを利用して全体の投稿の一覧や、ユーザごとの投稿の一覧を閲覧できるようにする。

$ create-nuxt-app hoge

プロジェクトのディレクトリをappディレクトリ配下にいれているのは、アプリケーションのコアコードとそれ以外のコードを明確にするため。また各種ツールのパス指定を簡潔にするため。例えば、Lintやコードフォーマット形式外の箇所を1つずつignoreする必要がない。

※サンプルアプリケーションの詳細な解説は、Nuxt.jsビギナーズガイドをご購入ください。

ブログサービス

5. Nuxt.jsアプリケーションのテスティング

01. フロントエンドにおけるテストの必要性

従来は、UI層と密接に関係しているためや外部のSDKを読み込むため、API接続があることためテストが難しかった。またSeleniumなどのe2eテストツールは存在したが、DOMやブラウザに強く依存するため、作成コストは高いがテストの寿命は短かった。

UTはVuexデータストアと挙動が複雑なVueコンポーネント、フレームワークに依存しないレイヤのコードをテストすべきである。Jestを利用すると良い。アサーションライブラリからテストランナー、カバレッジレポーター、スナップショットテストまで内包しており、特有の設定を覚える必要がない。

$ yarn add -D jest @vue/test-utils lodash.clonedeep babel-jest 'babel-core@^7.0.0-0' @babel/core babel-preset-vue-app vue-jest

6. アプリケーションのデプロイと運用

名称 モード 学習コスト 運用コスト メタタグ対応(SEO/OGP) 拡張の柔軟性
Universal(デフォルト) SSR 高い 高い ? ?
Generate SPA 低い 低い ?‍♂️ ?‍♂️
SPA SPA 非常に低い 低い ?‍♀️ ?‍♂️

デプロイ先はService Level Agreement(uptime)やレイテンシ、運用コストなど総合的な判断が必要。

SSR

静的サイト

(Netlify参考記事)
【爆速】静的ページを無料で独自ドメインでSSL(HTTPS)で公開する方法(Github => CircleCI => AWS S3 / Firebase Hosting / Netlify)

7. プラグインとモジュール、エコシステムの開発・貢献

  • @nuxtjs/axios
  • json-server
  • @nuxtjs/pwa

(PWA参考記事)
[Nuxt/WebSpeechAPI]騒がしい居酒屋でもワンタップで店員さんを呼ぶサービス「親指ですみません」

サードパーティモジュールの探し方は、以下リポジトリから探すのが良い。また本書では自作プラグイン・モジュールの開発からnpmへの公開まで記載されています。

8. 最新技術のキャッチアップのススメ

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[JavaScript] イベントリスナーを複数同時に設定可能な関数またはメソッドを作成する

jQuery の on の使い方に慣れていると addEventListener に同時に複数のイベントを登録したいときがあります。

通常の書き方

const target = document.querySelector("設定対象");
target.addEventListener("click", MyFunc);
target.addEventListener("keydown", MyFunc);

MyFunc の部分には自身で定義した関数を登録します。
querySelector の使い方は割愛します。

代わりの関数を作成する場合

TypeScript

const addMultipleEventListener = (element: Element | null, eventNames: string, listener: listener): void => {
    const target = element as EventTarget;
    const events = eventNames.split(" ");
    events.forEach((event: string) =>
        target.addEventListener(event, listener, false)
    );
};

JavaScript

const addMultipleEventListener = (target, eventNames, listener) => {
    const events = eventNames.split(" ");
    events.forEach(event => target.addEventListener(event, listener, false));
};

使い方

const target = document.querySelector("設定対象");
addMultipleEventListener(target, "click keydown", MyFunc);

本来の addEventListener とは使い方が若干異なります。

jQuery の on 相当のメソッドを追加する場合

Reflect.defineProperty を使用することで、
該当のメソッドが存在しない場合にオリジナルのメソッドを生やせます。

TypeScript

type listener = EventListener | EventListenerObject | null;
Reflect.defineProperty(EventTarget.prototype, "on", {
    configurable: true,
    enumerable: false,
    writable: true,
    value: function(eventNames: string, listener: listener): void {
        const target = this as EventTarget;

        const events = eventNames.split(" ");
        events.forEach((event: string) =>
            target.addEventListener(event, listener, false)
        );
    },
});

on の型定義で怒られる場合

TypeScript で Element や EventTarget に on がないと怒られる場合は型定義を拡張します。

type listener = EventListener | EventListenerObject | null;

declare global {
    interface EventTarget {
        on(eventNames: string, listener: listener): void;
    }
    interface Element {
        on(eventNames: string, listener: listener): void;
    }
}

JavaScript

Reflect.defineProperty(EventTarget.prototype, "on", {
    configurable: true,
    enumerable: false,
    writable: true,
    value: function(eventNames, listener) {
        const events = eventNames.split(" ");
        events.forEach(event => this.addEventListener(event, listener, false));
    },
});

使い方

const target = document.querySelector("設定対象");
target.on("click keydown", MyFunc);

厳密には jQuery の on よりもシンプルな実装なので、完全再現するにはもう少し手を加える必要があります。

サンプル

参考にした記事

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

5分でわかる「今更だけどReactってなに?」

2年ぶりくらいに業務で React をやることになったので、個人的なおさらい用です。

React ってなに?

React は UI を作るためのライブラリです。

UI は「コンポーネント」という概念によって記述することになります。
基本的にはユーザーが自由に実装した「カスタムコンポーネント」を UI 毎に作成し、それを組み立てることで Web アプリケーションを構築することができます。
HTML の DOM 要素を利用したコンポーネントを作成するには React.DOM オブジェクトを利用しすることもできます。

React の特徴

以下の4つが React の特徴です。

  • リアクティブ
  • 仮想 DOM
  • Component ベース
  • JSX

リアクティブであること

ユーザーの操作やデータの変化を監視して、その変化によって自分で設定した処理に沿うように自動的に画面を再描画してくれます。

仮想 DOM

jQuery や一般的な JavaScript では DOM 操作を「最適化して」処理を記述する必要があります。
DOM 操作は非常にコストの大きい処理です。近年の Web 開発では非常に多くの DOM 操作を必要とします。ユーザーの操作に応じて多くのデータを更新したり、見た目を変化させるためです。

React では、仮想 DOM という React が内部に持っている独自の DOM 情報と実際の DOM を効率的な方法で比較し、差分を変更してくれるので、処理が非常に軽くなります。

注意点としては、DOM 操作を必要としないわけではなく、純粋な JavaScript を最適化した処理よりも早くなることはありません。
ですが規模の大きいアプリケーションでは全てを最適化することは現実的ではありません。
あくまで、楽にいい感じにしてくれるもの、と捉えておくと良さそうです。

Component ベース

React ってなに? でも書いたように、React はコンポーネントを作って、それを組み立てて Web 開発を行います。
では、それによるメリットはなんでしょうか。
それは、「保守性」「再利用性」「デザインシステムとの相性の良さ」が挙げられます。

保守性

コンポーネント単位で開発していくと、しっかりと設計を行うことでコンポーネントに「単一責任の原則」が生まれます。
機能・見た目・状態などをそのコンポーネントに閉じ込め、外から変更をできなくすることができます。
それにより機能の所在が明らかに別れてデバッグがしやすくなります。

再利用性

保守性で書いた単一責任の原則は再利用性の向上にも寄与します。
もしそのコンポーネントが複雑な依存関係を持っていない場合、複数の場所でコンポーネントを再利用することが可能となり、開発スピードが上がります。

デザインシステムとの相性の良さ

近年ではアプリケーション開発にデザインシステムを持ち込むことが多くなっています。
例えば Atomic Design のように Web アプリ全体をコンポーネントで分け、それを役割によって分類・管理し、それを組み合わせていくようなことが、コンポーネントベースであれば簡単に行うことができます。

JSX

JSX も React の特徴の一つです。
JSX は JavaScript の拡張構文で、JavaScript の中に文書構造を持ち込むことができるという特徴があります。
簡単にいうと、JavaScript の中で HTML が書けて、属性や文字列に変数やメソッドを埋め込むことができるというものです。

なぜ JSX が必要なのか、不思議に思う方もいると思います。
HTML と JavaScript は分離して管理すべきだ!という思想が広く定着していたこともあります。
ですが近年の Web 開発では、データをサーバーから API で動的に表示させることが非常に多いです。

ほぼ実態のない HTML 要素に JavaScript の処理を紐付けることで、意味のない空の div や空の a タグが散乱し、文書構造もなにもあったものではない状況です。
そのために WAI-ARIA という仕様が取り沙汰されましたが、先程も述べたように近年の Web 開発では「動的に」表示が変化します。つまり内容が変わってしまうのです。

それならば、JSX で記述する WAI-ARIA の状態を管理してあげたほうが、より現実的なセマンティクス Web の実現につながるのではないかという意見もあり、採用しているプロダクトが多いようです。

Accessible Rich Internet Applications (WAI-ARIA) 1.2 日本語訳

なんで React や Vue のような JavaScript ライブラリが人気なのか

ここまで React の特徴を書いた中ですでに React に対して「高機能な近年の Web アプリ開発に適していること」を感じた人も多いのではないでしょうか。

  • 肥大化した処理の DOM 操作の最適化
  • コンポーネントによる管理のしやすさ
  • JSX によるアプリケーション化した Web の管理の最適化

これらは Vue などの、どのライブラリにも大抵は共通しており、細かな振る舞いやスケーリングの思想の違いによって使い分けられています。

コンポーネントの最小構成

最小限の構成は render() という、カスタムコンポーネント(ユーザーが定義したコンポーネント)に必須のメソッドで React のコンポーネントを返す形です。

コンポーネントに「プロパティ(props)」を追加すると、その値に応じてふるまいを変更できます。
追加したすべてのプロパティは this.props でアクセスすることができ、例えば、親コンポーネントから、子孫コンポーネントに情報を渡す際に非常に便利です。

また、コンポーネントには propTypes というプロパティも追加でき、そのコンポーネントが受け付けるプロパティの名前や値の型を宣言することができます。
必須ではありませんが、データを検証することができるし、コンポーネントの仕様としても機能するため、メンテナビリティが向上するため推奨されています。
更に、 getDefaultProps() というメソッドを作成して設定することで、省略可能なプロパティのデフォルト値をオブジェクトで返すこともできます。

プロパティは変更ができないデータ(immtable data)として扱われ、getDefaultProps() で定義したデフォルト値か、親コンポーネントから受け取った値のどちらかを持っています。

状態の管理(ステート)

コンポーネントは描画する際にステートのデータを利用します。
ステートに変化があると、React は自動的に UI を再構成してくれます。つまり、最初に render() で初期描画をしたら、ユーザーの操作やデータの更新を見て render() メソッドの中で設定した表示方法に沿って UI を自動的に最適化してくれるというわけです。

ステートにアクセスするには this.state オブジェクトを使うことでコンポーネントからアクセスできます。
ステートを変更するには this.setState() を使い、このメソッドが呼ばれると render() メソッドを呼び出して UI を更新してくれます。

ステートはコンポーネント固有のデータで、データはコンポーネントからコンポーネントへ受け渡すことはしません。
コンポーネントが持つプライベート変数のようなものだと認識しておけばよさそうですね。

まとめ

ここまでお読みいただきありがとうございます!
この記事を読んで実際に触ってみたいと思った方はぜひ公式のチュートリアルを試してみてください!
導入からちょっとしたゲームの作成ができて、時間もそれほど必要ありません。(そして日本語です!)

チュートリアル:React の導入

誤りや認識の違いなどがありましたらご指摘いただけると助かります!:bow:

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Reactの入力フォームを仮想ウインドウ化する

Reactの入力フォームを仮想ウインドウ化する

sc.gif

ユーザ入力用のUIの位置決めが面倒くさい

 フロントエンドのUIを作る際、ユーザ入力を行うための場所をわざわざ作るのはそれなりに手間のかかる作業です。特に配置場所を作るのがそれなりに面倒です。今回はこれをできる限り簡単に解決する方法を解説していきたいと思います。

 こちらの記事でToDoを入力するためのアプリケーションを作ったので、その入力フォームを改造していきます。

  React-Reduxが難しい? それは過去の話だ! ~ ToDoアプリを最小限の労力で記述する ~

 今回必要とするコンポーネント
   https://www.npmjs.com/package/@jswf/react

インストールの方法

npm -D i @jswf/react

仮想ウインドウを利用する上でやるべき事

フォームの該当箇所をJSWindowで囲む

<JSWindow></JSWindow>

以上で入力フォームの仮想ウインドウ化は完了しました。お疲れ様です。

前回のプログラムを変更するとこんな感じです。

function FormComponent() {
  const todoModule = useModule(TodoModule);
  return (
   <JSWindow>{/*←追加*/}
    <div style={{ textAlign: "center" }}>
      <div>
        <div>タイトル</div>
        <input
          style={{ width: "20em" }}
          value={todoModule.getState("input", "title")!}
          onChange={e => todoModule.setState(e.target.value, "input", "title")}
        />
        <div>説明</div>
        <textarea
          style={{ width: "20em", height: "5em" }}
          value={todoModule.getState("input", "desc")!}
          onChange={e => todoModule.setState(e.target.value, "input", "desc")}
        />
        <div>
          <button onClick={() => todoModule.addTodo()}>Todoを作成</button>
        </div>
      </div>
    </div>
   <JSWindow>{/*←追加*/}
  );
}

 足したのはJSWindowだけです。これによって、以下のように仮想ウインドウ上にコンテンツが表示されるようになりました。この仮想ウインドウはサイズが可変、移動、最大化、最小化の機能がデフォルトで付いています。
image.png

 この仮想ウインドウ、閉じるボタンが搭載されているので押したら消えます。そして二度とToDOを書き込むことは出来なくなるという自由が手に出来てしまいます。

 流石にそれでは困るので、閉じたウインドウを再び開けるようにします。

interface TodoState {
  //入力中データの保持
  input: {
    title: string;
    desc: string;
  };
  //TODOリスト
  todos: {
    id: number;
    title: string;
    desc: string;
    done: boolean;
  }[];
  //TODOのID附番表index
  index: number;
  //ウインドウの状態
  windowState: WindowState; //<----- 追加
}
//初期値
protected static defaultState: TodoState = {
  todos: [],
  input: { title: "", desc: "" },
  index: 0,
  windowState: WindowState.HIDE //<----- 初期状態の追加
};

function FormComponent() {
  const todoModule = useModule(TodoModule);
  return (
    <>
      {/* ボタンの追加 */}
      <button
        onClick={()=>todoModule.setState({ WindowState: WindowState.NORMAL })}
      >
        ウインドウの表示
      </button>
      {/* タイトルとウインドウ状態設定を追加 */}
      <JSWindow title="ToDoの入力" windowState={todoModule.getState("WindowState")!}>
        <div style={{ textAlign: "center" }}>
          <div>
            <div>タイトル</div>
            <input
              style={{ width: "20em" }}
              value={todoModule.getState("input", "title")!}
              onChange={e =>
                todoModule.setState(e.target.value, "input", "title")
              }
            />
            <div>説明</div>
            <textarea
              style={{ width: "20em", height: "5em" }}
              value={todoModule.getState("input", "desc")!}
              onChange={e =>
                todoModule.setState(e.target.value, "input", "desc")
              }
            />
            <div>
              <button onClick={() => todoModule.addTodo()}>Todoを作成</button>
            </div>
          </div>
        </div>
      </JSWindow>
    </>
  );
}

 windowStateを設定すると、仮想ウインドウの状態を変更することが出来ます。ということで、ボタンを押したらステータスをNORMALに戻し再表示出来るようになりました。

まとめ

 この仮想ウインドウコンポーネントは複数表示やネストも可能です。詳細な機能に関しては

  Reactで超簡単、タグで挟み込むだけの仮想ウインドウの実装

 の記事で説明しています。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【個人開発】プログラミングを勉強したので誰かの書き込みを表示するだけのWebサイトを作った

kotoniwa

https://tzanarkand.com

何をするwebサイトなのか

ユーザーそれぞれが好きな言葉を書き込む、そして画面をクリックすると誰かが書いた言葉がランダムでぼんやりと出てくるだけのサイト。

スクリーンショット 2019-10-04 1.54.09.png
スクリーンショット 2019-10-04 1.57.32.png

使ったもの

ruby
rails
javascript
jquery
Nginx
unicorn
postgresql

自分のスキル

専門学校でサーバーとネットワークの勉強をしていたけど、プログラミングの経験はほぼ0(シェルスクリプトちょっとやったかなくらい)。

他人が書いたrailsアプリを自分が立てたapacheサーバーで公開した事はある。

railsもjavascriptもコードを見たことはあります程度。

自分で1からコードを書いてというのはこれが初めて。

勉強したこと

udemyでjavascriptとrailsとhtmlとcssの講座を購入してみたけど最初にざっと見ただけであまり活用しなかった。結局これ実際にやってみないとよくわからないな、と思ったので。

実装したいと思ったことをその都度ググって、よくわからなかったらそこを深掘りして、みたいな感じで作りながら学習を進めた。

作るまでの流れ

現在はサーバー運用系のお仕事をしていて、web系の方に転職してみようかなという思いが出てきたのでとりあえず何かを作ってみることに。

今まで自分で一からwebサイトを作ったことはなかったのであんまり難しいことをやろうとすると挫折するだろうと思い、とにかくシンプルなものを作りたかった。

wikipediaをランダムで表示したりするやつとかのランダム系のサイトが好きだったのでそんな感じのをイメージしていて、「なんでも好きに書いていい」となった時に皆がどんなことを書くのかに興味があったのでこれを作ろうと思った。

感想

とりあえず公開まで持っていけてよかった。
こんな簡単な感じのサイトでもここまで躓きポイントが大量にあるのか…と思ったので、作ろうと思っても途中で諦めてしまう人は大量にいると思う。
次はもうちょい真面目なwebサービス感のあるサイトを作る予定。
もっと技術つけてはやく転職したい。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

webRTCでtrackイベントが発火したからと言って安心してはいけない

TL;DR;

  • webRTCはtrackイベントが発火して終わりではない
  • connectionstateがconnectedになるまではシグナリングし続ける必要あり

trackで終わりではない

大体のwebRTCのサンプルを見ると、大体ontrackに設定した関数が呼び出されて、
MediaStreamが取れればめでたしめでたしといった感じになっています。

映像を映す分にはこれでOKなのですが、シグナリングのためのDB監視やwebSocket接続を
リソース管理を効率的に行おうとしてその場で切断しようとすると面倒なことになる場合があります。

時間がかかるパターンのみ引っかかるという厄介なケース

同一LAN内での接続や、STUNサーバーを利用したパターンなどでは
onTrac後即シグナリングをやめても大体問題ありませんが、TURNサーバーを使ったケースではほとんど繋がりません。
(まったくつながらないわけではないという一番いやなパターンです)

基本的に、connectionstateがconnectedになるまではシグナリングの継続は必須です。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ブログスポットの中でのMobileNet利用 / Using MobileNet inside BlogSpot

ブログスポットの中でのMobileNet利用

Using MobileNet inside BlogSpot

[Demo]
https://randomwalkjapan.blogspot.com/2019/10/mobilenetusing-mobilenet-inside-blogspot.html

[Source]
https://github.com/tanakayutaka/MobileNetOnBlogspot-Blogger-

Googleが運営する無料ブログサービスであるブログスポット(このサイト)に、カメラに映った映像を分類するMobileNetという実験プログラムを組み込んでみた。既に学習済みのネットを利用するだけで、学習は行わない。映し出された窓にはカメラの映像が、その下に画像判定結果とその可能性(0から1の範囲)が示される。計算負荷が大きいため処理が遅くなります。実行したくない人はカメラアクセスを拒否してください。

Installed MobileNet on this site, blogspot, i.e., Google's free blog service. This only classifies object based on pre-educated neural net but no new learning is done. Under the camera video shown, object name and possibilities(0-1) are shown. Due to heavy computation, reactions will be slow. Pls deny camera access if you do not wish to run.

なお、BlogSpotの記事の場所に結果を表示するには、下のようにparentメソッドを利用します。To display the result on blog body, use parent method as below.

<body>

<div id='myContainer'></div>

</body>

function setup() {

// Create a camera input

video = createCapture(VIDEO);

video.parent('myContainer')

video.size(200,300)

// Initialize the Image Classifier method with MobileNet and the video as the second argument

classifier = ml5.imageClassifier('MobileNet', video, modelReady);

resultsP = createP('Loading model and video...');

resultsP.parent('myContainer')

}

function gotResult(err, results) {

// The results are in an array ordered by confidence.

resultsP.html(results[0].label + ' ' + nf(results[0].confidence, 0, 2));

resultsP.parent('myContainer')

classifyVideo();

..Just Cut & Paste from Visual Studio Code

(also pls delete, white-space: pre; )

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む