20200122のvue.jsに関する記事は12件です。

⛰【Vue.js】MariaDBのJSON型カラムから取得したデータの指定の値を変数名で取り出す為にパースする

環境

Vue.js 6.12.0
PHP 7.3.10
Laravel 6.5.0
MariaDB

やりたいこと

MariaDBのに下記のようなデータが格納されていてそれをLaravelのAPIで取得する。
その内のcontentカラム(JSON型)のデータからdata_kindの値を判断基準として条件分岐を行い、
valueの内容である「テストの内容です?」や「赤文字で強調する!!」や円周率をVueので表示する為にJSONをパースする

id content del_flg
1 {"data_kind": "1", "value": "テストの内容です?"} 0
2 {"data_kind": "2", "value": "赤文字で強調する!!"} 0
3 {"data_kind": "3", "value": "円周率を表示"} 0
4 {"data_kind": "4", "value": "削除済み???"} 1

やったこと

下に全体で色々書いてますが一番重要なのは下記のパース部分です
これが無いとJSONではなくJSONの形をしたただの文字列としてデータが扱われるので値を取り出すことができません

          // 取得データをforEachで全てJSON.parseにかける
          res.data.recordList.forEach(value => {
            value["content"] = JSON.parse(value["content"]);
          });

全体

Hoge.vue
// テンプレ部分
<template>
  <section class="container">

    <div v-for="data in tableData" :key="content.id">
      <!-- 通常表示 -->
      <div v-if="data.content.data_kind === '1'">{{ data.content.value }}</div>
      <!-- クラスを付けて装飾を変更 -->
      <div v-else-if="data.content.data_kind === '2'" class="redBold">{{ data.content.value }}</div>
      <!-- 円周率を表示 -->
      <div v-else-if="data.content.data_kind === '3'">3.141592653589323846....</div>
    </div>

  </section>
</template>

// データ取得とパース部分
<script>
export default {
  data() {
    return {
      tableData: []
    };
  },
  methods: {
    getContent() {
      axios
        .get("/api/getContent", {
          params: {
            delFlg: 0
          }
        })
        .then(res => {
          // 取得データをforEachで全てJSON.parseにかける
          res.data.recordList.forEach(value => {
            value["content"] = JSON.parse(value["content"]);
          });
          this.tableData = res.data.recordList;
        });
    }
  },
  mounted() {
    this.getContent();
  }
};
</script>

// 装飾
<style lang="sass" scoped>
.redBold
  color: red
  font-weight: bold
</style>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vue.js computedとmethodの違い

この記事は初心者向け Vue.jsでcomputedとmethodsの違いについて記述した自分用メモになります。
誤っている点がありましたらご指摘をお願いいたします。

この記事は以下の方向けの記事となっております。

推定読者:
・computedとmethodのそれぞれの使い方は分かるが、2つの違いが分からない人
・どんな時にどちらを使えばいいのか分からない人

computedとmethodの違い

computedとmethodの違いは「キャッシュされるかどうか」です。
computedはキャッシュされ、methodはキャッシュされません。つまり、computedとmethodsは実行されるタイミングが異なります。

computedは参照先の値が変わった時のみ実行され、methodsはテンプレートの中身が再描画される度に実行されます。
この違いがどのような差をうむのかを以下に記述します。

キャッシュされるcomputedとキャッシュされないmethodsの違い

以下、全く同じ値を返すcomputedとmethodです。

    <button @click="counter += 1">カウンター</button>
    <button @click="otherCounter += 1">他のカウンター</button>
    <p>{{ otherCounter }}</p>
    <p>{{ counterMethod() }}</p>
    <p>{{ counterComputed }}</p>

 <script>
new Vue({
   el: '#app',
   data: {
     counter: 0,
     otherCounter: 0
   },
   methods: {
     counterMethod() {
          console.log('methodが実行されました')
          return this.counter > 2 ? '2より大きい': '2より小さい' 
      }
   },
   computed: {
     counterComputed() {
          console.log('computedが実行されました')
          return this.counter > 2 ? '2より大きい': '2より小さい'
      }
   }
 })
</script>  

zerokai.png

上記のコードはカウンターボタンが押された時、counterの値が1足され、足された値に対してmethodとcomputedがそれぞれ2より大きい値かどうかを返すという内容になっております。
また、cmethodとcomputedが実行されるタイミングが分かるようconsole.logで実行タイミングを見れるようにしています。

では、カウンターボタンを3回クリックしてみましょう。

実行結果
3click.png

赤枠で囲ったconsole.log結果に注目してください。
methodとcomputedの両方が実行されていることが分かります。

では、次に他のカウンターボタンを3回クリックしてみましょう。
実行結果
otherclick.png

赤枠で囲ったconsole.log結果に注目してください。
methodだけが実行されていることが分かります。

