- 投稿日:2020-09-27T17:38:11+09:00
魚インベーダー
Vue.jsをもう少し覚えた
先月、算数インベーダを作成した。
↓これ
https://qiita.com/loxop/items/6acc5a11229c387f854avuexも詳しくなりました。xxインベーダーを作るのにあんまり関係ないけどw
魚インベーダー
魚の漢字ってあまり知らない。
じゃ、学習しようってことで作ってみました。ロジック
落下してくる漢字に8個くらいの選択肢を表示して打つてな具合。
サーバ公開
DBとかないので普通にレンタルサーバーに公開できるはず。
これは、算数インベーダー作成時に習得済み。
ビルドしてパスの設定を vue.config.js に書いて配置。vue.config.jsmodule.exports = { publicPath: '/sakana', }以下のリンクで試せます。
http://auto-giken-fukuoka.jp/sakana/答えの選択肢のよみのボタンを選択して緑のエリアの下のほうをタップするとよみが発射されます。
- 投稿日:2020-09-27T13:31:48+09:00
typescriptベースでのVue.jsの書き方(基本)
はじめに
おはようございます。こんにちは。こんばんは。
Watatakuです。
今回はVue.jsでTypeScriptを始めよう(はじめかた)の続きなのですが前の章でTypeScriptの書き方が大体分かったのでTypeScriptベースでVueアプリを作っていきます。この記事はの対象者はVueを勉強しているけど「TypeScriptベースでアプリを構築したい!」という方へ向けて書いております。
基本の書き方
ではまずはじめに実際にコードを用いて解説していきます。
<template> <div class="hello"> <h1>{{ msg }}</h1> <h2>{{ this.count }}</h2> <button @click="countUp">increment</button> </div> </template> <script lang="ts"> import { Component, Prop, Vue } from 'vue-property-decorator'; @Component export default class HelloWorld extends Vue { @Prop() private msg!: string; private count: number = 0; public countUp(): void { this.count++; } } </script>上記サンプルコードでは、ボタンをクリックするたびにカウンタの値が一つづつ増えていくものです。
今回はこちらのコードで基本の解説をしていきます。まず最初に、
private count: number = 0;
です。
この部分はdata() { return { count: 0 } }と同じになります。
propsの受け取りと書き方
※
msg="Welcome to Your Vue.js + TypeScript App"
と言う文字列がpropsとして送られてくるとして解説します。
まずはPropsをvue-property-decorator
からインポートします。import { Prop } from 'vue-property-decorator';受け取りかたは
@Prop() private msg!: string;このように書くと親から送られてきたprops(Welcome to Your Vue.js + TypeScript App)を受け取ることができます。
因みに名称に「!」を付与する必要があります。メソッドの書き方
本来なら
methods: { ・・・・・・・ }のようにしてmethodsの中に各々メソッドを記述していきますがそんなことは必要なくただただVueクラス内でメソッドを書けばOKです。
その他の書き方
監視プロパティ:watch
ここからはスクロールの量を取得するサンプルコードを用いて解説していきます。
<template> <div class="about"> <h1>This is an about page</h1> <p>{{ this.scrollY }}</p> </div> </template> <script lang="ts"> import { Component, Vue, Watch } from 'vue-property-decorator'; @Component export default class About extends Vue { private scrollY: number = 0; public handleScroll(): void { this.scrollY = window.scrollY; } @Watch('scrollY') public scrollYChange(val: number, oldVal: number) { console.log( 'スクロールの値が' + oldVal + 'から' + val + 'に変化しました。' ); } private mounted(): void { window.addEventListener('scroll', this.handleScroll); } private destoryed(): void { window.removeEventListener('scroll', this.handleScroll); } } </script> <style> .about { height: 200vh; } </style>このようにwatchを使用する時は
vue-property-decorator
による@Watchデコレータによって記述しています。
※また使用する時はwatchをimportして下さい。import { Watch } from 'vue-property-decorator'@Watch('監視するもの', {deep: <真理値>, immediate: <真理値>}) <メソッド名>(val: データ型, oldVal: データ型) { // 処理 }ライフサイクル
ライフサイクルについてはこちらをご覧ください。
// ライフサイクルの書き方 public beforeCreate(): void { console.log('ライフサイクルbeforeCreate'); } public created(): void { console.log('ライフサイクルcreated'); } public beforeMount(): void { console.log('ライフサイクルbeforeMount'); } public mounted(): void { console.log('ライフサイクルmounted'); } public beforeUpdate(): void { console.log('ライフサイクルbeforeUpdate'); } public updated(): void { console.log('ライフサイクルupdated'); } public beforeDestroy(): void { console.log('ライフサイクルbeforeDestroy'); } public destroy(): void { console.log('ライフサイクルdestoroy'); }以上。
最後に
解説が浅いところとか、間違い等があると思いますのでその時はアドバイス等お願いします。
最後まで読んでいただきありがとうございました。
Twitterやってます。良ければチェックして見てください。
- 投稿日:2020-09-27T13:31:48+09:00
TypeScriptベースでVue.jsを書く(基本編)
はじめに
おはようございます。こんにちは。こんばんは。
Watatakuです。
今回はVue.jsでTypeScriptを始めよう(はじめかた)の続きなのですが前の章でTypeScriptの書き方が大体分かったのでTypeScriptベースでVueアプリを作っていきます。この記事はの対象者はVueを勉強しているけど「TypeScriptベースでアプリを構築したい!」という方へ向けて書いております。
基本の書き方
ではまずはじめに実際にコードを用いて解説していきます。
<template> <div class="hello"> <h1>{{ msg }}</h1> <h2>{{ this.count }}</h2> <button @click="countUp">increment</button> </div> </template> <script lang="ts"> import { Component, Prop, Vue } from 'vue-property-decorator'; @Component export default class HelloWorld extends Vue { @Prop() private msg!: string; private count: number = 0; public countUp(): void { this.count++; } } </script>上記サンプルコードでは、ボタンをクリックするたびにカウンタの値が一つづつ増えていくものです。
今回はこちらのコードで基本の解説をしていきます。まず最初に、
private count: number = 0;
です。
この部分はdata() { return { count: 0 } }と同じになります。
propsの受け取りと書き方
※
msg="Welcome to Your Vue.js + TypeScript App"
と言う文字列がpropsとして送られてくるとして解説します。
まずはPropsをvue-property-decorator
からインポートします。import { Prop } from 'vue-property-decorator';受け取りかたは
@Prop() private msg!: string;このように書くと親から送られてきたprops(Welcome to Your Vue.js + TypeScript App)を受け取ることができます。
因みに名称に「!」を付与する必要があります。メソッドの書き方
本来なら
methods: { ・・・・・・・ }のようにしてmethodsの中に各々メソッドを記述していきますがそんなことは必要なくただただVueクラス内でメソッドを書けばOKです。
その他の書き方
算出プロパティ:computed
算出プロパティはアノテーションではなく、get構文を用いて実装します。
public get doubledCount(): number { return this.count * 2; }監視プロパティ:watch
ここからはスクロールの量を取得するサンプルコードを用いて解説していきます。
<template> <div class="about"> <h1>This is an about page</h1> <p>{{ this.scrollY }}</p> </div> </template> <script lang="ts"> import { Component, Vue, Watch } from 'vue-property-decorator'; @Component export default class About extends Vue { private scrollY: number = 0; public handleScroll(): void { this.scrollY = window.scrollY; } @Watch('scrollY') public scrollYChange(val: number, oldVal: number) { console.log( 'スクロールの値が' + oldVal + 'から' + val + 'に変化しました。' ); } private mounted(): void { window.addEventListener('scroll', this.handleScroll); } private destoryed(): void { window.removeEventListener('scroll', this.handleScroll); } } </script> <style> .about { height: 200vh; } </style>このようにwatchを使用する時は
vue-property-decorator
による@Watchデコレータによって記述しています。
※また使用する時はwatchをimportして下さい。import { Watch } from 'vue-property-decorator'@Watch('監視するもの', {deep: <真理値>, immediate: <真理値>}) <メソッド名>(val: データ型, oldVal: データ型) { // 処理 }
- deep : trueの場合、監視するプロパティがオブジェクトの場合ネストされた値の変更も検知します。
- immediate : trueの場合、初期読み込み時にも呼び出します。
ライフサイクル
ライフサイクルについてはこちらをご覧ください。
// ライフサイクルの書き方 public beforeCreate(): void { console.log('ライフサイクルbeforeCreate'); } public created(): void { console.log('ライフサイクルcreated'); } public beforeMount(): void { console.log('ライフサイクルbeforeMount'); } public mounted(): void { console.log('ライフサイクルmounted'); } public beforeUpdate(): void { console.log('ライフサイクルbeforeUpdate'); } public updated(): void { console.log('ライフサイクルupdated'); } public beforeDestroy(): void { console.log('ライフサイクルbeforeDestroy'); } public destroy(): void { console.log('ライフサイクルdestoroy'); }参考:https://noumenon-th.net/programming/2019/07/02/class-style/
以上。最後に
解説が浅いところとか、間違い等があると思いますのでその時はアドバイス等お願いします。
最後まで読んでいただきありがとうございました。
Twitterやってます。良ければチェックして見てください。
- 投稿日:2020-09-27T10:20:10+09:00
Nuxt.jsで認証認可入り掲示板APIのフロントエンド部分を構築する #4 サインアップページの作成
←Nuxt.jsで認証認可入り掲示板APIのフロントエンド部分を構築する #3 個別記事ページの作成
サインアップ(登録)ページの作成
サインアップページ及びそのロジックを作っていきますが、難易度が一気に上がります。
一気にすべて理解しようとせず、少しずつコードを読み解いていってください。まずはサインアップページを作ります。
pages/sign_up.vue<template> <v-app id="inspire"> <v-main> <v-container class="fill-height" fluid > <v-row align="center" justify="center" > <v-col cols="12" sm="8" md="4" > <form @submit.prevent="signUp"> <v-card class="elevation-12"> <v-toolbar color="primary" dark flat > <v-toolbar-title>SignUp form</v-toolbar-title> </v-toolbar> <v-card-text> <ul v-if="errors"> <li v-for="(message, i) in errors.full_messages" :key="i"> {{ message }} </li> </ul> <v-text-field id="name" v-model="name" label="name" name="name" prepend-icon="mdi-account" type="text" /> <v-text-field id="email" v-model="email" label="email" name="email" prepend-icon="mdi-email" type="email" /> <v-text-field id="password" v-model="password" label="Password" name="password" prepend-icon="mdi-lock" type="password" /> </v-card-text> <v-card-actions> <v-spacer /> <v-btn color="primary" type="submit"> 登録 </v-btn> </v-card-actions> </v-card> </form> </v-col> </v-row> </v-container> </v-main> </v-app> </template> <script> export default { data () { return { name: '', email: '', password: '', errors: [] } }, methods: { async signUp () { try { const data = await this.$store.dispatch('signUp', { name: this.name, email: this.email, password: this.password }) this.$store.commit('setUser', data.data) this.$router.push('/') } catch (e) { this.errors = e.data.errors } } } } </script>フォームを送信すると
signUp()
メソッドが発火し、storeのsignUpアクション(この後作ります)でRails APIにPOSTし、正常終了したらsetUser
でユーザーデータをstoreに保存(この後作ります)。
エラーが起きたらcatchしてエラーを出力している、という形です。参考:Vue Material Component Framework — Vuetify.js
store側の実装
ログインに関わる処理はサイト全体で共通して使いそうなので、store/index.jsに書いていきます。
store/index.jsexport const state = () => ({ user: null, auth: {}, logged_in: false }) export const getters = { user (state) { return state.user }, logged_in (state) { return state.logged_in }, auth (state) { return state.auth } } export const mutations = { setUser (state, value) { state.logged_in = !!value state.user = value }, setAuth (state, value) { state.auth = value } } export const actions = { async signUp (_c, user) { return await this.$axios.$post('/v1/auth', user) } }ログインしているかどうかの判定に使うlogged_inに注目。
setUser(state, value) {
state.logged_in = !!value
state.user = value
},
ユーザー情報セットの際、二重否定を使うことでuserの中身があればtrue, なければfalseが入るようにしています。axiosの拡張
続いてaxiosのデフォルト挙動を変えます。
axiosでサーバサイドと通信する度にgetter['auth']
してヘッダに付与するのは冗長かつしんどいので共通化します。
また、レスポンスが返ってくるたびにアクセストークンをstoreに保存するのも毎度書いていたら辛いので一緒に共通化します。plugins/axios.jsexport default ({ $axios, store }) => { $axios.onRequest((config) => { config.headers = store.getters.auth }) $axios.onResponse((response) => { if (response.headers['access-token']) { const authHeaders = { 'access-token': response.headers['access-token'], client: response.headers.client, expiry: response.headers.expiry, uid: response.headers.uid } store.commit('setAuth', authHeaders) } }) $axios.onError((error) => { return Promise.reject(error.response) }) }nuxt.config.jsplugins: [ + '~/plugins/axios' ],
これで、以後axiosを使う度、リクエストにはアクセストークンが自動付与されて、レスポンス後はトークンがstoreに自動保存されます。
セッション永続化の準備
今のままだと認証情報はstoreに入れているだけなので、画面遷移する分には問題ないのですが、F5押下のようにリロードするとログアウト状態になってしまいます。
これを永続化するためにはトークン情報をcookieかWebStorageに保存する必要があります。
今回は簡易的な機能のためlocalStorageを使いますが、トークンをlocalStorageに保存することはセキュリティ的には弱いため、ちゃんとしたプロダクトでは避けた方が良いかもしれません。
参考:HTML5のLocal Storageを使ってはいけない(翻訳)
- cookie:サーバサイド・クライアントサイドどちらでも読み込み書き込みできるため、SSRでも使える。ただし値セットが面倒
- WebStorage(LocalStorage):クライアントサイドのみのため、SSRでは使えない。そのため一瞬未ログイン画面が出てしまうデメリットがあるが、pluginを入れれば超簡単にstoreを永続化できる
今回は手軽さを取ってLocalStorageを使います。
$ yarn add vuex-persistedstatenuxt.config.jsplugins: [ - '~/plugins/axios' + '~/plugins/axios', + { src: '~/plugins/localStorage.js', ssr: false } ],plugins/localStorage.jsimport createPersistedState from 'vuex-persistedstate' export default ({ store }) => { createPersistedState({ key: 'bbs_session', paths: [ 'auth' ] })(store) }これだけの設定で、
state.auth
がbbs_session
というlocalStorageのkeyで保存されます。
特にlocalStorageを意識することなくstate.auth
に値をセットするとlocalStorageにもセットされるというすぐれものです。とはいえこれだけでは保存しているだけで、画面リロード時に読み込む処理が入っていません。
そのロジックは共通レイアウトに入れてしまいます。共通レイアウトの修正
ここまでで機能の大部分はできました。
ですが共通レイアウトが暗く見づらい上、不要なサイドバー等があるので作り直す勢いで修正します。また、前述の通り画面リロード時のセッション復元も作ります。
layouts/default.vue<template> <v-app> <v-app-bar fixed app > <n-link to="/"> <v-toolbar-title v-text="title" /> </n-link> <v-spacer /> <span v-if="logged_in"> {{ current_user.name }}さん </span> <v-btn v-if="logged_in" icon > <v-icon>mdi-logout</v-icon> </v-btn> <v-btn v-else icon to="/sign_up" nuxt > <v-icon>mdi-account-plus</v-icon> </v-btn> </v-app-bar> <v-main> <v-container> <nuxt /> </v-container> </v-main> <v-footer app > <span>© {{ new Date().getFullYear() }}</span> </v-footer> </v-app> </template> <script> export default { data () { return { title: 'Sample bbs' } }, computed: { current_user () { return this.$store.getters.user }, logged_in () { return this.$store.getters.logged_in } }, async beforeMount () { const session = JSON.parse(window.localStorage.getItem('bbs_session')) if (session && Object.keys(session.auth).length) { await this.$axios.$get('/v1/auth/validate_token') .then(data => this.$store.commit('setUser', data.data)) .catch(() => { this.$store.commit('setUser', null) this.$store.commit('setAuth', {}) }) } } } </script>
beforeMount()
はCSR(クライアントサイドレンダリング)でのみ最初に実行されます。
localStorageはサーバサイドで使えないので、クライアントサイド描画されるタイミングでセッションの値を取得し、auth
が保存されている場合(画面更新直前までログイン状態だった場合)にvalidate_tokenを叩きにいき、user情報とauthの更新をしてログイン状態を復帰します。
無効なauthパラメータだった場合はuserとauthをクリアします(自動的にlocalStorageもクリアになります)。ここまで組み込めば、ログイン後に画面更新してもセッション復帰する状態になるはずです。
ページを開いた直後は未ログイン状態ですが、ちょっと待てばログインになります。
このタイムラグが気になる場合はcookieで実装が必要になります。nuxt.config.jsvuetify: { customVariables: ['~/assets/variables.scss'], theme: { - dark: true, + dark: false, themes: { - dark: { + light: { primary: colors.blue.darken2, accent: colors.grey.darken3, secondary: colors.amber.darken3,そして色変え。これでだいぶスッキリするはずです。
参考
Rails devise token authとNuxt.jsを連携(Twitter認証)
Nuxt.jsのStoreによるデータ保存 [vuex-persistedstate][js-cookie]続き
→Nuxt.jsで認証認可入り掲示板APIのフロントエンド部分を構築する #5 ログイン・ログアウトの実装
【連載目次へ】