iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 19
1

昨天稍微看了一下自己的文章進度,發現有個東西漏掉,DAY 18 的內容提到 FirebaseModel.vue ,F_ 開頭的方法,這是另外做來 Mixin 的模組檔,如果只看昨天的程式碼是不行的,非常抱歉請先在這章我們整理一隻 FirebaseModel.vue 出來,跟FirebaseModel.js 放在一起就可以了。

以下是目前 FirebaseModel.vue 的內容,已經先封裝到一個地步了,後續可能還會隨著專案進行有很多更動,這就是沒有好好規劃就開始挑戰30天的下場...。

其中有些程式碼目前還沒用到,後續章節慢慢帶入。

<template>
  <span>
  </span>
</template>

<script>
import { firebase, db } from './FirebaseModel.js'
export default {
  methods: {
  
    // 用來檢查目前登入者
    // 這邊算是用用看 async 看之後使用程式碼上會不會比較好讀。
    async F_showUser (e, msg) {
      console.log('觸發了F_showUser')
      var user = firebase.auth().currentUser
      // var name, email, photoUrl, uid, emailVerified
      console.log('F_showUser: ', user)
      if (user != null) return user
      else return null
    },

    // 登入方法
    F_signIn (account, password) {
      console.log('觸發了F_signIn')
      firebase.auth().signInWithEmailAndPassword(account, password).then(() => {
        console.log('登入成功')
        this.F_showUser().then(user => {
          this.$router.push(`/backend/${user.uid}`)
        })
      }).catch(function (error) {
        // Handle Errors here.
        var errorCode = error.code
        var errorMessage = error.message
        console.error(errorCode, errorMessage)
      })
    },

    // 註冊方法
    F_signUp (user) {
      firebase.auth().createUserWithEmailAndPassword(user.account, user.password).then(() => {
        this.F_setManagerData(user)
        this.$router.push('/backend')
      }).catch(function (error) {
        // Handle Errors here.
        var errorCode = error.code
        var errorMessage = error.message
        console.error(errorCode, errorMessage)
      })
    },

    // 登出方法
    F_signOut () {
      console.log('觸發了F_signOut')
      firebase.auth().signOut().then(function () {
        // Sign-out successful.
        console.log('登出成功')
      })
    },

    // 新增文章方法 (原本是F_updateArticle,避免和更新文章名稱衝突)
    F_addArticle (data) {
      console.log('觸發了F_updateArticle')
      db.collection('posts').add(data).then(res => {
        console.log('新增文章成功')
      }).catch(res => {
        console.log('新增文章失敗')
      })
    },
    
    F_updateArticle (data) {
        // 方法待新增,編輯文章用
    },

    // 監看者方法
    F_stateWatcher () {
      console.log('監看者觸發')
      firebase.auth().onAuthStateChanged(function (user) {
        if (user) {
          // User is signed in.
          // var email = user.email
          // var emailVerified = user.emailVerified
          // var photoURL = user.photoURL
          // var isAnonymous = user.isAnonymous
          // var uid = user.uid
          // var providerData = user.providerData
          console.log('現在使用者: ', user)
        } else {
          console.log('logout')
          //
        }
      })
    },
    
    // 確認已登入直接進後端
    F_checkLogin () {
      console.log('觸發了F_checkLogin')
      this.F_showUser().then(res => {
        console.log(res)
        if (res === null) this.$router.push('login')
        else this.$router.push(`backend/${id}`)
      })
    },

    // 抓該容器下所有文件
    F_getCollectionDocs (collection, orderBy) {
      const docs = []
      return db.collection(collection).orderBy(orderBy.where, orderBy.order).get().then(function (querySnapshot) {
        querySnapshot.forEach(function (doc) {
          const data = doc.data()
          data.id = doc.id
          docs.push(data)
        })
        return docs
      })
    },

    // 註冊管理者
    F_setManagerData (user) {
      db.collection('manager').doc(user.name).set({
        account: user.account,
        password: user.password,
        displayName: user.displayName,
        name: user.name,
        email: user.email,
        phoneNumber: user.phoneNumber,
        address: user.address
      }).catch(function (error) {
        console.error('Error writing document: ', error)
      })
    }, 
        
    // 更新個人資料 ( 非完整 )
    F_updateProfile (userInfo) {
      console.log('觸發了F_updateProfile')
      var user = firebase.auth().currentUser
      return user.updateProfile({
        displayName: userInfo.displayName
        // photoURL: photoURL
      })
    },

    F_getUserInfo () {
        // 待新增,註冊完進入個人編輯頁用
    },

    // 更新個人資料 ( 完整 )
    F_updateManagerInfo () {
        // 待新增,個人編輯頁更新資料用
    }
  }
}
</script>

main.js 要去混入我們的 firebase 模組


import firebase from './Model/FirebaseModel.vue'
Vue.mixin(firebase)

其中更新個人資料 ( 非完整 ) 的方法特別注意一下,updateProfile 只能提供兩個選項,一個是 displayName,一個是 photoURL,文件在這:

https://firebase.google.com/docs/reference/js/firebase.User#updateprofile