以上の結果から、
・methodは全く関係ない要素の変化であってもテンプレートが再描画される度に実行
・computedは関係する要素(参照している要素)が変化した場合のみ実行
上記2点のタイミング差による違いがわかりました。

参照したサイトさま

この記事を書くにあたり参照したサイト様、記事一覧です。

りんごとバナナとエンジニア/【Vue.js】computedとmethodsの違い

udemy教材
超Vue JS 2 入門 完全パック - もう他の教材は買わなくてOK! (Vue Router, Vuex含む)

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

初心者によるプログラミング学習ログ 217日目

100日チャレンジの217日目

twitterの100日チャレンジ#タグ、#100DaysOfCode実施中です。
すでに100日超えましたが、継続。

100日チャレンジは、ぱぺまぺの中ではプログラミングに限らず継続学習のために使っています。

217日目は

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

?【初心者】Nuxt.js とFirebaseを使ってログイン機能を実装する。 その3

前回に引き続き、Nuxt.jsのアプリケーションを作っていきます。
今回は、今まで準備してきたログイン機能を実際に動かしていきましょう。

前回はこちらからどうぞ。

ログイン機能の実装(store)

ログイン機能は基本的に
loginState(ここは変数ですので自分で名前を決めることができます。)という状態がtrueの時に画面を表示し、falseの時に問答無用でログイン画面に戻す。」
という操作のことを指します。
状態の操作を行うので、まずはその1で触れたように/storeをいじくります。
store/index.jsのファイルを作りここに記述していきます。

store/index.js
// 保持させるデータ
export const state = () => ({
  mailAddress: '',
  password: '',
  loginState: false,
})

// 同期処理
export const mutations = {

  // ログイン処理
  loginState(state, mailAddress, password) {
    state.mailAddress = mailAddress;
    state.password = password;
    state.loginState = true;
  },
  //ログアウト処理
  logoutState(state) {
    state.loginState = false;
  },
}

ここでstatemutationsが出てきました。
storeを使う上で非常に重要になってくるので、まとめて説明します。

storeの機能

state

アプリケーション内に共通の変数(グローバル変数)を管理するところです。
今回はmailAddresspasswordを空に、loginStatefalseに初期設定しています。
ここで扱っているものは、アプリケーションどこからでもthis.$store.state.ファイル名(index.jsなら省略).変数名でアクセスできます。

mutations

stateで設定した、変数を更新することができます。
ただし、非同期処理はできせん。非同期処理を行う場合は後述のactionsが必須になります。
ここで扱っているものは、アプリケーションのどこからでもthis.$store.commit('musation名', this.変数名, this.変数名, ~~~~~);
みたいな感じになります。
必ずcommitで呼び出さなければいけない事を覚えといてください。

storeには主に残り2つ機能があリます。
折角ですので、紹介させてもらいます。

actions

基本的には、mutationsを非同期処理したくなった時に使う機能です。
ここで扱っているものは、アプリケーションのどこからでもthis.$store.dispatch('action名', this.変数名, this.変数名, ~~~~~);

getters

ここではstateの値を加工することができます。
例で見た方が早いので、以下を見てください。

store/hoge.js
export const state = {
 runners: [
  {name: "A", time: 9.8},
  {name: "B", time: 10.1},
  {name: "C", time: 12},
  {name: "D", time: 5.2},
  {name: "E", time: 10},
 ]
},

export const getters = {
  getRuners: state => {
    return state.runners.filter(runner => runner.time <= 10)
  },

  fetchName: (state, getters) => {
    getters.getRunners.forEach(runner => console.log(runner.name))
  }
}

これでthis.$store.getters(fetchName)を呼ぶと、

console.
[
 {name: "A", time: 9.8},
 {name: "D", time: 5.2},
 {name: "E", time: 10},
]

となります。

以上が、storeで主に使っていく機能です。
今回は、statemutationsのみで製作していきます。

ログイン機能の実装(layouts/page)

ではここまでで作ってきたログイン機能を実際に動かすレイアウトを整えていきましょう。
まずは全体を表示するlayoutsからです。
layoutsは基本的にlayouts/default.vueのみしかいじりません。

layouts/default.vue
<template>
  <v-app>

    <v-content>
      <v-container>
        //この<nuxt />にpageが表示されていく
        <nuxt />
      </v-container>
    </v-content>

  </v-app>
</template>

基本はこれだけで大丈夫です。

次に、<nuxt />に表示させていくpagesを作っていきましょう。
まずスタートの画面となるpages/index.vueをいじっていきましょう。

pages/index.vue
<template>
  <v-container>
    <h3 style="color: black; text-align: center">ログイン</h3>
    <!-- ここにメールアドレスとパスワードを入力してもらう。それぞれmailAddress/passwordという変数に格納される。 -->
    <v-text-field v-model="mailAddress" label="メールアドレス" light></v-text-field>
    <v-text-field v-model="password" label="パスワード" light></v-text-field>
    <!-- エラー時(validがtrue時)にvalidErrorを表示させる -->
    <p class="errorMessage" style="color: red" v-if="valid">{{validError}}</p>
    <v-btn @click="login()"> ログイン </v-btn>
  </v-container>
