- 投稿日:2020-05-22T23:57:29+09:00
vuexを用いたnpmパッケージの作り方
vue.jsのコンポーネントライブラリをnpmパッケージとして公開するやり方は多くありますが、vuexを用いたライブラリの作り方の記事は少なかったので、今回私が作ったライブラリを例に、ここに書き残しておこうと思います。
自己紹介
wh.im というサービスを運営しています @aitaro です。普段は大学院生やっています。wh.imの詳細はこちらの記事から。
wh.im用の開発用ライブラリを作りました
リポジトリはGithubにあります。
npmパッケージを作ったのは今回が初めてのため、間違いやよりベターな方法があればコメントで指摘いただけると嬉しいです。npmパッケージを作った背景
昨日リリースしたwh.imですが、複数のエンジニアの方から、自分もゲーム作ってみたいという声を頂きました。(ありがとうございます!)
ただ、wh.imとの連携部分など、少しクセの強いところがあったので、ライブラリ化して開発者が連携部分を意識せず開発できるようにに、今回ライブラリ作成に踏み切りました。npmパッケージ公開までのステップ
- VueCLIで新規プロジェクト作成
- 不要なファイル削除
- package.jsonの編集
- storeの読み込み & ゴリゴリ実装
- npmにアカウント作成
- build & deploy
- ENJOY!
今回のメインは4番ですが、順を追って解説しようと思います。
1. VueCLIで新規プロジェクト作成
いつものやつです。下を実行します。
whim-client-vue
の部分は適宜読み替えてください。$ vue create whim-client-vue
色々聞かれますが、必要なのはBabelとVuexです。(Linterはお好みで)
2. 不要なファイル削除
普通にcreateすると下のようなフォルダ構造になっているはずです。(.git, node_modulesは除外)
whim-client-vue ├── .browserslistrc ├── .eslintrc.js ├── .gitignore ├── README.md ├── babel.config.js ├── package.json ├── public │ ├── favicon.ico │ └── index.html ├── src │ ├── App.vue │ ├── assets │ │ └── logo.png │ ├── components │ │ └── HelloWorld.vue │ ├── main.js │ └── store │ └── index.js └── yarn.lock今回はVuexの部分しか使わないので、vueコンポーネント等関係ない部分は消していきます。最終的に以下のようになりました。
whim-client-vue ├── .browserslistrc ├── .eslintrc.js ├── .gitignore ├── README.md ├── babel.config.js ├── src │ ├── main.js │ └── store │ └── index.js └── yarn.lock3. package.jsonの編集
編集後のpackage.jsonを下に載せます。(devDependenciesはlint等の設定で変わります。)
"private" はモジュールとして公開しないという設定なので、消しておきます。
"scripts" の部分はbuildだけ下記の内容に変更し、serveやlintを消しておきます。
また、"version"は慣習として、開発中は 1.0.0 未満に設定し、開発が完了して初めて 1.0.0 に上げるようです。package.json{ "name": "whim-client-vue", "version": "0.1.0", "scripts": { "build": "vue-cli-service build --target lib --name whim-client-vue ./src/main.js" }, "dependencies": { "core-js": "^3.6.4", "vue": "^2.6.11", "vuex": "^3.1.3" }, "devDependencies": { "@vue/cli-plugin-babel": "~4.3.0", "@vue/cli-plugin-eslint": "~4.3.0", "@vue/cli-plugin-vuex": "~4.3.0", "@vue/cli-service": "~4.3.0", "@vue/eslint-config-prettier": "^6.0.0", "babel-eslint": "^10.1.0", "eslint": "^6.7.2", "eslint-plugin-prettier": "^3.1.1", "eslint-plugin-vue": "^6.2.2", "prettier": "^1.19.1", "vue-template-compiler": "^2.6.11" } }4. storeの読み込み & ゴリゴリ実装
本記事のメインディッシュです。こちらの記事を参考にしました。
- https://forum.vuejs.org/t/should-i-use-vuex-when-creating-a-component-library/57589store/index.js
まず、
store/index.js
を編集します(簡略化したコードを使っています)。store/index.js// initial state const state = { appState: {}, // room information }; // mutations const mutations = { // appStateに値を代入 setAppState(state, appState) { state.appState = appState; } }; // actions const actions = { // appStateの値をリセット deleteState() { setAppState({}); } }; const getters = { // appStateの値を取得 appState: state => { return state.appState; }, }; export default { // 名前空間を使うように namespaced: true, state, mutations, actions, getters };コードの中身は setAppState関数でstateのappStateを変更、stateはappStateの情報を保持し、gettersでappStateの情報を取り出します。actionsのdeleteStateではappStateの情報をクリアしています。
また、namespaced: true を使うことで、このライブラリが導入された先で名前の衝突がおこらないようにしています。main.js
その後、
main.js
を編集します。main.js// store/index.js の読み込み import store from "./store"; export default { install(Vue, options) { // storeが渡されなかったら、エラーを出力 if (!options.store) { throw new Error("Please provide vuex store."); } // vuex module を名前空間付きで登録 options.store.registerModule("whimClient", store); // $whimにメソッドを生やす Vue.prototype.$whim = { getState() { return options.store.getters["whimClient/appState"]; }, deleteState() { return options.store.dispatch("whimClient/deleteState"); } }; } };順を追って解説します。
まずはじめに
store/index.js
を読み込みます。import store from "./store";次にexportするObjectにinstall関数を定義します。
このinstallはライブラリがmain.jsで
Vue.use(whimClientVue, { store })
と読み込まれるときに、呼び出されます。したがって install以下のスクリプトはこのライブラリが読み込まれたユーザー側で実行されます。
optionsには、Vue.useで呼び出したときの第2引数が入ります。(上の例では{ store }
)export default { install(Vue, options) { // ... } };今回はvuexが必須なので、vuexがoptionsに渡されていることを確認します。
渡されなかった場合はerrorを投げます。
私は普段ズボラなので、エラーは適当に済ませますが、今回は公開するライブラリで、なおかつ(storeの渡し忘れといった)発生が想定されうるエラーなので、エラーが受けた人がなぜエラーになったかをわかるようにします。if (!options.store) { throw new Error("Please provide vuex store."); }次に、moduleの登録をします。今回はwhimでもよかったのですが、名前衝突を避けるためにちょっと捻ります。
基本的にここで登録するstoreは、ユーザーは直接使わないので、ややこしめの名前ぐらいで良いと思います。// Register vuex module options.store.registerModule("whimClient", store);最後に、ユーザーが
$whim
経由でアクセスできるメソッドを登録します。このように登録することで、Vue上の任意の場所で、this.$whim.getState()
でappStateの値がとれたり、this.$whim.deleteState()
でappStateの値を消すことができます。Vue.prototype.$whim = { getState() { return options.store.getters["whimClient/appState"]; }, deleteState() { return options.store.dispatch("whimClient/deleteState"); } };蛇足(飛ばしてもOK)
this.$whim.getState()
でappStateの値が取れるようになりましたが、使いづらくないですか?私は使いづらいです。例えば、stateのxxxプロパティにアクセスするのに、this.$whim.getState().xxx
と書くのはちょっと抵抗があります。私はthis.$whim.state.xxx
という感じでアクセスしたい!と思ったので、どうしたらそうかけるかを調べました。
上のコードを以下のように変更します。let prototypeWhim = { deleteState() { return options.store.dispatch("whimClient/deleteState"); } }; Object.defineProperty(prototypeWhim, "state", { enumberable: true, get: function() { return options.store.getters["whimClient/appState"]; } }); Vue.prototype.$whim = prototypeWhim;prototypeWhim Objectに対して、definePropertyを用いて動的に、propertyをセットしております。
こうすることで、property風にappStateにアクセスすることができます!5. npmにアカウント作成
ゴリゴリとライブラリが完成したら次は公開します。
まずは準備として、npmアカウントをこちらからを作ります。その後、コンソールで以下のコマンドを叩き、ログインします。$ npm login
ここまでできたら準備完了です!
6. build & deploy
最後の仕上げにnpmでライブラリを公開します。
まず、buildをします。$ npm run build # or $ yarn buildそうすると、
dist/whim-client-vue.common.js
といったファイルが生成されます。
これがbuildされたスクリプトファイルなので、これをpackage.jsonの "main" に登録します。
また、ライセンスもお好みで作っておきます。今回は"license": "MIT"
を設定しました。
最終的なファイルは以下になります。(devDependenciesはlint等の設定で変わります。)package.json{ "name": "whim-client-vue", "version": "1.0.1", "main": "dist/whim-client-vue.common.js", "license": "MIT", "scripts": { "build": "vue-cli-service build --target lib --name whim-client-vue ./src/main.js" }, "dependencies": { "core-js": "^3.6.4", "vue": "^2.6.11", "vuex": "^3.1.3" }, "devDependencies": { "@vue/cli-plugin-babel": "~4.3.0", "@vue/cli-plugin-eslint": "~4.3.0", "@vue/cli-plugin-vuex": "~4.3.0", "@vue/cli-service": "~4.3.0", "@vue/eslint-config-prettier": "^6.0.0", "babel-eslint": "^10.1.0", "eslint": "^6.7.2", "eslint-plugin-prettier": "^3.1.1", "eslint-plugin-vue": "^6.2.2", "prettier": "^1.19.1", "vue-template-compiler": "^2.6.11" } }その後以下のコマンドで公開完了です?
$ npm publish
npmのサイトからデプロイされたことが確認できます。
自分のプロジェクトに追加して、楽しみましょう!今回わからなかったこと
今回一通りやってわからなかったこと、やり残したことをメモしておきます。
動作確認について
ライブラリを作るとき、実際にimportして動作確認しながら作りたかったのですが、そのやりかたがわかりませんでした。結局毎回npmにpublishしてバグってたら修正していきました。
CI/CDについて
今回のように手元でpublishしていると、ヒューマンエラーでpublishし忘れといった事態が考えられます。そうするとgithubのコードと実際に動いているコードが変わってしまい、そのライブラリのユーザーが混乱します。
CI/CDは導入しましょう(自分に念押し)。テストコードについて
途中で力尽きて、ここまでやり遂げられませんでした。
己の力不足です。反省。
やっぱあった方がいいよね。まとめ
vue.jsのライブラリの作り方を1から一通りまとめました。jsのライブラリは初めてでしたが、思ってたよりすんなりいった印象です。ただ一方いくつかの課題も見えてきたので、もう少し色々探って行きたいと思います。
最後に
今回題材として使ったのは wh.im というサービスを使ってゲームを作るときにあると便利な whim-client-vue です。こちらのドキュメントを読むと簡単につくれると思います。興味があれば、ぜひゲームを作ってみてください。
- 投稿日:2020-05-22T23:13:46+09:00
vue.jsとmoment.jsを使って、TODOに日付を表示する
vue.jsとmoment.jsを使って、TODOに日付を表示する
TODOリストに日付を追加する方法が分からなかったので、メモ。
moment.js導入手順
$ yarn add moment
で、vuecliのプロジェクトにmoment.jsをインストールします。
import moment from 'moment';で、インストールしたmoment.jsを読み込みます。
TODOに日付を表示する
下記のように、TODOを追加するシンプルなコードを書きます。
<template> <div id="app"> <h2>todos</h2> <p> <input v-model="newtodo" v-on:keyup.enter="addtodo" /> </p> <div v-for="todo in todos" :key="todo.id"> <p> <span class="todo">{{ todo }}</span> </p> </div> </div> </template> <script> import moment from 'moment'; export default { data() { return { todos: [], newtodo: '', }; }, methods: { addtodo() { if (!this.newtodo) { return; } this.todos.push(this.newtodo); this.newtodo = ''; }, }, }; </script>addtodoメソッドで、TODOと現在の時刻を取得して、todos[]にpushします。
addtodo() { if (!this.newtodo) { return; } const params = { text: this.newtodo, created_at: new Date(), }; this.todos.push(params); this.newtodo = ''; },
parmas
に、入力したtodoと、created_atには、new Date()で、現在の日付を代入したもの を代入します。
this.todos.push
で、配列todos[]にparams
の値をpushします。とすることにより、テンプレート側で{{todo}}で参照できます。
<div v-for="todo in todos" :key="todo.id"> <p> <span class="todo">{{ todo }}</span> </p> </div>{{todo.text}}とすれば todosの中のtextが取れるし、{{todo.created_at}}とすれば日付が取れます。
これだけだと、moment.jsの出番がないので、活用します。
export default { filters: { moment: function(date) { console.log(date); return moment(date).format('YYYY/MM/DD HH:mm'); }, },で、momentというフィルターを作成します。文字列をDate関数よりも簡単に扱えるmoment関数に変換するものです。
テンプレート上で、
{{ todo.created_at | moment }}
とすることによって、momentのフィルターを通しました。
moment(date).format('YYYY/MM/DD HH:mm');
の部分で、YYYY/MM/DD HH:mmの形式に変換することができました。
変換した結果が下記になります。
使い方忘れそうなのでメモしました。
- 投稿日:2020-05-22T20:49:18+09:00
北海道の訪問記録を残すWebサイトを作った
全国の北海道ファンの皆さんこんにちは.
早速ですがこの地名を読めますか?
幌筵1
当然読める日本人の方々はここから
漢字の読めない若い方々はここから
読めなかった非国民の方々はここからアクセスできます.
私は北方領土をロシア領と呼ぶ売国奴2なのでアクセスできませんでした.
北海道は広いですよね.いろんなところに行きますよね.今回,北海道の自治体単位での訪問記録を付けられるWebサイトを作ったので紹介いたします.
要するに,経県値の丸パクリですね.
皆と共有して思い出話に花を咲かせましょうマウント取り合いまくりましょう.Webサイト概要
日本が主権を失った島々が堂々と居座っていますが,日本の自治体としては正しく存在するのでセーフです.使い方
- 北海道が表示されるので自治体を直接ポチポチするか,下の振興局別 のリストからポチポチします.
- 右下のTwitterアイコンをクリックして共有します.
最大レベルは925です.真の道産子目指して頑張りましょう.
赤に染まった北海道を目指しましょう.ホストサービスはFirebase Hostingを使っています.
使用したライブラリはVue.jsです.初めて触りました3.
JSは素のまま書いています.トランスパイルなんて知りません.サイト作成までの流れ
- 国土地理院から北海道の地形データを引っ張ってくる
- SVGに変換,IDなどの情報などをつけ足す
- Firebase Hostingのテンプレートを作成
- JSのコードを書く(定義含め300行くらい)
- デプロイ
簡単ですね.勉強含め4日くらいでできました.
地味にはまったところ
SVG中のstyle要素の名前空間
Vue.jsのコンテキストに含まれるSVGにそのまま<style>要素を置くとtemplate compile errorになるため,名前空間を宣言してあげましょう4.
コンパイルエラーになる例NG<style> path { fill: #FFFFFF; } </style>動作する例
OK<svg:style> path { fill: #FFFFFF; } </svg:style>Win10 Mobile版Edgeでのv-on:inputイベント
Windows 10 Mobileの端末ではRadioボタンやSelect要素のinputイベントが発火しません.
他のブラウザやデスクトップ版Edge5では動作するため,見落としがちです.changeイベントを使いましょう.
イベントが発生しない例NG<input type="radio" V-bind:id="'option'+index" v-bind:value="index" v-model="value" v-on:input="$emit('input',{'index':index,$event})">イベントが発生する例
OK<input type="radio" V-bind:id="'option'+index" v-bind:value="index" v-model="value" v-on:change="$emit('change',{'index':index,$event})">データ更新に合わせたURLの変更
vue-routerを併用する際に同時にURLも変更したい際の実装例のお決まりはあるのでしょうか?
今回は算出プロパティ内で変更しましたが,ほかのやり方があると思います.Gorillavar app = new Vue({ el: "#app", router, computed:{ newurl:function(){ return "abc" }, rout:function(){ router.replace({path:`/app/${this.newurl}`}) return "" }, } }).$mount("#app")所感
正直,普段作る業務アプリの範囲内だと,UIとViewModelを分けるうまあじがあまりありませんね.
開発してて思ったのは「よくわからないけど動いてる.すごい」でした,
今回のように,趣味で使う小さいアプリには簡単に適用できたので,慣れの問題でしょうかね.
最後に私の訪問マップにてお終いとさせていただきます6.
以上,ありがとうございました.
- 投稿日:2020-05-22T19:03:58+09:00
【Vue.js】 ライフサイクルフック
はじめに
ライフサイクルフックはVueのオプションオブジェクトの1つ。Vueインスタンスの生成から破棄までの間の特定のタイミングで実行されるメソッド(関数)を
ライフサイクルフック
という。ライフサイクルフックはコンポーネントごとに存在する。ライフサイクルフック一覧
dataオプションやmethodsオプションは自由に定義できるが、ライフサイクルフックは使用できるメソッドがあらかじめ決まっており、以下のようなタイミングでメソッドが実行される。
ライフサイクルフック タイミング beforeCreate インスタンス生成時。リアクティブデータが作成される前。 created インスタンス生成後。リアクティブデータが作成された後。 beforeMount インスタンスがDOM(HTML)にマウントされる前。DOMの操作はできない。 mounted インスタンスがDOM(HTML)にマウントされた後。DOMの操作ができる。 beforeUpdate データが更新され、DOMが更新される前。 updated データが更新され、DOMが更新された後。 beforeDestroy インスタンスが破棄される前。 destroyed インスタンスが破棄された後。 errorCaptured 任意の子孫コンポーネントからエラーが捕捉された時。 ※リアクティブデータ・・・オプションで定義されているデータ。定義しているデータが更新されるとHTML側も自動的に更新される。変更が瞬時に反映されるデータ。
基本的な書き方
sample.jsnew Vue({ el: 'app', ライフサイクルのメソッド名: function() { ここに処理をかく } })beforeCreate
sample.jsnew Vue({ el: 'app', data: { message: 'Hello', }, // インスタンスが生成され、処理が実行される beforeCreate: function() { // リアクティブデータはまだ生成されていないのでmessageは参照できない // コンソールには何も出力されない console.log(this.message) } })created
sample.jsnew Vue({ el: 'app', data: { message: 'Hello', }, // インスタンスが生成された後、処理が実行される created: function() { // コンソールにHelloと出力される console.log(this.message) } })beforeMount
sample.vue<template> <!-- まだマウントされていないのでmessageの中は空のまま --> <div id="app">{{ message }}</div> </template> <script> new Vue({ el: 'app', data: { message: '', }, // マウントされる前に処理が実行される beforeMount: function() { // messageにHelloを代入 this.message = 'Hello' } }) </script>mounted
sample.vue<template> <!-- Helloが表示される --> <div id="app">{{ message }}</div> </template> <script> new Vue({ el: 'app', data: { message: '', }, // マウントされた後に処理が実行される mounted: function() { // messageにHelloを代入 this.message = 'Hello' } }) </script>
- 投稿日:2020-05-22T18:57:48+09:00
Vue.jsの学習記録
最近Vue.jsを勉強しているので、備忘録として。
Vue.jsを勉強しようと思った理由
- JavaScriptの基礎的な勉強を一通り終えた(TODOアプリを作れるレベル)ので、新しくJSのフレームワークに触れてみたかった。
- JSには様々なフレームワーク(Angular,Reactとか)と比べて、人気が高く、初学者でもとっつきやすい印象を受けたから。
- 独自のHTMLタグを作ることができ、データバインディングが非常に簡単という特徴があるから、開発の可能性が広がる。
といった点から、Vue.jsを学びました。
ちなみに、学習している教材は、udemyのVue JS入門決定版!jQuery を使わない Web 開発 - 導入からアプリケーション開発まで体系的に動画で学ぶを使って勉強しています。Vue.jsの導入
以下のURLからVue.jsのインストールができます。
Vue.jsのインストール
導入する方法は、直接ダウンロードする方法と、CDNによる読み込み、NPMを利用したダウンロード、CLIを利用したダウンロードの4つの方法があります。学習を目的としている方は、直接ダウンロードする方法か、CDNによる読み込みの方法が比較的すぐ導入できるのでオススメです。
初めに
HTMLの記述
<body> <div id="app"> <!-- ここにVue.jsの内容を記述 --> </div> </body>
div
タグを作って、idを"app"
とします。JavaScriptにVueのインスタンスを作成
var app = new Vue({ el: '#app' })JavaScriptにVueインスタンスを作成しました。
el
プロパティを使って、先ほどHTMLに記述したid"app"
をマウント(id"app"
が含まれている要素を結びつける)しています。ここまでが、Vue.jsを書く初めの準備。
Hello, Vue.js!と表示させたい
Vue.jsを使って、HTML上で
Hello, Vue.js!
と表示させます。<body> <div id="app"> <p>{{ message }}</p> </div> </body>new Vue({ el: '#app', data: { message: 'Hwllo, Vue.js!' } })HTMLで、まずmustache構文
{{}}
を使ってオブジェクトを呼び出します。
JSで、data
プロパティにmessage
オブジェクトを定義し、Hello, Vue.js!
と記述します。
以上がHTML上にHello, Vue.js!
と表示させる方法です。ディレクティブについて
ディレクティブとは、Vue独自の属性のことです。(v-bind、v-modelとか)
勉強してきたディレクティブを紹介します。v-bind
v-bindは
class
やvalue
、style
など、v-bind:value
のようなかたちで属性を呼び出すことが可能です。
一部紹介<div id="#app"> <!-- input欄の中にhogeの値を表示 --> <input type="text" v-bind:value="hoge"> <!-- urlプロパティに記入した値のリンク先に飛ぶ --> <a v-bind:href="url">Googleに飛びます</a> </div>new Vue({ el: '#app', data: { hoge: 'hoge', url: 'https://www.google.com' } })こんな記述になります。
v-model
双方向データバインディングができます。
以下のような記述です。<div id="app"> <!-- pタグとinputタグ共に'ホゲー'の文字列が出力される --> <p>{{hoge}}</p> <input type="text" v-model="hoge"> </div>new Vue({ el: '"app', data: { hoge: 'ホゲー' } })
input
タグの中で文字を変更した時、リアルタイムにp
タグの文字列も影響します。v-if
Vue.jsで書く、
if
文ですね。<div id="app"> <p v-if="hoge"> "hoge"がtrueなら表示されます!! </p> </div>new Vue({ el: '#app', data: { hoge: true } })
data
プロパティにfalse
と記述すると、p
タグが消えます。v-for
Vue.jsで書く、おなじみ
for
文ですね。<div id="app"> <ul> <li v-for="friut in fruits"> <!-- 配列'fruits'の中身が全て表示される --> {{ fruit }} </li> </ul> </div>new Vue({ el: '#app', data: { fruits: [ 'apple', 'banana', 'grape' ] } })v-on
v-on:イベントの種類=関数()
のようなかたちで、イベントを起こすことができます。
関数の呼び出しにはmethods
プロパティを使用します。<div id="app"> <input type="text" v-model="message"> <button v-on:click="alert">click</button> </div>new Vue({ el: '#app', data: { message: '' }, methods: { alert(this.message) } })
input
タグに文字を入力し、clickボタンを押すと、input
の文字列をmessage
オブジェクトに格納し、alertでmessage
の文字列が出力されます。
- 投稿日:2020-05-22T17:07:43+09:00
【Nuxt.js】firebase基礎編(Auth版):メールアドレスログインをできるようにしよう
前置き
ログイン機能があると
サービスの幅が広がりますよね?
でも難しそう?
そう思っていませんか??
それを解決するのがfirebase Auth!
これを使えば簡単に実装できます?今回はログインの実装がメインです!
そのため新規アカウント作成画面は作りません。
まずauthに慣れていきましょう??アプリ開発基礎編
追加オプション機能では
アカウント作成などもやっていきます!
https://note.com/aliz/n/n8411db2c9a20【使うもの】
・Firebase Authentication
・Vuex(ログイン状態の保持)Step1: firebase authの準備
まずはfirebaseでプロジェクトを作成し、
ログイン方法の設定をしていきます?プロジェクトの作成方法はこちら
step1-5. アカウントを選択
プロジェクト概要画面まで
https://note.com/aliz/n/nacc97fe7d019#Ls0Km・プロジェクトができたら
サイドメニューのAuthenticationを選択
ログイン方法を設定を選択・メールを選択
・メールでのログインを有効にし、保存
・usersタブに戻りユーザーを追加
登録できるとユーザー情報が表示されます?
Step2: firebaseとの連携
こちらの記事の
Step3、Step4をご覧ください?
https://note.com/aliz/n/nacc97fe7d019#Ls0Kmplugin/firebase.jsimport firebase from "firebase/app" if (!firebase.apps.length) { firebase.initializeApp({ apiKey: "貼り付け", authDomain: "貼り付け", databaseURL: "貼り付け", projectId: "貼り付け", storageBucket: "貼り付け", messagingSenderId: "貼り付け", appId: "貼り付け", measurementId: "貼り付け" }) } export default firebaseStep3: ログイン機能の実装
公式ガイドのこちらを見てみましょう?
Get Startedタブから順番に進めてみます?
ログインフォームを作って
methodsにこの関数を書けば良いわけですね?
signInWithEmailAndPassword()https://firebase.google.com/docs/auth/web/start#sign_in_existing_users
index.vue<template> <div class="page"> <form class="form" @submit.prevent > <label class="label"> <span class="label"> email </span> <input class="input" type="text" v-model="email" > </label> <label class="label"> <span class="label"> password </span> <input class="input" type="password" v-model="password" > </label> <button class="button" type="submit" @click="login" > Login </button> </form> </div> </template> <script> import firebase from '~/plugins/firebase' export default { data() { return { email: '', password: '' } }, methods : { login() { firebase.auth().signInWithEmailAndPassword(this.email, this.password) .then(user => { // eslintがある場合は // 引数にuser追加とeslint-disable-lineの記載 console.log('成功!')// eslint-disable-line }).catch((error) => { alert(error) }); }, } } </script> <style lang="scss"> .Login { > .form { > .button { display: block; } > .label { > .input { display: block; border: 1px solid blck; } } } } </style>Step4: Vuexに移行
今のままだとログインするだけなので
Vuexを使うメリットがないのですが、
ログインしたという状態を
保持するための準備です!index.vue<template> <div class="page"> <form class="form" @submit.prevent > <label class="label"> <span class="label"> email </span> <input class="input" type="text" v-model="email" > </label> <label class="label"> <span class="label"> password </span> <input class="input" type="password" v-model="password" > </label> <button class="button" type="submit" @click="login" > Login </button> </form> </div> </template> <script> import firebase from '~/plugins/firebase' export default { data () { return { email: '', password: '', } }, methods : { login (email, password) { this.$store.dispatch('login', {email: this.email, password: this.password}) }, } } </script>store/index.jsimport firebase from '~/plugins/firebase' export const state = () => ({ }) export const getters = { } export const actions = { login(context, payload) { firebase.auth().signInWithEmailAndPassword(payload.email, payload.password) .then(user => { console.log('成功!') }).catch((error) => { alert(error) }) }, } export const mutations = { }【解説】
index.vueで入力した
email, passwordを引数で渡します?
index.jsのactionsでは
第一引数が必ずcontextになるので
第二引数としてemail, passwordを受け取ります?Step5: ユーザーデータの取得
ログインができたら
ユーザー情報を表示したいので
情報を取得してきましょう!?
こちらを見てみましょう?
onAuthStateChanged()index.jsimport firebase from '~/plugins/firebase' export const state = () => ({ user: { uid: '', email: '', }, }) export const getters = { user: state => { return state.user } } export const actions = { login({ commit }, payload) { firebase.auth().signInWithEmailAndPassword(payload.email, payload.password) .then(user => { console.log('成功!') firebase.auth().onAuthStateChanged(function (user) { if (user) { commit('getData', { uid: user.uid, email: user.email }) } }) }).catch((error) => { alert(error) }) }, } export const mutations = { getData (state, payload) { state.user.uid = payload.uid state.user.email = payload.email } }【解説】
それぞれの役割を確認したい方はこちら
https://note.com/aliz/n/n6f4a42bce5b5?state?
・取得情報の格納場所?getters?
・stateを取得?actions?
・ログインと同時に取得したいので
ログイン成功時(.then)に記載
→step7でログインと取得で
切り分けるように調整をします✂︎
・ガイド参考
これで取得ができます!
ID:user.uid
?:user.email
引数に直接user.uidとは書けないので
一旦uidと置き換えます
・commit
ログイン情報をstateに入れるため
mutationsを呼び出します?mutations?
取得した情報でstateを書き換えます【index.vue】
computed users()でgettersを呼び出し表示Step6: ログイン情報保持
先ほどログインが成功した時に
ユーザーデータを取得できたので
こちらを追加しましょう!
・stateにログイン状態の真偽値を追加
→ログインできたらtrueに変更
・v-ifで真偽値による出し分け
→ログインtrue, ログアウトfalseindex.jsimport firebase from '~/plugins/firebase' export const state = () => ({ user: { uid: '', email: '', // ログイン状態の真偽値を追加 login: false, }, }) export const getters = { user: state => { return state.user } } export const actions = { login({ commit }, payload) { firebase.auth().signInWithEmailAndPassword(payload.email, payload.password) .then(user => { console.log('成功!') firebase.auth().onAuthStateChanged(function (user) { if (user) { commit('getData', { uid: user.uid, email: user.email }) // ユーザー情報の取得と同時にcommitで真偽値の切り替え commit('switchLogin') } }) }).catch((error) => { alert(error) }) }, } export const mutations = { getData (state, payload) { state.user.uid = payload.uid state.user.email = payload.email }, // 真偽値を切り替えるmutationsを追加 switchLogin (state) { state.user.login = true }, }index.vue<template> <div class="page"> <p v-if="user.login" class="text" > {{ user }} </p> <form v-else > // 省略 </form> </div> </template> <script> import firebase from '~/plugins/firebase' export default { computed: { user () { return this.$store.getters['user'] }, }, data () { return { email: '', password: '', } }, methods : { login (email, password) { this.$store.dispatch('login', {email: this.email, password: this.password}) }, } } </script>Step7: ログイン保持のチェック✅&調整
最後にcomponentsに移動させ
全てのコンポーネントで
ログインが保持されるかチェック✅
リロードしない限り
保持されることが確認できます✨?また、store/index.jsのactionsを
役割で切り分けてみます✂︎【Login.vue】
index.vueをまるまるコピペ
・fibaseのimportが不要→削除
・全体のdiv class="login"に変更Login.vue<template> <div class="login"> <p v-if="user.login" class="text" > {{ user }} </p> <form v-else class="form" @submit.prevent > <label class="label"> <span class="label"> email </span> <input class="input" type="text" v-model="email" > </label> <label class="label"> <span class="label"> password </span> <input class="input" type="password" v-model="password" > </label> <button class="button" type="submit" @click="login" > Login </button> </form> </div> </template> <script> export default { computed: { user () { return this.$store.getters['user'] }, }, data () { return { email: '', password: '', } }, methods : { login (email, password) { this.$store.dispatch('login', {email: this.email, password: this.password}) }, } } </script>index.vue<template> <div class="page"> <Login /> <p v-if="user.login" class="text" > ログインに成功! </p> </div> </template> <script> import Login from '~/components/Login.vue' export default { components: { Login: Login, }, computed: { user () { return this.$store.getters['user'] }, }, } </script>【store/index.js】
・ログイン(login)
・ログイン情報の取得(checkLogin)
で切り分けました✂︎
actions内で別のactionsを
dispatchで呼び出せます?store/index.jsimport firebase from '~/plugins/firebase' export const state = () => ({ user: { uid: '', email: '', login: false, }, }) export const getters = { user: state => { return state.user } } export const actions = { login({ dispatch }, payload) { firebase.auth().signInWithEmailAndPassword(payload.email, payload.password) .then(user => { console.log('成功!') dispatch('checkLogin') }).catch((error) => { alert(error) }) }, checkLogin ({ commit }) { firebase.auth().onAuthStateChanged(function (user) { if (user) { commit('getData', { uid: user.uid, email: user.email }) commit('switchLogin') } }) }, } export const mutations = { getData (state, payload) { state.user.uid = payload.uid state.user.email = payload.email }, switchLogin (state) { state.user.login = true }, }
- 投稿日:2020-05-22T16:28:51+09:00
Vue.jsで作る!自動保存するToDoリスト~その1~
誰向けですか?
・Vue.js超初心者
・Vue.jsの基本構文は覚えたけど次は何すればいいの?
・リロードしたら消えちゃう!!↑という方向けです。自分自身の学習のためにも記事を書かせていただきます!記述で間違いなどがありましたら教えてくださるとありがたいです?♂️
このパートの完成イメージ
とりあえずinputに書いてbuttonを押すと配列(items)に追加できるようにしよう!
次回以降で順にCSSで見た目、watchやmountedを使用して保存できるようにします。このパートですること
1.HTMLを書いてVueで操作できるようにする
2.Vueで配列の作成やinputをバインディングする
3.関数を作成して追加、削除できるようにする1.HTMLの記述
index.html<div id="app"> <div> <!-- v-modelはこのinputをVueとバインディングさせる役割 --> <input v-model="message"> <!-- @click=""の中はVueで記述するメソッド(@はv-on:の省略です) --> <button @click="add_item()">追加</button> <button @click="all_del_item">全削除</button> <!-- v-for( 配列, index(配列内の要素に振られた添字)を(item,idx)と表している ) --> <ul><li v-for="(item,idx) in items"> {{ item }} <button @click="del_item( idx )"> 削除 </button> </li></ul> </div> </div>Vue.jsの記述
main.jsconst myApp = new Vue({ // id="app"をVueでマウントする el: '#app', //何の処理もない配列やオブジェクトなどをおく場所(もしdataに処理を加えたい場合はcomputedを使う) data: { //配列の初期状態,良い朝の流れである items: ['起きる', '洗顔', '歯磨き',], //inputの初期状態(既に何か書かれていたら変なので空にしておく) message: '' },これではまだmessageの追加や削除ができないので、data{},の続きにmethodsを記述する。
// Vueアプリケーション内で使用する関数を定義する場所 methods: { // itemsに追加するメソッド、{ itemsにmessageをpush(追加)する } add_item: function () { this.items.push( this.message ) }, // 削除ボタンを押した時のメソッド、{ items(自身)を1つsplice(削除)する } del_item: function ( _idx ) { this.items.splice( _idx, 1 ) }, // itemsを全て削除するメソッド、spliceの数を大きい数字にすれば全て消えるでしょう all_del_item: function ( _idx ) { this.items.splice( _idx, 10000 ) } },#まとめ
実際に記述してinputに書いた文字が追加・削除できたでしょうか?
次のパートではこの寂しい見た目をCSSで装飾しましょう!(SCSSかBootstrapで予定しています)
この記事を読んでくださったあなたの成長を応援させていただきます!!!
- 投稿日:2020-05-22T12:36:22+09:00
Nuxt.jsをVue.jsに解体するTips(Plugin編)
背景
- Nuxt.jsで動いているSPAアプリをVue.jsに解体してほしい的な話があり、部分部分をTipsとして投稿します。
- APIはLaravel(6.x)です。なおLaravelとNuxt.jsは同一リポジトリです(なぜ)
- Nuxt.jsは2.9。Vueは2.6.10
- 今回はPlugin編です。
Nuxt.jsでコンテキストに注入している場合
Nuxt.jsの書き方の例
Nuxt.js公式ドキュメントより抜粋
plugins/combined-inject.jsexport default ({ app }, inject) => { inject('myInjectedFunction', string => console.log('That was easy!', string)) }Vue.jsでの解体例
- Vue.prototypeでインスタンスプロパティを追加。
resources/js/combined-inject.jsconst MyInjectedPlugin = {} MyInjectedPlugin.install = function (Vue) { Vue.prototype.$myInjectedFunction = string => console.log('That was easy!', string) } export default MyInjectedPlugin;resources/js/app.jsimport Vue from "vue"; import router from '~/router' import App from '~/App.vue' import MyInjectedPlugin from '~/plugin/combined-inject' import DefaultLayout from '~/layouts/default' import NoAuthLayout from '~/layouts/noauth' Vue.use(MyInjectedPlugin) //Vue.useでpluginを追加 Vue.component('default-layout', DefaultLayout) Vue.component('noauth-layout', NoAuthLayout) new Vue({ router: router, render: h => h(App), }).$mount('#app')PluginからVue Routerを使いたい場合
導入例
resources/js/app.jsimport Vue from "vue"; import router from '~/router' import App from '~/App.vue' import RouterPlugin from '~/plugin/router-plugin' import DefaultLayout from '~/layouts/default' import NoAuthLayout from '~/layouts/noauth' Vue.use(RouterPlugin, router) // Vue.useの引数にrouterを渡す Vue.component('default-layout', DefaultLayout) Vue.component('noauth-layout', NoAuthLayout) new Vue({ router: router, render: h => h(App), }).$mount('#app')resources/js/plugin/router-plugin.jsconst RouterPlugin = {} RouterPlugin.install = function (Vue, router) { Vue.prototype.$hoge = () => { router.push("/") } } export default RouterPlugin;PluginからVuexを使いたい場合
resources/js/app.jsimport Vue from "vue"; import router from '~/router' import App from '~/App.vue' import StorePlugin from '~/plugin/store-plugin' import store from '~/store/store' // Vuexを定義しているモジュールをimportする Vue.use(StorePlugin, store) // Vue.useの引数にstoreを渡す Vue.component('default-layout', DefaultLayout) Vue.component('noauth-layout', NoAuthLayout) new Vue({ store router: router, render: h => h(App), }).$mount('#app')resources/js/plugin/store-plugin.jsconst StorePlugin = {} StorePlugin.install = function (Vue, store) { Vue.prototype.$fuga = () => { store.dispatch('~~') } } export default StorePlugin;参考
関連リンク
- 投稿日:2020-05-22T10:11:44+09:00
ポストコロナ時代の歩き方。~密違反監視カメラ作った~
やぁ、やぁ、自粛解禁ムードになってきてみなさん油断していないですかね?
そんな悪い子たちのために密違反監視カメラ作りやした。
iOSのアプリで人の密を判定するアプリを作って、そのライブ映像を見れるサイトを作りました。コンセプトは車のスピード違反取締りのオービスみたいな感じで、
人が密違反をしていたら、写真を撮ってしまうぞ!
という怖い監視カメラです。ライブ映像はこちらから見れるますたぶん。
https://orbisforwalkers.tokyo
(5/22の午後14:00~18:00くらいの間だけ試しにライブ配信やります。それ以外は未定です。)
見れてなかったらごめんなさい、、背景
コロナ便乗 創作欲求満たすぜ大喜利!!と言われたら反論はできない。
コロナ禍の中で、一線の研究者達が世界のために日々闘う姿をみて感動し、凡人である我々に何ができるのか考えた時に、とにかく何か作らなければと使命に駆られた....
という理由で開発したのなら格好がつくのだがそういう理由ではない。大それたことは関係なく、何かを感じて物を作るという自然なことを日々やっていかなければならないと考えていた矢先に、コロナになったのでいつの間にかこういうプロダクトが出来てしまった。という感じだ。Gomenn...
今回のプロダクト制作の目的は大きく分けると二つで、
- 考えた物をチームで形にしていく練習
- 興味分野の技術習得 (技術習得のトピックは以下)
- firebase使えるようにならんとなぁと思ってた事。(ライブ演出仕事とかインスタレーションの仕事が減るかも)
- 最近仕事でインスタレーションの開発した際に人体検知の機械学習に触れた事 -> なにか使えるのでは?
- 動画配信系の勉強せんとなぁと思ってた事。
これらの目的を達成したら出来てしまったという流れ.
Orbis for walkersはコロナ警察を助長するようなプロダクトであるため微妙な雰囲気はあるのだが、外出自重しろよ!!という意図ではなく、
こういうのを既存の技術で割とサクッと作れてしまうんだぞ、という事の周知としてみてもらえればと思う。また、本来の目的ぽくポストコロナ時代の歩きかたの何かしらの参考になればまぁよしと思う。
これに個人情報をくっつければ、密スコアが高い人間は逮捕といったデストピアが想像できる。「このアルゴリズムが誰かの人生を狂わせる。。」などと考えながら実装するエンジニアがこの世にはいるのだろう。
デザインはkikiがニヤリという感じにしてくれた。
システム構成
iOSアプリで人体検知、密スコア判定
密スコアが閾値を超えたら、画像をfirebaseに投げる。
管理画面で良く撮れた画像(個人情報特定できない画像)をパブリッシュすると、サイトに表示。
ついでに、iOSアプリで密判定を描画している様子をlive配信。
という感じのフローだ。iOS アプリ
最近仕事で使った人体検知はwindows環境でpythonだったのだが、
アプリでサクッとみんな出来た方が楽しい説 + windows PC買う予算ない
ということでiOS環境で試すことにした。
CoreMLの勉強と思っていたが結局自作モデルは使わなかったが、
ほんと今更だけど、こんな簡単に学習モデルを用意出来てしまうとは思わなかった。時代についていけていなかった。CreateMLでObject Detecitonの学習モデルを作りたい場合annotations.jsonをどうやって用意するか不明だったが、
IBMのCloud Annotations Toolで作れた。
Cloud Annotations Tool
こんな感じで、この画像のどの範囲にマスク野郎がいるかを決めてラベルを割り当てる作業をする。
こちらに詳しくやり方書いてあるので参考に
How to Label Data — Create ML for Object Detection | hackernoonで、エクスポートしたデータをcreateMLに突っ込んで学習させれば、モデルデータが完成する。
コードは一行も書かない。すごい!!
ちなみに学習は数時間かかる。雑魚macだと他の作業出来なくなるので夜寝る前に開始して寝よう。そして出来たデータは以下の公式apple developerのリンク先からダウンロードできるコードで使える。
Recognizing Objects in Live Captureこのコードを参考にfirebase周り入れてゴニョゴニョして完成。
やっぱり自作アプリが自分のiPhoneとかに入ると嬉しいね!
チーム内での配信はdeploygateで行った。
どうでもよいが数年振りにiosのアプリ開発したけどまだcocoapodがスタンダードなのだろうか?firebaseの公式もcocoapodで入れるの推奨してた。管理画面
管理画面はこんな感じ。
vueでwebpack構成SPA。普通です。
フレームワークはbootstrap制のcoreUIを使いました
https://coreui.io/vue/Firebase
firebase初心者だったので、firebaseというかfirestoreの勉強は以下の書籍で行った。
実践Firestore (技術の泉シリーズ(NextPublishing)) Kindle版
RDBに少し慣れてるとfirestoreでのデータ構造やコレクションの設計どうするかとか謎だったが、
この本読んで色々すっきりしました。mysqlとかいじったことある人がfirestoreなんぞ?の時はこれがベストな気がする。
あとちょっと古いけどmonoさんの記事とか。
Cloud Firestoreの勘所 パート1 — 概要
皆様ありがとうございました。
現場
ipad防御するカバー。
Otterbox defenderのiPad pro12.9用。重くてデカイしかも高い1万円以上する。普通は絶対買わない。
5/22(金)の午後は街を撮影しながらlive配信しようかと思っている。
どうぞよろしく。