Vue、Google firestore、およびGoogle認証とシンプルなtodoアプリ

63091 ワード


導入


私は、最速の最も簡単な意味のプロジェクトを行うことによってプログラミング言語を学ぶ.実際のプロジェクトを行うことで、デザインから利益を得ることができますし、プロジェクトを最初から最後まで管理します.この記事では、我々はアプリケーションを使用してビルドを学ぶVue VUEアプリケーションの状態管理Vuex
この記事では次のことを学びます
  • vue cli ( version 2 )を使用してプロジェクトを作成する
  • Vueコンポーネントの作成と使用
  • ブートストラップVueを使用したコンポーネントのスタイル
  • 状態管理のためのVUEXの使用
  • Google Firebase認証による認証
  • Googleファイアストア
  • ソースコード


    からの完全なソースを見つけることができますGitHub

    前提条件

  • Visual Studioのコードをインストールhere
  • からインストールするhere
  • Vue CLIをインストールするhere
  • npm install -g @vue/cli
    

    プロジェクト作成


    あなたのマシンにインストールされているVueコマンドラインインターフェイス(CLI)を確認してください.VUE CLIを以下のコマンドを実行してインストールできます
    ToDoアプリケーションプロジェクトを作成する
    vue create todo-app
    
    上記のコマンドは新しいVueプロジェクトを名前で作成しますtodo-appディレクトリを新しいプロジェクトに変更
    cd todo-app
    
    インストール
    npm install vuex --save
    
    Vueブートストラップのインストール
    npm install bootstrap bootstrap-vue --save
    
    Firebaseをインストールする
    npm install firebase --save
    

    コンパイルとホットリロードの開発


    npm run serve
    

    生産のためのコンパイルとミニフィケーション


    npm run build
    

    ファイルとフィックスファイル


    npm run lint
    

    カスタマイズ設定


    参照Configuration Reference .

    VSコードでプロジェクトを開きます


    VSコードでプロジェクトを開きます
    code .
    
    Vue CLIによって生成されたデフォルトのファイル構造が表示されます

    HelloWorldを削除します.Vueコンポーネント今すぐ.後でコンポーネントを追加します.
    組み合わせコードキー( Ctrl + JまたはCMD + J )を押してVSコードで端末を開きます.

    firebaseを作成します。js


    Firebaseは認証とデータベースイベント( CRUD )を提供します.
    FireBaseプロジェクトを既に構成していることを確認してくださいGoogle Firebase
    新しい名前を作成するfirebase.js の下にsrc ディレクトリ
    次のコードをファイルにコピーします
    import firebase from 'firebase';
    // For Firebase JS SDK v7.20.0 and later, measurementId is optional
    const firebaseConfig = {
      // Add your firebase config here
    };
    
    const firebaseapp = firebase.initializeApp(firebaseConfig);
    
    // database
    const db = firebaseapp.firestore();
    
    // authentication
    const auth = firebase.auth();
    const provider = new firebase.auth.GoogleAuthProvider();
    
    export { auth, provider };
    export default db;
    
    設定を変更してくださいfirebaseConfig あなたと

    ステート管理用のオブジェクトを作成する


    ソースディレクトリ(src)ディレクトリの下にあるすべての州を持ちたい.
    次に、srcフォルダの下にあるストアという名前のフォルダを作成します.

    ユーザー状態を作成する


    ユーザーの状態をGoogle Firebaseを使用してサインアウトユーザーを管理する.これは、署名されたユーザーを制御したり、署名した.とユーザーインターフェイスは、ユーザーのステータスに基づいて更新されます.
    新しいJavaScriptファイルを作成するuser.js ストアディレクトリの下で.
    次のコードをファイルにコピーします
    const state = {
      user: null
    };
    
    const getters = {
      user: state => state.user
    };
    
    const actions = {
      signIn ({commit}, user) {
        commit('signIn', user);
      },
      signOut({commit}) {
        commit('signOut');
      }
    };
    
    const mutations = {
      signIn: (state, user) => {
        state.user = user;
      },
      signOut: state => state.user = null
    };
    
    export default {
      state,
      getters,
      actions,
      mutations
    };
    

    を作成する


    ToDoリストとToDo項目を管理する状態をtodos.の状態を制御します
  • Google Firestoreデータベースからの読み込みデータ
  • Firestoreデータベースへのデータの追加
  • データをFirestoreデータベースに更新する
  • データベースからデータを削除
  • 新しいJavaScriptファイルを作成するtodos.js ストアディレクトリの下で.
    次のコードをファイルにコピーします
    import db from '../firebase'
    
    // State declaration
    const state = {
      /**
       * each todo item will have the format
       * {
       *  id: String,
       *  title: String,
       *  completed: Boolean
       * }
       */
      todos: []
    };
    
    // Getters
    const getters = {
      // Get all todo items in the current state
      allTodos: state => state.todos
    };
    
    // actions
    const actions = {
      /**
       * Loading todos   
       * This is fetch data from database
       */
      fetchTodos ({commit}, user) {        
        db.collection('user')
          .doc(user.uid)
          .collection('todos')
          .onSnapshot(snapshot => {
            commit('setTodos', snapshot.docs.map(doc => {
              return {
                id: doc.id,
                doc: doc.data()
              }
            }));
          })    
      },
      /**
       * Add a new todo action
       * This is fired when the user submit the form add a new todo 
       * @param {String} payload - The title string of the the new todo
       */
      addTodo({ commit}, payload) {
        const uid = payload.user.uid;
        const title = payload.title;
    
        const newtodo = {
          title,
          completed: false
        };
    
        db.collection('user')
          .doc(uid)
          .collection('todos')
          .add(newtodo)
          .then(docRef => {
            commit('addTodo', {
              id: docRef.id,
              data: newtodo
            });
          }) 
      },
      /**
       * Update the status of the todo item in the state
       * @param {Object} payload - The object contains
       * - the id to identify the todo item in the collection list
       * - completed property to update the status of the todo item
       */
      toggleCompleted ({commit}, payload) {
        const uid = payload.user.uid;
        const id = payload.id;
        const completed = payload.completed;
        db.collection('user')
          .doc(uid)
          .collection('todos')
          .doc(id)
          .update({
            completed: completed
          })
        commit('toggleCompleted', {
          id,
          completed
        });
      },
      /**
       * 
       * @param {*} param0 
       * @param {Number} payload - The number id to identify the todo item in the collection
       */
      deleteTodo ({commit}, payload) {
        const uid = payload.user.uid;
        const id = payload.id;
        db.collection('user')
          .doc(uid)
          .collection('todos')
          .doc(id)
          .delete();
        commit('deleteTodo', id);
      }
    };
    
    // mutations
    const mutations = {
      setTodos: (state, todos) => {    
        state.todos = todos.map(todo => {
          return {
            id: todo.id,
            title: todo.doc.title,
            completed: todo.doc.completed
          }
        });
      },
      addTodo: (state, {id, data}) => {      
        console.log('addTodo');
        const newtodo = {
          id,
          title: data.title,
          completed: data.completed
        };  
        const oldTodos = [...state.todos];
        const index = oldTodos.findIndex(todo => todo.id === id);    
        // adding new todo the list
        if (index < 0) {
          state.todos.unshift(newtodo); // = [newtodo, ...state.todos];
        }
    
        console.log(state.todos);
      },
      toggleCompleted: (state, {id, completed}) => {
        const index = state.todos.findIndex((todo) => todo.id === id);
        if (index >= 0) {
          state.todos[index].completed = completed;
        }
      },
      deleteTodo: (state, id) => {
        const index = state.todos.findIndex((todo) => todo.id === id);
        if (index >= 0) {
          state.todos.splice(index, 1);
        }
      }
    };
    
    export default {
      state,
      getters,
      actions,
      mutations
    };
    

    クリエイトブイ


    現在、我々は両方のために州を持ちますuser and todos , 私たちは店のコレクションにそれらを使用したい
    新しいファイルを作成するstore.js の下にsrc フォルダ.
    次のコードをファイルにコピーします
    // Create a store
    import Vue from 'vue'
    import Vuex from 'vuex'
    import todos from './todos';
    import user from './user';
    
    Vue.use(Vuex);
    
    // create store
    export default new Vuex.Store({
      modules: {
        todos,
        user
      }
    });
    

    プロジェクトへのストアの追加


    開けるmain.js 我々のアプリケーションにストアを追加します.
    また、ここで我々のアプリケーションにブートストラップを追加します
    import Vue from 'vue'
    import App from './App.vue'
    // Import store
    import store from './store/store'
    // Bootstrap
    import { BootstrapVue, IconsPlugin } from 'bootstrap-vue'
    
    // import bootstrap and BootstrapVue css
    import 'bootstrap/dist/css/bootstrap.css'
    import 'bootstrap-vue/dist/bootstrap-vue.css'
    
    Vue.use(BootstrapVue);
    Vue.use(IconsPlugin);
    
    Vue.config.productionTip = false;
    
    new Vue({
      render: h => h(App),
      store
    }).$mount('#app')
    

    コンポーネントの作成


    現在、我々はすべてのセットアップを持っています.アプリケーションのコンポーネントを作成します.我々のアプリケーションは、次のコンポーネントがあります
  • Login コンポーネント-ログインするユーザーを表示するか、またはログアウトしました
  • NewTodo コンポーネント-新しいToDo項目を追加するフォームコンポーネントです
  • TodoList コンポーネント-それぞれのToDo項目を表示するリストビューです
  • TodoItem コンポーネント-これは表示されるToDo項目です
  • ログインコンポーネント


    新しいファイルを作るLogin.vue コンポーネントフォルダの下に.ファイルに次のスクリプトをコピーします
    <template>
      <div class="login">
        <div @click="logout" v-if="user" class="logout">
          <b-avatar variant="info" :src="imageSrc" class="mr-3"></b-avatar>
          <span class="mr-auto">{{user.user.displayName}}</span>      
        </div>
        <b-button v-else variant="primary" @click="login">Sign In</b-button>    
      </div>
    </template>
    <script>
    import { mapGetters, mapActions } from 'vuex';
    import { auth, provider } from '../firebase'
    
    export default {
      name: 'Login',
      data() {
        return {
          imageSrc: ''
        };
      },
      computed: mapGetters(['user']),
      methods: {
        ...mapActions(['signIn', 'signOut']),
        login() {
          auth
          .signInWithPopup(provider)
          .then(authUser => {
            this.imageSrc = authUser.user.photoURL;
            this.signIn(authUser);
          })
          .catch(error => alert(error.message))      
        },
        logout() {
          this.signOut();
        }
      }
    }
    </script>
    <style>
    .login {
      text-align: center;
    }
    
    .logout {
      cursor: pointer;
    }
    </style>
    

    コンポーネントの作成


    新しいファイルを作るNewTodo.vue コンポーネントフォルダの下に.ファイルに次のスクリプトをコピーします
    <template>
      <b-form @submit="AddNewTodo">
        <b-form-group
          label="Add new todo"
          label-for="newTodo"
        >
          <b-form-input
            id="newTodo"
            placeholder="What needs to be done"
            v-model="todo"
            required
          >        
          </b-form-input>
        </b-form-group>
        <b-button type="submit" variant="primary">Add New Todo</b-button>
      </b-form>
    </template>
    <script>
    // import actions
    import { mapGetters, mapActions } from 'vuex'
    
    export default {
      name: "NewTodo",
      data() {
        return {
          // data for binding to the input text
          todo: ''
        }
      },
      computed: mapGetters(['user']),
      methods: {
        ...mapActions(['addTodo']),
        /**
         * Form submit hanlder
         */
        AddNewTodo (event) {
          event.preventDefault();
          if (this.todo && this.todo !== "") {
            // update data base
            this.addTodo({
              user: this.user.user,
              title: this.todo
            })                  
            // clear todo
            this.todo = "";
          }      
        }
      }
    }
    </script>
    <style>
    
    </style>
    

    コンポーネントを作成する


    新しいファイルを作るTodoItem.vue コンポーネントフォルダの下に.ファイルに次のスクリプトをコピーします.TodoItem は親から3つのプロパティをとるTodoList )
  • id - identifierこの項目(この値はFirestoreデータベースによって生成されます)
  • title -これは文字列の説明です
  • 完了-これは、アイテムが完了したかどうかを表すbooleanです
  • <template>
      <b-form>
        <b-row>
          <b-col cols="11">
            <b-form-checkbox switch size="lg" :checked="completed" 
                @change="toggleComplete">                    
              <label :class="{complete: completed}">{{title}}</label>      
            </b-form-checkbox>       
          </b-col>      
          <b-col cols="1">
            <b-icon icon="trash" class="hover-trash" @click="removeTodo"></b-icon>
          </b-col>
        </b-row>
    
      </b-form>
    </template>
    <script>
    import { mapGetters, mapActions } from 'vuex'
    
    export default {
      name: 'TodoItem',
      props: {
        id: String, // The todo item key
        title: String, // The title description of the todo item
        completed: Boolean // indicating if the todo item has been completed
      },
      computed: mapGetters(['user']),
      methods: {
        ...mapActions(['toggleCompleted', 'deleteTodo']),
        toggleComplete () {
          // change the status of the todo item
          this.toggleCompleted({
            user: this.user.user,
            id: this.id,
            completed: !this.completed
          })
        },
        removeTodo () {
          // delete the todo from the state collection
          this.deleteTodo({
            user: this.user.user,
            id: this.id
          });
        }
      }
    }
    </script>
    <style scoped>
    .complete {
      text-decoration: line-through;
    }
    
    .hover-trash:hover {
      color: red;
    }
    
    .row {
      border-bottom: 1px solid gray;
    }
    </style>
    

    コンポーネントの作成


    新しいファイルを作るTodoList.vue コンポーネントフォルダの下に.ファイルに次のスクリプトをコピーします
    <template>
      <b-container fluid class="ml-3">
        <h1>Todo list goes here</h1>
        <ul>
          <li v-for="todo in allTodos" :key="todo.id">
            <todo-item :title="todo.title" :completed="todo.completed" :id="todo.id" ></todo-item>        
          </li>
        </ul>
      </b-container>
    </template>
    <script>
    import TodoItem from './TodoItem.vue'
    // vuex actions and getters
    import { mapGetters, mapActions } from 'vuex';
    
    export default {
      name: 'TodoList',
      components: {
        TodoItem
      },
      computed: mapGetters(['allTodos', 'user']),
      methods: {
        ...mapActions(['fetchTodos'])
      },
      created() {
        this.fetchTodos(this.user.user);
      }
    }
    </script>
    <style scoped>
    ul li {
      list-style: none;
    }
    </style>
    

    コンポーネントへのコンポーネントの追加


    開けるApp.vue そして次のようにコードを更新します
    <template>
      <div class="mt-5">
        <img alt="Vue logo" src="./assets/logo.png"> 
          <login></login>
          <div v-if="user">
            <b-container>        
              <new-todo></new-todo>      
            </b-container>
            <todo-list></todo-list>   
          </div>
      </div>
    </template>
    
    <script>
    import NewTodo from './components/NewTodo.vue'
    import TodoList from './components/TodoList.vue'
    import { mapGetters } from 'vuex'
    import Login from './components/Login.vue'
    
    export default {
      name: 'App',
      computed: mapGetters(['user']),
      components: {
        NewTodo,
        TodoList,      
        Login
      }
    }
    </script>
    
    <style>
    * {
      margin: 0;
      padding: 0;
    }
    
    img {
      display: block;
      margin-left: auto;
      margin-right: auto;
    }
    </style>
    

    ビルドと配備


    今、我々はすべてのコンポーネントを完了し、ローカルアプリケーションをテストしている.ビルドとアプリケーションの配備のための時間です.

    アプリケーションのビルド


    npm run build
    
    このコマンドはアプリケーションをコンパイルし、フォルダの下にあるすべてのファイルを生成しますdist . これは、Googleクラウドのホストに展開されるフォルダです.

    配備する


    あなたが持っていることを確認してくださいfirebase-tools グローバルにインストール
    npm install -g firebase-tools
    
    今ログインする必要があります
    firebase login
    
    ファイアウォールプロジェクト
    firebase init
    
    ホスティングオプションを選択します.
    尋ねるpublic directory , 種類distときに1つのページのアプリを入力すると、' Y '
    種類N Github Automationビルドを要求する場合.
    種類N 上書きを求められた場合index.html . 我々は、我々のファイルを保ちたいです
    次に、ホスティングプロジェクトを選択すると、既存のいずれかを選択することができます既に作成したり、新しいものを作成します.
    プロジェクトの配備
    firebase deploy
    
    おめでとう!最初から最後までToDoアプリケーションを構築し、正常にアプリケーションを配備できます.