</template>

<script>
import firebase from "~/plugins/firebase.js";

export default{
  data() {
    return {
        mailAddress: '', //打ち込んでもらうメールアドレス
        password: '', //打ち込んでもらうパスワード
        valid: false, //打ち込んだメールアドレス・パスワードが正しくない時はtrue、正しい時はfasle
        validError: "UserIDまたはPasswordが間違っています", //validがtrueの時に表示するメッセージ
    }
  },
  methods: {
    login: function() {
      //ここはただのfirebaseの公式の関数なので、あまり気にしなくて大丈夫です。
      firebase.auth().signInWithEmailAndPassword(this.mailAddress, this.password)
       .then(user => {
        //storeのmutationsの`loginState`を呼び出す
        this.$store.commit('loginState', this.mailAddress, this.password);
        // ログインしたら飛ぶページを指定
        this.$router.push("top");
        //エラーがおきたら、以下の処理
      }).catch((error) => {
        this.valid = true;
      });
    },
  },
}

</script>

ここにあるmethodsでそのページ内の関数を定義します。
今回は、loginで最低限のログイン機能を実装しています。
firebase.auth().signInWithEmailAndPasswordは「メールアドレスとパスワードでログインしますよ。」というFirebase特有の関数です。(詳しくは公式を確認してください)

次に遷移先のページを作りましょう。
今回はthis.$router.push("top")というように、pages/top.vueという所に画面遷移をしてみます。
($routerの書き方は、その1methodsをみてください。)
では、pages/top.vueを作っていきましょう。

pages/top.vue
<template>
  <v-content>
    <h3 style="color: black">topです。</h3>
  </v-content>
</template>

<script>
</script>

とりあえずこんな感じにしました。
このページでは、まだ特に関数も必要ないので<template>だけで大丈夫です。
では実装してみましょう!

QiitaExample.gif

いい感じになりましたね。

まとめ

ここまでで一旦のログイン機能は完成です。
以降はリダイレクト処理、細かなVuetifyコンポーネントについて触れていきたいです。
また、間違っている点があれば教えてください!!

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

Nuxt.js + axiosでスネークケース・キャメルケースを相互変換する

サーバー側から返されるデータのオブジェクトキーはスネークケースの場合がほとんどですが、Nuxt.jsにおいてはキャメルケースで扱われることが主流となっています。
スネークケースとキャメルケースを併用して書くこともできますが、記述量が増えることでメンテナンスしづらくなる要因の一つになります。

そこで、Nuxt.js + axiosでスネークケース・キャメルケースを相互変換するプラグインを作成しました。

まず、camelcase-keyssnakecase-keysをインストールします。

/plugins/axios.jsファイルを作成します。

axios.js
import camelcaseKeys from 'camelcase-keys'
import snakecaseKeys from 'snakecase-keys'
export default ({ $axios }) => {
  $axios.onRequest((config) => {
    if (!config.data || typeof config.data !== 'object') {
      return config
    }
    config.data = snakecaseKeys(config.data)
    return config
  })
  $axios.onResponse((response) => {
    if (!response.data || typeof response.data !== 'object') {
      return response
    }
    response.data = camelcaseKeys(response.data)
    return response
  })
}

nuxt.config.jsのpluginsに追記します。(axiosがmodulesに追加されているかも確認してください)

nuxt.config.js
...
plugins: [
  {
    src: '~/plugins/axios'
  }
],
modules: [
  '@nuxtjs/axios'
],
...

これでリクエスト時はキャメルケースのオブジェクトキーがスネークケースに、外部から受け取ったデータのオブジェクトキーがスネークケースならキャメルケースに変換されます。

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

【Firebase】onShapshotを使ったらVuexに怒られた話

はじめに

FirebaseのメソッドonSnapshotVuexを使用した際に、このようなエラーが出た。

Error: [vuex] do not mutate vuex store state outside mutation handlers.

stateは変更してないのに。。。という方も多いはず。

今回はこの原因と対処法についての記事です。

まずは、実際のコードがこちら

今回はチェックボックス付きのToDoリストを'snapshot'でリアルタイムに更新させるプロジェクトを作成してみました。

index.vue
<template>
  <div>
    <div v-for="(item, index) in taskList" :key="index">
      <input
        type="checkbox"
        :checked="item.isChecked"
        @click="toggleCheck(item.isChecked, item.id)"
      >
    </div>
  </div>
</template>