然後我們的 ArticleEditor.vue 有作些更動,注意 @ok 部分直接使用了上面 mixin 的方法。


<template>
  <b-container class="pageArticleEditor">
    <b-modal id="modal-1" title="是否新增文章" @ok="F_addArticle(articleData)">
      <p class="my-4">如要新增請按確認</p>
    </b-modal>
    <b-row>
      <b-col cols="12">
        <label for="input-large">文章標題:</label>
        <b-form-input id="input-large" size="lg" placeholder="請輸入文章標題" v-model="title"></b-form-input>
      </b-col>
      <b-col cols="12">
        <MarkdownPro
          @on-save="updateData"
        ></MarkdownPro>
      </b-col>
      <b-col class="mt-2"><b-button v-b-modal.modal-1 variant="primary">點擊新增文章</b-button></b-col>
    </b-row>
  </b-container>
</template>

<script>
import { MarkdownPro } from 'vue-meditor'
export default {
  name: 'ArticleEditor',
  data () {
    return {
      title: '',
      articleData: {}
    }
  },
  components: {
    MarkdownPro
  },
  methods: {
    updateData (saveEventInfo) {
      const splitter = '<!-- more -->'
      if (saveEventInfo.value.indexOf(splitter) === -1) {
        saveEventInfo.value = saveEventInfo.value.slice(0, 20) + splitter + saveEventInfo.value.slice(20)
      }

      saveEventInfo.stopOnMore = saveEventInfo.value.split(splitter)
      saveEventInfo.stopOnMore = saveEventInfo.stopOnMore[0] + '...'

      this.articleData = saveEventInfo
      this.articleData.title = this.title
      this.articleData.createdAt = new Date().getTime()
    
      // 這邊算是用用看 async => .then 看會不會比較好讀。
      this.F_showUser().then(res => {
        const buffer = {
          displayName: res.displayName,
          email: res.email,
          uid: res.uid,
          photoURL: res.photoURL
        }

        this.articleData.authorInfo = buffer
      })
    }
  }
}
</script>

articlePage.vue 也重整一下資料結構

<template>
  <b-container fluid>
    <b-row>
      <b-col cols="8" offset="2">
        <div class="article">
          <div class="content__header">
            <h3>{{ articleInfo.title }}</h3>
            <p>文章作者: {{ articleInfo.authorInfo.email }}</p>
            <p>上傳時間: {{ articleInfo.createdAt }}</p>
          </div>
          <div class="article__content" v-html="articleInfo.html"></div>
        </div>
      </b-col>
    </b-row>
  </b-container>
</template>

<script>
import { db } from '../Model/FirebaseModel.js'
export default {
  name: 'ArticlePage',
  data () {
    return {
      articleId: this.$route.params.articleId,
      articleInfo: {
        title: '',
        createdAt: '',
        authorInfo: {
          displayName: '',
          email: '',
          uid: '',
          photoURL: ''
        }
      }
    }
  },
  created () {
    const articleRef = db.collection('posts').doc(this.articleId)
    articleRef.get().then((doc) => {
      if (doc.exists) {
        this.articleInfo = doc.data()
      } else {
        // doc.data() will be undefined in this case
        console.log('No such document!')
      }
    }).catch(function (error) {
      console.log('Error getting document:', error)
    })
  }
}
</script>

ArticleList.vue 也來優化一下,不要用 {target} 接出來,太難看了,讓他每次傳該迴圈的 id 值進去 click。

<template>
  <div class="article__blocks">
    <div class="article__blocks__block" v-for="article in posts" :key="article.id">
      <div class="article__blocks__block_title">
        <h3>{{ article.title }}</h3>
      </div>
      <div class="article__blocks__block_content">
        <p>{{ article.stopOnMore }}</p>
      </div>
      <div class="goto" @click="gotoArticle(article.id)"  :data-articleId="article.id">
        <p> >> 繼續閱讀</p>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'ArticleList',
  props: {
    msg: String
  },
  created () {
    this.F_getCollectionDocs('posts', { where: 'createdAt', order: 'desc' }).then(docs => {
      this.posts = docs
    })
  },

  data () {
    return {
      posts: [
      ]
    }
  },

  methods: {
    gotoArticle (articleID) {
      const targetArticle = this.posts.find(ele => {
        return articleID === ele.id
      })
      this.$router.push(`/article/${targetArticle.id}`)
    }
  }
}
</script>

今天算中場休息,複製程式碼 Mixin 一下,明天我們要來完善我們的註冊流程。


沒事也可以逛逛我們其他團隊成員的文章啦 ~~
eien_zheng: 前端小嘍嘍的Golang學習旅程_The journey of learning Golang 系列
PollyPO技術: 前端設計轉前端工程師-JS踩坑雜記 30 天 系列
阿電: 忍住不打牌位,只要30天VueJS帶你上A牌 系列
喬依司: 實作經典 JavaScript 30 系列


上一篇
Day 18: 製作完整個人訊息編輯頁
下一篇
Day 20: 完善註冊流程 01 - 前台註冊優化
系列文
Vue CLI + Firebase 雲端資料庫 30天打造簡易部落格及後臺管理30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言