- 投稿日:2021-03-05T22:39:06+09:00
Vue Router導入
Vue Routerとは
webページのルーティングを実装してくれる Vue.js 公式 のプラグイン
導入
Vue CLI を使用しているので、以下コマンド
vue add router質問がくる
質問1
Y
There are uncommitted changes in the current repository, it's recommended to commit or stash them first.質問2
Y(historyモードを選択する)
https://qiita.com/kozzzz/items/af9ad63fa70d4724cc2aUse history mode for router? (Requires proper server setup for index fallback in production) (Y/n)正常に起動した
✔ Successfully invoked generator for plugin: @vue/cli-plugin-router
- 投稿日:2021-03-05T22:07:59+09:00
SPAなビンゴゲームをVue2からVue3に移行した際に行った4つの事と、負債の返済
どんなアプリ?
イベントでチョット使えるSPA(Single Page Application)なビンゴゲーム「Bingo SPA」です。
ビンゴマシンとビンゴカードがワンセットになっています。
ビンゴマシンはこんな感じで動きます。
カードはこのようなものです。
ビンゴマシンとカードは連動していません。連動していません!(大切な事だから2回)
そのため、カードは手元に紙で用意して、ビンゴマシンだけ使う、もしくはその逆も可能となっています。※カードに至っては、ビンゴ判定すらありません。誰かいい感じの実装をお願いします!
ちなみに SORACOM UG #8 で使いました。あまりにも「あたらない」とネタになっていましたが。
https://uchimanajet7.hatenablog.com/entry/2017/12/16/144824Vue2 → Vue3 移行で行った事
私のVueアプリケーション作成は、
<script>
を読み込むケースです。npmではありません。その上で、Vue2からVue3への移行で行った事は4つです。
全貌はGitHubのdiffをご覧ください。
<script>
の読み込み先を変更new Vue()
からVue.createApp()
へ変更data
をオブジェクトから関数へ変更el
を削除してmount()
へ変更ともかくVue3のアプリが起動できてしまえば、問題がある部分はエラーが発生するので、あとは潰していけば良いでしょう。ともかく起動できるところまでが移行の第1ステップです。
以下、diffです。
<script>
の読み込み先変更- <script src="//jp.vuejs.org/js/vue.min.js"></script> + <script src="//unpkg.com/vue@next"></script>
Vue.createApp()
への変更、data
の関数化、el
の削除。- const app1 = new Vue({ - data: { - options: [], - latest: null, - results: [], - shuffling: false - }, + const app1 = Vue.createApp({ + data() { + return { + options: [], + latest: null, + results: [], + shuffling: false + } + },
mount()
への変更window.onload = function () { + app1.mount('#app1'); }
これ以降の調整
エラーや意図としない挙動に関しては、Vue2からのマイグレーションガイドを見ましょう。
負債の返済
このビンゴゲームには遊んでいる最中のリロード対策として、番号確定直後やカードをタップした毎に、
sessionStorage()
をへ状態を保存しています。リロードの際には状態を復帰する必要があるわけですが、この実装を今まで(Vue2)の時には、Vueインスタンスを作った後に
Windows.onload()
操作していました。
この実装はVue3では動きません。動くけど...const app1 = new Vue({ data: { card_id: null, cards: [] }, ... }); window.onload = function () { if (sessionStorage.getItem('card_id') && sessionStorage.getItem('cards')) { app1.card_id = sessionStorage.getItem('card_id'); app1.cards = JSON.parse(sessionStorage.getItem('cards')); } };本来このような操作は
created()
もしくはmounted()
で実装すべきだったのです。
これはVue2の頃から存在するインスタンスのライフサイクルにおけるフックメソッドで、ほかにはmounted()
やdestroyed()
と、インスタンスの状態の変更に合わせて発火します。created()を使った実装const app1 = new Vue({ data: { card_id: null, cards: [] }, created: function() { if (sessionStorage.getItem('card_id') && sessionStorage.getItem('cards')) { this.card_id = sessionStorage.getItem('card_id'); this.cards = JSON.parse(sessionStorage.getItem('cards')); } }, ... });最初からライフサイクルフックメソッドで実装しておけば、Vue3への移行で困ることは無かったわけです。
これは私が知らなかったというのが原因ですが、ここから得られた知見は「副作用を利用すると、アップグレードに弱くなる」ということです。Vue2からのマイグレーションガイドには、フレームワークが想定している破壊的変更や注意点が列挙されます。即ち、正しくトラブルが発生するため対処もできます。一方、副作用はフレームワーク側から見れば想定外なのでサポートできませんし、それをサポートしろというのは無理があります。
今回負債が返済でき、良かったです。
まとめ
ソフトウェアは設計思想に合わせて利用すると、アップグレードに強い。
ビンゴゲームはMITですので、お気軽にお使いください。
現場からは以上です!EoT
- 投稿日:2021-03-05T05:46:44+09:00
Vue.js × Electron × Firebaseで ニコ生コメント風アプリ を作る
お魚学部からSIer就職して1年、フロントやらIoTやらやっている「てぬ太」です。
先日、オンライン勉強会を開催するにあたって、参加者の反応が見えないことが怖かったので画面にコメントが流れるアプリを作成しました。はじめに、このアプリ作成にあたっては、@yunecoさんの記事およびソースコードを参考にさせていただきました。
Vue.jsと物理演算とElectronで仕事中にデスクトップでお寿司をつまめるようになったのでソースと解説【クソアプリ】
VueとFirebaseの基本機能全部使ってぬるぬる動くポートフォリオサイトを作ったのでソースと解説本投稿内では差分の工夫・苦労した点を主に書いていきます。
1. デモ画面
2. 使った技術
3. 参加者が使用するwebアプリ
4. 主催者が使用するデスクトップアプリ
5. まとめ細かい実装はこちらで
github:
https://github.com/tenugui-taro/nico_come_form_public
https://github.com/tenugui-taro/nico_come_screen_public1. デモ画面
参加者:Webアプリからコメント書き込み
主催者:共有している画面にコメントが流れる
2. 使った技術
Vue.js:投稿時点で最新は Vue3ですが Vuetifyを使用するために、Vue2を使用しています。
@vue/composition-api:Vue2でも composition-api の記述が出来るようになる。
Vuetify:素敵なデザイン・動きを手軽に使えるようになるVue UIライブラリ
投稿時点で Vue3 対応版リリースは、2021年Q3予定(ロードマップ)
Electron:背景透過からデスクトップアプリ作成までを担ってくれる。
Firebase:ログイン、データ更新・取得程度の機能ならバックエンド実装ほぼなしの手軽さ3. 参加者が使用するwebアプリ
https://github.com/tenugui-taro/nico_come_form_public
参加者にインストールなどの手間をかけさせないよう、Webアプリを用意しました。
機能・仕様としては以下の通りです。
【Firebase】
・匿名ユーザーでログイン可能
・リアルタイムでのデータ送信・取得 ※Realtime Database 使用【Vue】
・コメント投稿・履歴取得
・手軽に投稿できる定型文を用意
・色のカスタマイズ
・ハートの個数=投稿可能数VuetifyのUIコンポーネントが豊富でデザインは特に困らず。
v-rating
v-color-picker
v-data-tablefirebaseを連携させたナビゲーションガード
サインインしていなければリダイレクトというよくある実装。
src/router/index.tsrouter.beforeEach((to, from, next) => { const requiresAuth = to.matched.some(record => record.meta.requiresAuth); if (requiresAuth) { firebase.auth().onAuthStateChanged(user => { if (user) { signIn.value = true; next(); } else { // サインインしていない -> ログインページへリダイレクト next({ path: "/" }); } }); } else { next(); } });composition-api を切り出す
作るなかで、階層が深くなりコンポーネントをまたぐ値が増えてしまいました。
そこで、composition-api を別ファイルに切り出すことで、Webアプリ全体でリアクティブな値を保持するようにしました。src/plugins/composition-api.tsimport Vue from "vue"; import VueCompositionAPI from "@vue/composition-api"; Vue.use(VueCompositionAPI);src/main.tsimport Vue from "vue"; import App from "@/App.vue"; import router from "./router"; import "@/plugins/composition-api"; import vuetify from "@/plugins/vuetify"; Vue.config.productionTip = false; new Vue({ router, vuetify, render: h => h(App) }).$mount("#app");src/store/commentColor.tsimport "@/plugins/composition-api"; import { ref } from "@vue/composition-api"; export const commentColor = ref("#000000");子のイベントを親側でまとめて処理する
複数の子コンポーネントの処理の内容が同じだったので、親側の1つの関数で処理をまとめました。
src/views/Home.vue<template> <!-- 関係ない要素は省略しています --> <CommentForm @sendComment="sendComment" /> <FlashComments @sendFlashComment="sendComment"/> </template> <script lang="ts"> import { defineComponent } from "@vue/composition-api"; export default defineComponent({ setup() { const sendComment = () => { // 処理 }; return { sendComment }; } }); </script>4. 主催者が使用するデスクトップアプリ
https://github.com/tenugui-taro/nico_come_screen_public
機能・仕様としては以下の通りです。
【Firebase】
・リアルタイムでのデータ取得 ※Realtime Database 使用【Vue】
・コメントを画面に流す【Electron】
・透明なウィンドウを画面に表示する透明なウィンドウを画面に表示する
詳しくはこちら→Vue.jsと物理演算とElectronで仕事中にデスクトップでお寿司をつまめるようになったのでソースと解説【クソアプリ】
以下、2点を追加で設定しています。
・ウィンドウサイズを画面に合わせて最大化
・デベロッパーツールを別ウィンドウで表示させるsrc/background.tsasync function createWindow() { // Create the browser window. const win = new BrowserWindow({ width: 800, height: 600, transparent: true, frame: false, resizable: false, backgroundColor: '#00FFFFFF', hasShadow: false, alwaysOnTop: true, webPreferences: { enableRemoteModule: true, nodeIntegration: true, }, }); win.setIgnoreMouseEvents(true, { forward: true }); win.maximize(); // ウィンドウサイズを画面に合わせて最大化 if (process.env.WEBPACK_DEV_SERVER_URL) { await win.loadURL(process.env.WEBPACK_DEV_SERVER_URL as string); // デベロッパーツールを別ウィンドウで表示させる if (!process.env.IS_TEST) win.webContents.openDevTools({ mode: 'detach' }); } else { createProtocol('app'); win.loadURL('app://./index.html'); } }コメントを画面に流す
流れるコメントの高さを固定する実装にかなりハマってしまいました。
最終的には top: 〇〇vh を設定することで他の要素に影響されなくなり、無事固定できました。画面を流れるアニメーションはtransition-groupを用いてcssで設定しています。
src/views/App.vue<transition-group appear> <template v-for="comment in comments"> <FlowComment :key="comment.id" :comment="comment" /> </template> </transition-group>src/components/FlowComment.vue<template> <h1 class="comment-text" :style="{ top: `${comment.posY}`, left: `-100vw`, color: `${comment.color}`, }" v-text="comment.text" /> </template> <style lang="scss" scoped> .comment-text { position: absolute; } .v-enter-active { transition: all 13s linear; } .v-enter { transform: translateX(200vw); } .v-enter-to { transform: translateX(-100vw); } </style>5. まとめ
試行錯誤していたはずが、終わってみると特に書くネタがないのはなぜ.......
せめて Vuetify使いつつcomposition-api使いたい!という方などの役に立てば幸いです。