<script>
export default {
  ...mapState({
    taskList: state => state.taskList
  })
  created() {
    this.$store.dispatch('task/fetchTaskList')
  }
  methods: {
    toggleCheck(isChecked, taskId){
      this.$store.dispatch('task/toggleCheck', { isChecked: isChecked, taskId: taskId })
    }
  }
}
</script>
store/task.js
export const state = () => ({
  taskList: []
})

export const mutations = {
  setTaskList(state, list) {
    state.taskList = list
  }
}

export const actions = {
  fetchTaskList({ commit, rootState }) {
    const taskList = []
    this.$firestore()
      .collection('user')
      .doc(rootState.sign.uid)
      .collection('taskList')
      .onSnapshot(async querySnapshot => {
        await querySnapshot.forEach(doc => {
          const task = Object.assign(doc.data(), { id: doc.id })
          taskList.push(task)
        })
        commit('setTaskList', taskList)
      })
  }
}

簡単に言うと、snapshotでリストを取得して、表示させているだけです。
ここまでは問題なく動いています。

これにタスクのチェックを変更する処理を追加してみる。

store/task.js
async toggleDone({ rootState }, { isDone, taskId }) {
    const newTask = {
      isDone: isDone ? false : true
    }
    await this.$firestore()
      .collection('user')
      .doc(rootState.sign.uid)
      .collection('taskList')
      .doc(taskId)
      .set(newTask, { merge: true })
  }
}

このチェックボックスを押すとこのエラーが登場する。

Error: [vuex] do not mutate vuex store state outside mutation handlers.

stateは変更していないはずなのに、何故なのか?

詳しいエラーの状況

  1. 先ほどのエラーが出ている状態でリロードしてみた。

    • チェックの状態は問題なく反映されている。
    • ここでチェックの更新処理ではなく、リストの再取得に問題があることがわかる。
  2. リストを取得している関数にコンソールを出して、どこで止まっているのかを確認してみた。

    • チェックの値を更新した際にonSnapshot以降の処理しか動いていないことが判明。

つまりこういうこと

store/task.js
export const actions = {
  fetchTaskList({ commit, rootState }) {
    const taskList = []
    this.$firestore()
      .collection('user')
      .doc(rootState.sign.uid)
      .collection('taskList')
// firestoreの値が更新された際、ここから下の処理が自動で動く
      .onSnapshot(async querySnapshot => {
        await querySnapshot.forEach(doc => {
          const task = Object.assign(doc.data(), { id: doc.id })
          taskList.push(task)
        })
        commit('setTaskList', taskList)
      })
  }
}

onSnapshot移行しか処理が実行されていないとしたら、taskList.push(task)はどうやって実行されているのか??

つまり犯人はこいつである。

const taskList = []

考察

2回目の自動取得の際に新たなtaskListが存在せず、stateのtaskListを見てしまっていたのではないか。この処理はactionsで行っているので、エラーの内容にある通り、mutations以外でstateの値を変更することになっていた??。

結論

こうすればOK

store/task.js
export const actions = {
  fetchTaskList({ commit, rootState }) {
    this.$firestore()
      .collection('user')
      .doc(rootState.sign.uid)
      .collection('taskList')
// firestoreの値が更新された際、ここから下の処理が自動で動く
      .onSnapshot(async querySnapshot => {
        const taskList = []
        await querySnapshot.forEach(doc => {
          const task = Object.assign(doc.data(), { id: doc.id })
          taskList.push(task)
        })
        commit('setTaskList', taskList)
      })
  }
}

taskListの定義をonSnapshotの中に入れたら正常に動作した。

そもそも...

そもそも関数内で定義している変数名がstateで使用している変数名と同じなのはバグが増えるだけなのでやめた方がいいです。
関数用の変数名を自分なりに用意しておいた方がいいかも。

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

【Firebase】onShapshotを使ったらVuexに怒られた件

はじめに

FirebaseのメソッドonSnapshotVuexを使用した際に、このようなエラーが出た。

Error: [vuex] do not mutate vuex store state outside mutation handlers.

stateは変更してないのに。。。という方も多いはず。

今回はこの原因と対処法についての記事です。

まずは、実際のコードがこちら

今回はチェックボックス付きのToDoリストを'snapshot'でリアルタイムに更新させるプロジェクトを作成してみました。

index.vue
<template>
  <div>
    <div v-for="(item, index) in taskList" :key="index">
      <input
        type="checkbox"
        :checked="item.isChecked"
        @click="toggleCheck(item.isChecked, item.id)"
      >
    </div>
  </div>
</template>

<script>
export default {
  ...mapState({
    taskList: state => state.taskList
  })
  created() {
    this.$store.dispatch('task/fetchTaskList')
  }
  methods: {
    toggleCheck(isChecked, taskId){
      this.$store.dispatch('task/toggleCheck', { isChecked: isChecked, taskId: taskId })
    }
  }
}
</script>
store/task.js
export const state = () => ({
  taskList: []
})

