iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 30
0
Modern Web

我或許沒那麼懂 Web系列 第 30

Vuefire: Vue.js + Firebase

Day 30: Vuefire: Vue.js + Firebase

#ironman/2018/我或許沒那麼懂Web

本系列文前面介紹了 Vue.js 的資料繫結與渲染的原理,後面介紹了 Cloud Firestore 的使用概念,今天就來介紹如何整合兩個作為總結吧!

Firebase 官方有自己維護的 SDK,請參見:GitHub - firebase/firebase-js-sdk: Firebase Javascript SDK。而 Vue.js 官方也有針對整合 Firebase 出了一個 JS 套件,就叫做 Vuefire,可參見:vuefire/packages/vuefire at lerna · vuejs/vuefire · GitHub

在進行下去以前,請先參照
Day 10: Cloud Firestore β: (2) 建立專案 & 文件
Day 20: Cloud Firestore β (12): 初始化

首先,我們先透過 Vue-CLI 建立一個 Vue 專案:

# 安裝 Vue CLI
npm install -g vue-cli

# 建立一個 Vue 專案
vue init webpack burning-ironman
cd burning-ironman

加入 Firebase JS SDK 和 VueFire 套件,並安裝所有相依套件。

yarn add firebase vuefire@next
yatn install

可能是因為 Cloud Firestore 還處於測試版中,vuefire 在支援 Cloud Firestore 的部分也處於 Alpha 的狀態,並透過 Lerna 進行套件管理,若是要安裝有支援的版本,我們就要使用其在 npm 上的 next 版本。

編輯 ./src/main.js,引入相關套件並且加入資料庫初始化設定。

// src/main.js

import VueFire from 'vuefire'
import firebase from 'firebase/app'
import 'firebase/firestore'

Vue.use(VueFire)
firebase.initializeApp({
  projectId: 'YOUR_PROJECT_ID',
  databaseURL: 'YOUR_DB_URL'
})

export const db = firebase.firestore()

或者你也可以像我一樣將資料庫設定與 VueFire 分開:

// src/main.js

import VueFire from 'vuefire'
Vue.use(VueFire)
// src/db.js

import firebase from 'firebase/app'
import 'firebase/firestore'

// Initialize your firebase app
firebase.initializeApp({
  projectId: 'YOUR_PROJECT_ID',
  databaseURL: 'YOUR_DB_URL'
})
firebase.firestore().settings({ timestampsInSnapshots: true })

export const db = firebase.firestore()

我們以專案預設生成的 HelloWorld.vue 為例。首先我們要在 data() 回傳的資料物件中建立一個屬性用來存取資料, 並且給他初始值,避免在 Cloud Firestore 取得資料前就被用,引發 undefined 造成的程式出錯。然後再到 firestore() 回傳的資料物件中使用剛剛在 data() 建立的屬性鍵名去賦值。db 引入自我們剛剛建立的 db.js 所初始化的資料庫,用這個下查詢方法就可以了。

import { db } from '../db'

export default {
  name: 'HelloWorld',
  data () {
    return {
      districts: []
    }
  },
  firestore () {
    return {
      locations: db.collection('districts').orderBy('name')
    }
  }
}

如此一來我們就可以在 Template 中使用:

<template>
  <div>
    <article v-for="(district, idx) in districts" :key="idx">
      <h1>{{ district.name }}</h1>
      <ul>
        <li>City: {{ district.city }}</li>
        <li>Population: {{ district.population }}</li>
      </ul>
    </article>
  </div>
</template>

如果是要新增資料,則可以在 method() 返回的物件中建立對應方法,然後在裡面使用 db:

export default {
  name: 'HelloWorld',
  data () {
    return {
      districts: [],
      formMessage: '',
      formName: '',
      formPopulation
    }
  },
  firestore () {
    return {
      locations: db.collection('districts').orderBy('name')
    }
  },
  methods: { 
    addDistrict () {
      if (this.formName === '' || this.formPopulation === '') {
        this.formMessage = '資料不完全!'
      }
      db.collection('districts')
        .add({ this.formName, this.formPopulation })
        .then(() => {
          this.formName = ''
          this.formPopulation = ''
          this.formMessage = '已成功新增一個行政區!'
        })
        .catch(() => {
          this.formMessage = '資料在送出時遇到問題!'
        })
    }
  }
}
<template>
  <form @submit="addDistrict()">
    <p>{{formMessage}}</p>
    <input v-model="formName" placeholder="District Name">
    <input v-model="formPopulation" placeholder="District Population">
    <button type="submit">Add District</button>
  </form>
</template>

至於更新和刪除都是類似的方式,就不做示範了。

VueFire 取得資料的方式,一律都是使用 onSnapshot(),所以當伺服器上的資料有變動時,也會即時更新網頁上的資訊,這部分就不需要另外再處理了。可以參見其原始碼:


上一篇
Cloud Firestore β (21): 監聽變動 2
下一篇
後記 & 目錄
系列文
我或許沒那麼懂 Web31

尚未有邦友留言

立即登入留言