export const mutations = {
  setTaskList(state, list) {
    state.taskList = list
  }
}

export const actions = {
  fetchTaskList({ commit, rootState }) {
    const taskList = []
    this.$firestore()
      .collection('user')
      .doc(rootState.sign.uid)
      .collection('taskList')
      .onSnapshot(async querySnapshot => {
        await querySnapshot.forEach(doc => {
          const task = Object.assign(doc.data(), { id: doc.id })
          taskList.push(task)
        })
        commit('setTaskList', taskList)
      })
  }
}

簡単に言うと、snapshotでリストを取得して、表示させているだけです。
ここまでは問題なく動いています。

これにタスクのチェックを変更する処理を追加してみる。

store/task.js
async toggleDone({ rootState }, { isDone, taskId }) {
    const newTask = {
      isDone: isDone ? false : true
    }
    await this.$firestore()
      .collection('user')
      .doc(rootState.sign.uid)
      .collection('taskList')
      .doc(taskId)
      .set(newTask, { merge: true })
  }
}

このチェックボックスを押すとこのエラーが登場する。

Error: [vuex] do not mutate vuex store state outside mutation handlers.

stateは変更していないはずなのに、何故なのか?

詳しいエラーの状況

  1. 先ほどのエラーが出ている状態でリロードしてみた。

    • チェックの状態は問題なく反映されている。
    • ここでチェックの更新処理ではなく、リストの再取得に問題があることがわかる。
  2. リストを取得している関数にコンソールを出して、どこで止まっているのかを確認してみた。

    • チェックの値を更新した際にonSnapshot以降の処理しか動いていないことが判明。

つまりこういうこと

store/task.js
export const actions = {
  fetchTaskList({ commit, rootState }) {
    const taskList = []
    this.$firestore()
      .collection('user')
      .doc(rootState.sign.uid)
      .collection('taskList')
// firestoreの値が更新された際、ここから下の処理が自動で動く
      .onSnapshot(async querySnapshot => {
        await querySnapshot.forEach(doc => {
          const task = Object.assign(doc.data(), { id: doc.id })
          taskList.push(task)
        })
        commit('setTaskList', taskList)
      })
  }
}

onSnapshot移行しか処理が実行されていないとしたら、taskList.push(task)はどうやって実行されているのか??

つまり犯人はこいつである。

const taskList = []

考察

2回目の自動取得の際に新たなtaskListが存在せず、stateのtaskListを見てしまっていたのではないか。この処理はactionsで行っているので、エラーの内容にある通り、mutations以外でstateの値を変更することになっていた??。

結論

こうすればOK

store/task.js
export const actions = {
  fetchTaskList({ commit, rootState }) {
    this.$firestore()
      .collection('user')
      .doc(rootState.sign.uid)
      .collection('taskList')
// firestoreの値が更新された際、ここから下の処理が自動で動く
      .onSnapshot(async querySnapshot => {
        const taskList = []
        await querySnapshot.forEach(doc => {
          const task = Object.assign(doc.data(), { id: doc.id })
          taskList.push(task)
        })
        commit('setTaskList', taskList)
      })
  }
}

taskListの定義をonSnapshotの中に入れたら正常に動作した。

そもそも...

そもそも関数内で定義している変数名がstateで使用している変数名と同じなのはバグが増えるだけなのでやめた方がいいです。
関数用の変数名を自分なりに用意しておいた方がいいかも。

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

?【初心者】Nuxt.js とFirebaseを使ってログイン機能を実装する。 その2

前回に引き続きNuxt.jsを用いて、アプリケーションを作っていきたいと思います。
今回は、タイトル通りFirebaseを導入してログイン機能を実装する準備をしていきたいと思います。

前回の記事を読まれていない方はこちらからどうぞ。

Firebase側の準備

FirebaseはGoogleが運用しているサービスになるため、必ずGoogleアカウントが必要になります。
Googleアカウントはすぐにできるので、そこは割愛させていただきます。

Firebaseの機能

まずはじめに、今回使っていく機能を簡単に紹介していきます。

Authentication

まず、ログイン機能を司っているFirebase Authenticationです。
こちらでログインする際に使う、アカウント・パスワードの情報を扱います。
今回の記事のメインになるやつです。

スクリーンショット 2020-01-21 14.51.29.png

Firestore

こちらがアプリケーションで扱うデータを保管するデータベース(DB)です。
管理者画面などを作る際にはここにユーザー情報を格納するのがいいと思います。

スクリーンショット 2020-01-21 14.55.44.png

今回主に使っていくのはこの2つのサービスだけです。
他のサービスが気になる方がいれば、ここFirebaseが提供しているサービスを詳しく説明してくれている記事があったので、チェックしてみてください。

Firebaseプロジェクトを作る

では以上に説明した機能を実際にアプリケーションに落とし込んでいく準備をしていきましょう。
ここから、fifebaseのトップページに移動して、「使ってみる」をクリックしてください。
スクリーンショット 2020-01-21 14.25.24.png

すると、「プロジェクトを追加」するボタンがあると思うのでそこをクリック。

スクリーンショット 2020-01-21 14.26.32.png

そこで、今回のFirebaseのプロジェクト名を決めてください。

スクリーンショット 2020-01-21 14.18.59.png

次に、Googleアナリティクスの使用の有無を聞かれるので、有効にしましょう。
Googleアナリティクスとは、そのサービスのアクセス数・使用デバイス・閲覧時間などを統計してくれるサービスです。
これらは基本無料なので、とりあえず有効にしておきましょう。
スクリーンショット 2020-01-21 14.28.01.png

ここで、Googleアナリティクスのアカウントが必要になります。
折角ですので、「新しいアカウントを作成」してみましょう。
スクリーンショット 2020-01-21 14.35.55.png

アカウント名を入力した後に、アナリティクスの対象地域を選択します。
この記事をみている時点で、日本在住だと思うので「日本」を選択してください。
スクリーンショット 2020-01-21 14.38.05.png

ではプロジェクトを作成してみましょう!

はい、以下のようになればプロジェクトは出来ています。
スクリーンショット 2020-01-21 14.45.38.png

Firebaseの基本情報を表示させる

ここで、後に記述する必要が出てくるこのプロジェクトの情報をみてみましょう。

Firebaseのトップページ左上にある歯車ボタンを押して、「プロジェクトの設定」をクリック。
スクリーンショット 2020-01-21 16.24.11.png

一番下に、以下のような欄があるので今回は</>のアイコンをクリック。
スクリーンショット 2020-01-21 16.24.27.png

すると、Firebaseを追加するアプリのニックネームを入力するページに飛ぶので、適当に名前をつけてあげてください。
今回はFirebasse Hostingの設定をしないので、下のチェックボックスは無視でいいです。
ちなみにFirebase Hostingとは、アプリケーションの公開時に安全に配信できるようにする機能のようです。

Firebase Hostingの公式はこちら
スクリーンショット 2020-01-21 16.31.04.png

すると今回のFirebaseの情報を見ることができます。
このまま「コンソールに進む」を押してください。

スクリーンショット 2020-01-21 16.31.38.png

以降この情報は先ほどの「プロジェクトの設定」から簡単に見ることができます。

Firestoreの設定

次に、Firestoreの設定を行います。
Firebaseトップページの右にある「開発」の「Database」の「データベースの作成」をクリック。
スクリーンショット 2020-01-21 19.38.38.png

すると、以下の画面になるので、今回は「テストモード」で行います。
スクリーンショット 2020-01-21 19.39.03.png

ここが重要なのですが、「Cloud Firestoreのロケーション」は必ずGoogleアナリティクスのロケーションに合わせてください。
ここで合わせないと、Firestoreが機能しません。
さらにタチの悪いことに、これは一回決めてしまうと、以降変更することができません。
必ず、「asia-northeast1」(東京)もしくは「asia-northeast2」(大阪)に設定してください。
スクリーンショット 2020-01-21 19.39.24.png

Firebase Authentication

次に、Firebase Authenticationの設定を行います。
Firebaseトップページの右にある「開発」の「Authentication」をクリック。
今回はメールアドレスとパスワードでログイン認証を行なっていきたいので、「ログイン方法」の「メール/パスワード」をクリック。
スクリーンショット 2020-01-21 22.48.34.png

1つ目のバーを有効にして保存してください。
スクリーンショット 2020-01-21 22.49.07.png

これで、メールアドレス/パスワードでのログインが可能になりました。

では早速、ログインアカウントのサンプルを作成してみましょう。
「ユーザー」から「ユーザーの追加」をクリックしてください。
スクリーンショット 2020-01-21 22.49.40.png
ここで、実際に使うアカウントの設定ができるので、適当に作ってしまいましょう。
スクリーンショット 2020-01-21 22.50.45.png
これは後に使っていくので、記憶しておいてください。

以上で、Firebase側の下準備は全て終了です。

アプリケーション側の準備

次は、Firebaseを導入できるようにアプリケーション側の準備をします。

まずは今回のアプリケーションにFirebaseを導入します。
以下のうち(npm, yarn)前回の質問で答えた方を実行してください。

npm install firebase --save
yarn add firebase --save

以上のコマンドを終えると、/package.jsonfirebaseの記述が加わり、導入できていることが確認できます。
スクリーンショット 2020-01-21 15.53.52.png
ここでさらに、firebaseCLIを導入します。(CLI(Command Line Interface)はコマンド操作のことです。)

npm install -g firebase-tools
yarn add -g firebase-tools

さらにFirebaseにログインします。

firebase login

飛ばされた先で支持通りに進み、
スクリーンショット 2020-01-21 17.21.14.png
この画面が表示されると、ログイン完了です。

Firebaseディレクトリの導入

次に、Firebaseディレクトリをインストールします。

ここでも前回みたいに、めちゃくちゃ質問されます。

サービスの選択

? Which Firebase CLI features do you want to set up for this folder? Press Space
 to select features, then Enter to confirm your choices. (Press <space> to selec
t, <a> to toggle all, <i> to invert selection)
❯◯ Database: Deploy Firebase Realtime Database Rules
 ◯ Firestore: Deploy rules and create indexes for Firestore
 ◯ Functions: Configure and deploy Cloud Functions
 ◯ Hosting: Configure and deploy Firebase Hosting sites
 ◯ Storage: Deploy Cloud Storage security rules
 ◯ Emulators: Set up local emulators for Firebase features

ここではFirebaseのどのサービスを使うかを選択します。
今回はFirestoreを選択します。

プロジェクトの選択

? Please select an option: (Use arrow keys)
❯ Use an existing project 
  Create a new project 
  Add Firebase to an existing Google Cloud Platform project 
  Don't set up a default project 

先ほどプロジェクトは作っているので、Use an existing projectを選択します。

? Select a default Firebase project for this directory: 
❯ qiita-example-d1ffc (Qiita-Example) 

さらに、先ほど作った自分のプロジェクトを選択します。

Firestoreのルールの記述

? What file should be used for Firestore Rules? (firestore.rules) 

? File firestore.rules already exists. Do you want to overwrite it with the Fire
store Rules from the Firebase Console? 
? What file should be used for Firestore indexes? (firestore.indexes.json) 

これらはそのままEnterで大丈夫です。

✔  Firebase initialization complete!

最後にこの一文が表示されたら、Firebaseディレクトリの初期設定は完了です!

Firebaseをプラグインする

次にfirebaseは外部モジュールの扱いになるので、前回述べたpluginsにも記述していきます。
まずは、/pluginsのなかにindex.jsを新しく作ってください。

/plugins/index.js
import firebase from "firebase";

const config = {
  apiKey: process.env.VUE_APP_apiKey,
  authDomain: process.env.VUE_APP_authDomain,
  databaseURL: process.env.VUE_APP_databaseURL,
  projectId: process.env.VUE_APP_projectId,
  storageBucket: process.env.VUE_APP_storageBucket,
  messagingSenderId: process.env.VUE_APP_messagingSenderId,
  appId: process.env.VUE_APP_appId,
  measurementId: process.env.VUE_APP_measurementId
};
if (!firebase.apps.length) {
  firebase.initializeApp(config);
}

export default firebase;

このprocess.envは、
.envのファイルの中身の値を持ってくる」
という意味です。
そのため、.envファイルに今回のFirebaseプロジェクトに必要な情報を記述していきます。

なぜこのようなめんどくさい事をするのかというと、アプリケーションを公開した際に、Firebaseの情報が漏れる事を阻止するためです。
plugins/index.jsに情報をベタ打ちしているとすぐにFirebaseの特定ができますが、公開されることがない.envに情報を記述する事で、それを阻止することができます。

では、.envに先ほど確認した情報を記述していきましょう。
「プロジェクトの設定」の一番下にある、Firebase SDK snippetの「構成」を選択し、ここに書いてある情報を記述していきます。
スクリーンショット 2020-01-21 16.51.00.png

/.env
VUE_APP_apiKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
VUE_APP_authDomain = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
VUE_APP_databaseURL = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
VUE_APP_projectId = "xxxxxxxxxxxxxxxxx",
VUE_APP_storageBucket = "xxxxxxxxxxxxxxxxxxxxxxxxxx",
VUE_APP_messagingSenderId = "xxxxxxxxxxxxxx",
VUE_APP_appId = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
VUE_APP_measurementId = "xxxxxxxxxxxxxxx"

こんな感じになると思います。
xxxの部分は自分のFirebaseの情報を書いてください。
またここでVUE_APP_を頭につける必要があります。(これがないと読み込まれません。)

またpluginsを使っているので、nuxt.config.jsに「pluginsFirebaseを使います!」と宣言しないといけません。

/nuxt.config.js
import colors from 'vuetify/es5/util/colors'

export default {
...
plugins: [
    '~/plugins/firebase',
  ],
...
}

こんな感じです。

以上でFirebaseの導入は完了です。

まとめ

下準備だけでもかなり時間がかかってしまいました。

次回からは、ようやくレイアウトの実装を行なっていきたいと思います。
また間違えている点などがあれば教えていただけると助かります!!

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

【Vue.js】[Vue warn]: Error in v-on handler: "TypeError: handler.apply is not a function

はじめに

Vue.jsVuetifyを使用したSPAアプリケーションを作成中に以下エラーが発生しました。

[Vue warn]: Error in v-on handler: "TypeError: handler.apply is not a function

こちらを解決していきます。

環境

OS: macOS Catalina 10.15.1
Vue: 2.6.10
vuetify: 2.1.0

何をしたかったのか

v-forv-listをリストレンダリングし、それぞれの項目に対して以下2点を動的に変更したいと考えました。

  1. router-link行き先
  2. v-onディレクティブで発火するイベント

この2がうまくいかず、ブラウザのコンソールにはタイトルにあるエラーが発生していました。

まずは元のコードを示します。

元のコード

Sample.vue
<template>
<!-- 略 -->
        <v-list>
          <v-list-item
            v-for="item in items"
            :key="item.id"
            @click="item.action"
          >
            <router-link :to="{ name: item.link }">
              <v-list-item-title>
                {{ item.name }}
              </v-list-item-title>
            </router-link>
          </v-list-item>
        </v-list>
<!-- 略 -->
</template>

<script>
  export default {
    data() {
      return {
        items: [
          {id: 1, name: '1へのリンク', link: 'Component1', action: ''},
          {id: 2, name: '2へのリンク', link: 'Component2', action: ''},
          {id: 3, name: 'action1を実行', link: '', action: 'action1'},
          {id: 4, name: 'action2を実行', link: '', action: 'action2'},
        ]
      }
    },
    methods: {
      action1() {
        anyAction1()
      },
      action2() {
        anyAction2()
      }
    }
  }
</script>

これで、router-linkは動的に変更できていましたが、methodsに定義したaction1, action2が発火しませんでした。

次に解決したコードを示します。

解決したコード(変更部周辺のみ抜粋)

Sample.vue
<template>
<!-- 略 -->
          <v-list-item
            v-for="item in items"
            :key="item.id"
            @click="triggerClick(item.action)"
          >
<!-- 略 -->
</template>

<script>
  export default {
    // 略
    methods: {
      triggerClick(action) {
      if (action === action1) {
        anyAction1()
      } else if (action === action2) {
        anyAction2()
      }
    }
  }
</script>

改善したポイント

  • v-list-item内の@click="triggerClick(item.action)"と、動的な引数を渡した
  • methods内でその動的な引数に応じて発火するイベントの内容を変化させた

おわりに

最後まで読んで頂きありがとうございました:bow_tone1:

どなたかの参考になれば幸いです:relaxed:

参考にさせて頂いたサイト(いつもありがとうございます)

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

Vue.jsでGoogleMapsAPIを使用して地図を表示する(多分)最小構成

はじめに

Vue環境でGoogleMapsAPIを使用する機会があったので、自分用の備忘録を兼ねて。
Vue.jsじゃなくてもある程度流用できると思います。

公式ドキュメント(APIキーの取得方法も書いてます)

コード

<template>
  <div>
    <div class="map" ref="googleMap" />
  </div>
</template>

<script>
import GoogleMapsApiLoader from 'google-maps-api-loader';

export default {
  name: 'Map',
  data() {
    return {
      google: null,
      mapConfig: {
        center: {
          lat: 35.68944,
          lng: 139.69167
        },
        zoom: 17
      }
    }
  },
  async mounted() {
    this.google = await GoogleMapsApiLoader({
      apiKey: 'API_KEY'
    });
    this.initializeMap();
  },
  methods: {
    initializeMap() {
      new this.google.maps.Map(this.$refs.googleMap, this.mapConfig);
    }
  }
}
</script>

<style lang="scss" scoped>
.map {
  width: 100vw;
  height: 100vh;
}
</style>

Maps JavaScript APIを読み込むのにgoogle-maps-api-loaderを使用しました。

もっと実用的なGoogleMapsAPIとVue.jsの組み合わせ方はVue.jsの公式ドキュメントに載っているのでこちらを参考にすると良いかもしれません。

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

Vuetify Componentに定義されているCSSを上書きするTips

背景

タイトルそのまま

結論

scoped cssを使わない。

<template>
  <v-parallax dark :src="require('../../assets/images/hoge.jpg')" 
  </v-parallax>
</template>

<style>
.v-parallax__image {
  transform: translate(-50%, 0px) !important;
}
</style>

参考

How to override vuetify styles?

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

Vue + Firebase 本番デプロイコマンドメモ

前提

①firebaseでの各種設定を済ませていること

②ターミナルでfirebaseへのログイン

$
firebase login
zsh: command not found: firebase

と出てきてしまったら、、
npmのパスに問題がある可能性があるので

npm bin -g

でパスを確認

/Users/emisub/.npm-global/bin
(not in PATH env variable)

(not in PATH env variable)と出てきてしまったらパスを通す必要あり

export PATH=$PATH:`npm bin -g`

でパスを通す

③npmのインストール

$
npm i -g firebase-tools

Vueファイルを本番環境用に

$
npm run build

Firebaseにデプロイ

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