vue firebase_如何使用Vue.js,Vuex,Vuetify和Firebase構建SPA:使用Firebase添加身份驗證...

vue firebasejavascript

第4部分:瞭解如何使用Firebase添加身份驗證和購物車 (Part 4: learn how to use Firebase to add authentication and a cart)

Learn how to create a meal delivery website using Vue.js, Vuex, Vue Router, and Firebase.前端

瞭解如何使用Vue.js,Vuex,Vue Router和Firebase建立送餐網站。 vue

This is part four of my four-part series on building a Vue application. Here is a list of all the parts:java

這是我構建Vue應用程序的四部分系列的第四部分。 這是全部部分的列表: node

Part 1: Installing Vue and Building an SPA using Vuetify and Vue Routerios

第1部分:使用Vuetify和Vue路由器安裝Vue並構建SPA git

Part 2: Using Vue Routergithub

第2部分:使用Vue路由器 web

Part 3: Using Vuex and accessing APIvuex

第3部分:使用Vuex和訪問API

Part 4: Using Firebase for Authentication & Cart

第4部分:使用Firebase進行身份驗證和購物車

回顧 (Recap)

In the first part of this series, we created our Vue application using the Vue CLI. Also, we added Vuetify to the app. We used Vuetify to style our home page.

在本系列的第一部分中,咱們使用Vue CLI建立了Vue應用程序。 另外,咱們將Vuetify添加到了該應用程序中。 咱們使用Vuetify來設置主頁樣式。

In the second part, we used Vue Router to add navigation between the different pages of our app. We added components for all the pages in our application.

在第二部分中,咱們使用Vue Router在應用程序的不一樣頁面之間添加導航。 咱們爲應用程序中的全部頁面添加了組件。

In the third part, we were introduced to Vuex. We signed up for an API to provide recipes and used axios to retrieve them. This data was stored in the Vuex store which made it accessible to every component in the application.

在第三部分中,咱們介紹了Vuex。 咱們註冊了提供食譜的API,並使用axios來檢索它們。 此數據存儲在Vuex存儲中,這使得應用程序中的每一個組件均可以訪問。

什麼是Firebase? (What is Firebase?)

Firebase is a real-time cloud infrastructure for client-side apps. Firebase can turn any Frontend application into a full-stack product capable of scaling infinitely in the cloud. It abstracts away most of your complex server-side features like user authentication, data persistence, file storage, and microservices, so you can focus on building an awesome experience for the end user.

Firebase是用於客戶端應用程序的實時雲基礎架構。 Firebase能夠將任何前端應用程序變成可以在雲中無限擴展的全棧產品。 它抽象出了大多數複雜的服務器端功能,例如用戶身份驗證,數據持久性,文件存儲和微服務,所以您能夠專一於爲最終用戶構建出色的體驗。

The first step is to go to firebase and create a new account. Log in to the account that you created. You will see this dashboard:

第一步是轉到firebase並建立一個新賬戶 。 登陸到您建立的賬戶。 您將看到此儀表板:

Click the Add Project button. Enter a name for your project. I entered 「meal-prep」 for the name of my project. Check all checkboxes. Then click the create project button.

單擊Add Project按鈕。 輸入項目的名稱。 我爲項目名稱輸入了「進餐準備」。 選中全部複選框。 而後單擊create project按鈕。

Once your project is created, Firebase will take you to your project’s home page.

建立項目後,Firebase會將您帶到項目的主頁。

We need to integrate our project’s configuration into our meal-prep application. Click on the web button to add Firebase to your application. (NOTE: if you are not sure which button that is, it is the button with the <;/>. In the image above, the button is right above the words 「get started.」 Click the copy button to copy the snippet to your clipboard.

咱們須要將項目的配置集成到咱們的飯前準備應用程序中。 單擊Web按鈕將Firebase添加到您的應用程序。 (注意:若是不肯定是哪一個按鈕,則帶有< ; />的按鈕。在上圖中,該按鈕位於「入門」字樣的正上方。單擊複製按鈕,將代碼段複製到您的剪貼板。

Next, we need to incorporate this snippet into our meal prep application. You can initialize your firebase application in the main.js file. You can do it in the App.vue file.

接下來,咱們須要將此代碼段合併到咱們的餐食準備應用程序中。 您能夠在main.js文件中初始化main.js應用程序。 您能夠在App.vue文件中執行App.vue操做。

Instead, we are going to create a new directory called firebase in the src folder. Inside this new directory create a file called index.js. Paste the contents of your clipboard into this file. Remove the two lines with the script tags. In the first line of the file import firebase. On the last line initialize firebase. Your file should look like this:

相反,咱們將在src文件夾中建立一個名爲firebase的新目錄。 在這個新目錄中,建立一個名爲index.js的文件。 將剪貼板的內容粘貼到此文件中。 刪除帶有script標記的兩行。 在文件的第一行中導入firebase。 在最後一行初始化firebase。 您的文件應以下所示:

import firebase from 'firebase';const config = {    apiKey: "<youKeyHere>",    authDomain: "<youKeyHere>",    databaseURL: "<youKeyHere>",    projectId: "<youKeyHere>",    storageBucket: "<youKeyHere>",    messagingSenderId: "<youKeyHere>"};firebase.initializeApp(config);

We are importing firebase from an npm package that we have not installed yet. Let’s install it now. In your terminal, install firebase with this command:

咱們正在從還沒有安裝的npm軟件包中導入firebase。 如今安裝它。 在您的終端中,使用如下命令安裝firebase:

npm install firebase --save

Now that we have installed firebase and created a config file, we need to add this file to our application so Vue is aware of it. Open up the main.js file and import in the config file we created. Here is what my main.js file looks like:

如今,咱們已經安裝了firebase並建立了一個配置文件,咱們須要將此文件添加到咱們的應用程序中,以便Vue意識到這一點。 打開main.js文件,而後導入咱們建立的配置文件。 這是個人main.js文件的樣子:

import '@babel/polyfill';import Vue from 'vue';import './plugins/vuetify';import App from './App.vue';import router from './router';import store from './store';import '@/firebase/';Vue.config.productionTip = false;new Vue({    router,    store,    render: h => h(App)}).$mount('#app');

Go back to your firebase console in the browser. Click on Authentication. Click on the set up sign-in method button.

返回瀏覽器中的Firebase控制檯。 單擊Authentication 。 單擊set up sign-in method按鈕。

In the list of sign-in providers, click on Email/Password:

在登陸提供商列表中,單擊「電子郵件/密碼」:

Enable the option to all users to sign up using their email address and password. Then click the save button.

啓用全部用戶使用其電子郵件地址和密碼進行註冊的選項。 而後單擊save按鈕。

建立註冊表格 (Creating Sign Up Form)

In a previous post, we stubbed out the Join.vue and Signin.vue files. These two files will have almost the same code. We will create the Join form first. When we are finished we will copy/paste it into the Signin form.

在上一篇文章中,咱們對Join.vue和Signin.vue文件進行了存根處理。 這兩個文件將具備幾乎相同的代碼。 咱們將首先建立Join表單。 完成後,咱們會將其複製/粘貼到「登陸」表單中。

Open the Join.vue component. You can remove everything that is in the template. Vuetify has a default layout structure for components. It flows like this:

打開Join.vue組件。 您能夠刪除模板中的全部內容。 Vuetify具備組件的默認佈局結構。 它像這樣流動:

  • v-container

    V型容器
  • v-layout

    垂直佈局
  • v-flex

    彎曲

So let’s create that layout now in the component. The start of our file looks like this:

如今讓咱們在組件中建立該佈局。 咱們文件的開始看起來像這樣:

<template>    <v-container fill-height>        <v-layout align-center justify-center>            &lt;v-flex xs12 sm8 md4>            </v-flex>        </v-layout>    </v-container></template>

For the v-container we are adding fill-height. We add this so that it centers the form vertically in the window. For the v-flex we add xs12 sm8 and md4 values. This is similar to Bootstrap’s column width definition. On extra-small devices, the form will take up all 12 columns meaning the whole screen. On small devices, the form will be 3/4 of the screen wide. On medium and large screens the form will be 1/3 of the screen.

對於v-container咱們要添加fill-height 。 咱們添加它,使它在窗口中垂直居中。 對於v-flex咱們添加xs12 sm8md4值。 這相似於Bootstrap的列寬定義。 在超小型設備上,該表格將佔據所有12列,即整個屏幕。 在小型設備上,表格的寬度爲屏幕的3/4。 在中型和大型屏幕上,表單將是屏幕的1/3。

Inside the v-flex we are going to use a v-card. We add class=」elevation-12" to the v-card so that it appears to be floating above the page. For the top of the form, we will use a v-toolbar. We give it a color of primary. For the default installation of Vuetify the primary color is blue. We want the text in the toolbar to be white text instead of the default black. To turn the text white we add dark to the v-toolbar.

v-flex內部,咱們將使用v-card 。 咱們添加class=」elevation-12"v-card ,以便它彷佛是漂浮在網頁上面。對於形的頂部,咱們將使用一個v-toolbar ,咱們給它的顏色primary 。對於Vuetify的默認安裝是藍色,咱們但願工具欄中的文本是白色,而不是默認的黑色;要使文本變成白色,咱們要在v-toolbar添加dark

Next, we have a v-card-text. Inside of it, we have a v-form. For the form we are giving it a reference with the name of form. We are assigning it to the v-model with a value of valid.

接下來,咱們有一個v-card-text 。 在它裏面,咱們有一個v-form 。 對於表單,咱們給它提供一個名爲form的引用。 咱們將其分配給具備validv-model

The last thing we add is lazy-validation. Our form needs to capture the user’s email and password. We will use two v-text-field to capture these values. To make things look better I have prepended an icon for each field. Each field has a v-model and rules.

咱們添加的最後一件事是lazy-validation 。 咱們的表單須要捕獲用戶的電子郵件和密碼。 咱們將使用兩個v-text-field來捕獲這些值。 爲了使狀況看起來更好,我爲每一個字段添加了一個圖標。 每一個字段都有一個v-modelrules

Before the form is submitted the field will be validated against all rules that are defined. If they pass then you can submit the form. We will take advantage of this when the user clicks the Join button.

在提交表單以前,將根據定義的全部規則驗證該字段。 若是他們經過了,那麼您能夠提交表格。 當用戶單擊「加入」按鈕時,咱們將利用這一點。

The last item to add to the form is a button. We add a v-card-actions and add a button. Here is what the template looks like for our component:

要添加到表單的最後一項是按鈕。 咱們添加了v-card-actions並添加了一個按鈕。 這是咱們組件的模板的外觀:

<template>    <v-container fill-height>        <v-layout align-center justify-center>            &lt;v-flex xs12 sm8 md4>                <v-card class="elevation-12">                    <v-toolbar dark color="primary">                        <v-toolbar-title>Join Form</v-toolbar-title>                    </v-toolbar>                    <;v-card-text>                        <v-form ref="form" v-model="valid" lazy-validation>;                            &lt;v-text-field prepend-icon="person" name="email" label="Email" type="email"                                          v-model="email" :rules="emailRules" required>                            </v-text-field>                            <v-text-field prepend-icon="lock" name="password" label="Password" id="password"                                          type="password" required v-model="password" :rules="passwordRules">                            </v-text-field>                        </v-form>                    </v-card-text>                    <v-card-actions>                        <v-spacer></v-spacer>                        <v-btn color="primary" :disabled="!valid" @click="submit">Join</v-btn>                    </v-card-actions>                </v-card>            </v-flex>        </v-layout>    </v-container></template>

We defined several models in our template. We need to add them to the data section of our script. In the script add a data object. We will add valid, email, password, emailRules and passwordRules.

咱們在模板中定義了幾個模型。 咱們須要將它們添加到腳本的data部分。 在腳本中添加一個數據對象。 咱們將添加有效的,電子郵件,密碼,emailRules和passwordRules。

Email and password will contain the values the user inputs into the two text fields. Valid will tell if our form has passed all the rules we have created. For email, we check to make sure that the field is not empty. We also check that the contents match a basic RegExp to validate the email address. For password, we check to make sure the field is not empty. We also check to make sure the password is at least six characters in length.

電子郵件和密碼將包含用戶在兩個文本字段中輸入的值。 Valid將告訴咱們表單是否經過了咱們建立的全部規則。 對於電子郵件,咱們檢查以確保該字段不爲空。 咱們還檢查內容是否與基本RegExp匹配以驗證電子郵件地址。 對於密碼,咱們檢查以確保該字段不爲空。 咱們還會檢查以確保密碼長度至少爲六個字符。

Here is what the data object looks like now:

這是數據對象如今的樣子:

data() {    return {        valid: false,        email: '',        password: '',        emailRules: [            v => !!v || 'E-mail is required',            v => /.+@.+/.test(v) || 'E-mail must be valid'        ],        passwordRules: [            v => !!v || 'Password is required',            v =>                v.length >= 6 ||                'Password must be greater than 6 characters'        ]    };},

The last thing we need to add is methods. In methods, we have submit(). This method will validate our form first. If it passes validation then it will call an action in our Vuex store called userJoin. We pass it the email and password the user entered in the form.

咱們須要添加的最後一件事是方法。 在方法中,咱們有submit() 。 此方法將首先驗證咱們的表單。 若是經過驗證,它將在咱們的Vuex存儲中調用一個名爲userJoin 。 咱們向它傳遞用戶在表格中輸入的電子郵件和密碼。

Here is what the methods look like:

這些方法以下所示:

methods: {    submit() {        if (this.$refs.form.validate()) {            this.$store.dispatch('userJoin', {                email: this.email,                password: this.password            });        }    }}

在Vuex中建立userJoin操做 (Creating userJoin Action in Vuex)

Open up the store.js file. We will create a new action called userJoin. By default the first parameter passed to this action is context. I will use object destructuring to get just commit from context. Commit is how I will call my mutation.

打開store.js文件。 咱們將建立一個名爲userJoin的新操做。 默認狀況下,傳遞給該操做的第一個參數是context 。 我將使用對象分解來從context commit 。 承諾就是我所說的突變。

I will be using firebase to create the new user in the firebase database. To be able to use firebase in the store, I will need to import it. At the top of the file import firebase with this command:

我將使用firebase在firebase數據庫中建立新用戶。 爲了可以在商店中使用Firebase,我須要將其導入。 使用如下命令在文件頂部導入firebase:

import firebase from 'firebase';

Firebase authentication provides a method called createUserWithEmailAndPassword. We will pass the user’s email and password into this method. If it succeeds in registering the user it will return a user object. When it succeeds we will call two mutations: setUser and setIsAuthenticated. Here is what the action looks like:

Firebase身份驗證提供了一種名爲createUserWithEmailAndPassword的方法。 咱們會將用戶的電子郵件和密碼傳遞給此方法。 若是成功註冊用戶,它將返回一個用戶對象。 成功後,咱們將調用兩個突變: setUsersetIsAuthenticated 。 動做以下所示:

userJoin({ commit }, { email, password }) {    firebase        .auth()        .createUserWithEmailAndPassword(email, password)        .then(user => {            commit('setUser', user);            commit('setIsAuthenticated', true);        })        .catch(() => {            commit('setUser', null);            commit('setIsAuthenticated', false);        });}

This action calls two mutations. So let’s create then now. In mutations add a new mutation called setUser. Set the state value of user to the payload. Next, create a second mutation called setIsAuthenticated. Set the state value of isAuthenticated to the payload. Here is what the two mutations look like:

該動做稱爲兩個突變。 所以,讓咱們如今建立。 在突變中添加一個名爲setUser的新突變。 將用戶的狀態值設置爲有效負載。 接下來,建立另外一個名爲setIsAuthenticated突變。 將isAuthenticated的狀態值設置爲有效負載。 這是兩個突變的樣子:

setUser(state, payload) {    state.user = payload;},setIsAuthenticated(state, payload) {    state.isAuthenticated = payload;}

In state, we need to add two new value: user and isAuthenticated. Here is what state looks like now:

在狀態下,咱們須要添加兩個新值: userisAuthenticated 。 這是如今的狀態:

state: {    recipes: [],    apiUrl: 'https://api.edamam.com/search',    user: null,    isAuthenticated: false},

測試添加新用戶 (Test Adding a New User)

Start your server with the command npm run serve. Click on the Join button in the navigation. Enter your email and a password and click the join button. When you click the button nothing visible happens. To verify that the user was registered, go the firebase console in your browser. Click on Authentication. You should see a list of users that have been registered for your application. Here you can see that the user I just registered was created.

使用命令npm run serve啓動服務器。 單擊導航中的Join按鈕。 輸入您的電子郵件和密碼,而後單擊加入按鈕。 當您單擊按鈕時,看不見任何東西。 要驗證用戶是否已註冊,請在瀏覽器中進入firebase控制檯。 單擊Authentication 。 您應該看到已爲您的應用程序註冊的用戶列表。 在這裏您能夠看到我剛剛註冊的用戶已建立。

We need to notify the user that they have been successfully created. We will do this but later. First, we are going to copy and paste the contents of the Join.vue component into the Signin.vue component. There are only two changes you will need to make in the template. Change the title to 「Login Form.」 For the button make the text say 「Login.」 In the submit method have it dispatch to userLogin. Just to make sure you have it correct, here is what my entire Signin.vue file looks like:

咱們須要通知用戶它們已經成功建立。 咱們會這樣作,但稍後。 首先,咱們將複製Join.vue組件的內容並將其粘貼到Signin.vue組件中。 您只需在模板中進行兩項更改。 將標題更改成「登陸表單」。 對於按鈕,使文本說「登陸」。 在userLogin方法中將其調度到userLogin 。 爲了確保您設置正確無誤,這是我整個Signin.vue文件的外觀:

<template>    <v-container fill-height>        <v-layout align-center justify-center>            &lt;v-flex xs12 sm8 md4>                <v-card class="elevation-12">                    <v-toolbar dark color="primary">                        <v-toolbar-title>Login Form</v-toolbar-title>                    </v-toolbar>                    <;v-card-text>                        <v-form ref="form" v-model="valid" lazy-validation>;                            &lt;v-text-field prepend-icon="person" name="email" label="Email" type="email"                                          v-model="email" :rules="emailRules" required>                            </v-text-field>                            <v-text-field prepend-icon="lock" name="password" label="Password" id="password"                                          type="password" required v-model="password" :rules="passwordRules">                            </v-text-field>                        </v-form>                    </v-card-text>                    <v-card-actions>                        <v-spacer></v-spacer>                        <v-btn color="primary" :disabled="!valid" @click="submit">Login</v-btn>                    </v-card-actions>                </v-card&gt;            </v-flex&gt;        </v-layout>    </v-container></template><script>export default {    name: 'Signin',    data() {        return {            valid: false,            email: '',            password: '',            emailRules: [                v => !!v || 'E-mail is required',                v => /.+@.+/.test(v) || 'E-mail must be valid'            ],            passwordRules: [                v => !!v || 'Password is required',                v =&gt;                    v.length >= 6 ||                    'Password must be greater than 6 characters'            ]        };    },    methods: {        submit() {            if (this.$refs.form.validate()) {                this.$store.dispatch('userLogin', {                    email: this.email,                    password: this.password                });            }        }    }};</script><style scoped></style>

That’s it. You have now created both the Join and Login forms.

而已。 如今,您已經建立了「加入」和「登陸」表單。

We need to create the action for Login. Open up the store.js file. Create a new action called userLogin. We will use firebase to login the user. Firebase provides a method called signInWithEmailAndPassword. We will call this method and pass in the user’s email and password they entered into the form. If the user entered their email and password correctly then we will call the two mutations setUser and setIsAuthenticated. Here is what the userLogin action looks like:

咱們須要爲登陸建立操做。 打開store.js文件。 建立一個名爲userLogin的新操做。 咱們將使用Firebase登陸用戶。 Firebase提供了一種名爲signInWithEmailAndPassword的方法。 咱們將調用此方法,並將用戶輸入的電子郵件和密碼輸入表單。 若是用戶正確輸入了他們的電子郵件和密碼,那麼咱們將調用兩個突變setUsersetIsAuthenticated 。 這是userLogin操做的樣子:

userLogin({ commit }, { email, password }) {    firebase        .auth()        .signInWithEmailAndPassword(email, password)        .then(user => {            commit('setUser', user);            commit('setIsAuthenticated', true);        })        .catch(() => {            commit('setUser', null);            commit('setIsAuthenticated', false);        });},

重定向到我的資料 (Redirecting to Profile)

When a user successfully registers or login, we want to redirect them to their profile. When we created our app initially the Vue CLI 3 it created two routes for us. Those routes were / and /about. Eventually, the profile will contain a list of all recipes that the user has ordered from the menu page. Remember the button we put at the bottom of every recipe? That button will add the recipe to the user’s profile and store it in the database in firebase.

用戶成功註冊或登陸後,咱們但願將他們重定向到其我的資料。 最初建立應用程序時,Vue CLI 3爲咱們建立了兩條路由。 這些路線是//about 。 最終,配置文件將包含用戶從menu頁面訂購的全部食譜的列表。 還記得咱們放在每一個食譜底部的按鈕嗎? 該按鈕會將配方添加到用戶的我的資料中,並將其存儲在firebase中的數據庫中。

To redirect the user to the profile we will first import router at the top of the store.js file. The router is imported with the command:

爲了將用戶重定向到配置文件,咱們將首先在store.js文件頂部導入路由器。 使用如下命令導入路由器:

import router from '@/router';

Next, in both actions we redirect the user to /about if they successfully register or login. You can do the redirection with this command:

接下來,在這兩個操做中,若是用戶成功註冊或登陸,咱們會將用戶重定向到/ about。 您可使用如下命令進行重定向:

router.push('/about');

If the user fails to register an account or login successfully we will redirect the user to the home page. (NOTE: in a perfect scenario we will provide some notice to the user why the registration or login failed). You can redirect them to the home page with this command:

若是用戶沒法註冊賬戶或沒法成功登陸,咱們會將用戶重定向到主頁。 (注意:在理想狀況下,咱們將向用戶提供一些註冊或登陸失敗的通知)。 您可使用如下命令將它們重定向到主頁:

router.push('/');

To test the redirection, start your server and click on the Login button. Enter the email and password you used when you created your user account. Click the Join button. If everything worked successfully you should be redirected to the About page.

要測試重定向,請啓動服務器,而後單擊「登陸」按鈕。 輸入建立用戶賬戶時使用的電子郵件和密碼。 單擊加入按鈕。 若是一切順利,則應將您重定向到「關於」頁面。

更新導航 (Updating the navigation)

The navigation has buttons for Sign In and Join. When a user successfully registers or login we would like to hide these two buttons. In their place, we want to show a Logout button.

導航中包含用於Sign InJoin按鈕。 用戶成功註冊或登陸後,咱們想隱藏這兩個按鈕。 在他們的位置,咱們要顯示一個Logout按鈕。

Open up the AppNavigation component. We are going to group the two current buttons in a div. We are going to remove the class to hide the buttons on small and extra-small devices. Instead, we will place this class on the div. We add a v-if to the div to only show if the user is currently not authenticated. Below the div we will add a new button for Logout. This new button will have a style of outline with a color of white. When you click on this button it will call the method logout. We add a v-else to this button to show when the user is authenticated.

打開AppNavigation組件。 咱們將在div中將兩個當前按鈕分組。 咱們將刪除該類以隱藏小型和超小型設備上的按鈕。 相反,咱們將把此類放在div上。 咱們在div中添加v-if以僅顯示當前未經過身份驗證的用戶。 在div下面,咱們將爲註銷添加一個新按鈕。 此新按鈕將具備白色的輪廓樣式。 當您單擊此按鈕時,它將調用方法logout 。 咱們在此按鈕上添加了v-else,以顯示用戶經過身份驗證的時間。

Next, add a method called logout. This method will call an action in our store called userSignOut.

接下來,添加一個名爲logout的方法。 此方法將調用咱們商店中名爲userSignOut

We also need to add a new computed property called isAuthenticated. This property returns the value of isAuthenticated in the state of our store.

咱們還須要添加一個稱爲isAuthenticated的新計算屬性。 此屬性返回商店狀態中isAuthenticated的值。

Here is what your AppNavigation should look like:

這是您的AppNavigation外觀:

<template>    <span>        <v-navigation-drawer app v-model="drawer" class="brown lighten-2" dark disable-resize-watcher>            <v-list>                <template v-for="(item, index) in items">                    <v-list-tile :key="index">                        <v-list-tile-content>                            {
   
   
   

  {item.title}}                        </v-list-tile-content>                    <;/v-list-tile>                    <v-divider :key="`divider-${index}`"></v-divider>                </template>            </v-list>        </v-navigation-drawer>        <v-toolbar app color="brown darken-4" dark>            <v-toolbar-side-icon class="hidden-md-and-up" @click="drawer = !drawer"></v-toolbar-side-icon>            <v-spacer class="hidden-md-and-up"></v-spacer>            <router-link to="/"&gt;                <v-toolbar-title to="/">{
   
   
   

  {appTitle}}</v-toolbar-title>;            </router-link>            <;v-btn flat class="hidden-sm-and-down" to="/menu">Menu</v-btn>            <v-spacer class="hidden-sm-and-down"></v-spacer>            <;div v-if="!isAuthenticated" class="hidden-sm-and-down">                <v-btn flat to="/sign-in">SIGN IN</v-btn>                <v-btn color="brown lighten-3" to="/join">JOIN</v-btn>            </div>            <v-btn v-else outline color="white" @click="logout">Logout</v-btn>        </v-toolbar>    </span></template><script>export default {    name: 'AppNavigation',    data() {        return {            appTitle: 'Meal Prep',            drawer: false,            items: [{ title: 'Menu' }, { title: 'Sign In' }, { title: 'Join' }]        };    },    computed: {        isAuthenticated() {            return this.$store.getters.isAuthenticated;        }    },    methods: {        logout() {            this.$store.dispatch('userSignOut');        }    }};</script><style scoped>a {    color: white;    text-decoration: none;}</style>

We need to add the getter and action we just defined. Open up the store.js file. Create a new action called userSignout. This action will use firebase.auth() to sign the user out. After signing the user out, it sets the state variables user to null and isAuthenticated to false. Here is the userSignout method in the store:

咱們須要添加剛剛定義的吸氣劑和動做。 打開store.js文件。 建立一個名爲userSignout的新操做。 此操做將使用firebase.auth()將用戶註銷。 將用戶註銷後,它將狀態變量user爲null,並將isAuthenticated爲false。 這是商店中的userSignout方法:

userSignOut({ commit }) {    firebase        .auth()        .signOut()        .then(() => {            commit('setUser', null);            commit('setIsAuthenticated', false);            router.push('/');        })        .catch(() => {            commit('setUser', null);            commit('setIsAuthenticated', false);            router.push('/');        });}

Next, we need to add a getters section to the store object. The isAuthenticated getters method will return true or false based on user authentication. Here is what the getters section of the store looks like:

接下來,咱們須要向商店對象添加一個getters部分。 isAuthenticated getters方法將根據用戶身份驗證返回true或false。 這是商店的getters部分的樣子:

getters: {    isAuthenticated(state) {        return state.user !== null && state.user !== undefined;    }}

將配方添加到數據庫 (Adding Recipes to Database)

Once a user is logged in they can click on any recipe to add it to their account. Their recipes will be shown in their profile which is the /about route. We need a database to store these recipes. Go to your firebase console in the browser. Click on database in the left side navigation panel. On the next screen you will see buttons to create a realtime database or a cloud firestore database. Make sure you create a new realtime database. In the dialog make sure you select to start in test mode. Then click the enable button.

用戶登陸後,能夠單擊任何配方將其添加到他們的賬戶中。 他們的食譜將顯示在其我的資料(即/about路線)中。 咱們須要一個數據庫來存儲這些食譜。 在瀏覽器中轉到您的Firebase控制檯。 在左側導航面板中單擊database 。 在下一個屏幕上,您將看到用於建立實時數據庫或Cloud Firestore數據庫的按鈕。 確保建立一個新的實時數據庫。 在對話框中,確保您選擇以start in test mode 。 而後單擊enable按鈕。

Now we want to store the user’s recipes in the database. Open up the MealRecipes component. If a user tries to order a recipe and they are not logged in then we should redirect them to the login page. So let’s take care of that now. On the Order button add an @click that calls the method orderRecipe. Be sure to pass in item as an argument to the method. Your button should look like this:

如今,咱們要將用戶的配方存儲在數據庫中。 打開MealRecipes組件。 若是用戶嘗試訂購食譜而他們還沒有登陸,則咱們應將其重定向到登陸頁面。 所以,讓咱們如今來照顧它。 在「 Order按鈕上,添加一個@click,調用方法orderRecipe。 確保將item做爲方法的參數傳遞。 您的按鈕應以下所示:

<v-card-actions>    &lt;v-btn color="green" dark @click="orderRecipe(item)">Order</v-btn></v-card-actions>

Before we create our method, we will create a computed value for isAuthenticated. This is the exact same code we used in AppNavigation earlier to show and hide the login and logout button correctly. Add a computed isAuthenticated. It should look like this:

在建立方法以前,咱們將爲isAuthenticated建立一個計算值。 這與咱們以前在AppNavigation使用的代碼AppNavigation ,能夠正確顯示和隱藏登陸和註銷按鈕。 添加計算的isAuthenticated。 它看起來應該像這樣:

export default {    name: 'MealRecipes',    computed: {        recipes() {            return this.$store.state.recipes;        },        isAuthenticated() {            return this.$store.getters.isAuthenticated;        }    }};

Now we are ready to create our orderRecipe method. Add this method and its parameter. In this method, we want to first check if the user is logged in or not. If they are not we want to redirect them to /sign-in . If they are signed in then we want to call an action in the Vuex store that will append the recipe to the user account in the database. Here is what our method looks like:

如今咱們準備建立orderRecipe方法。 添加此方法及其參數。 在這種方法中,咱們要首先檢查用戶是否已登陸。 若是不是,咱們但願將其重定向到/sign-in 。 若是他們已登陸,則咱們要在Vuex存儲中調用一個操做,該操做會將配方追加到數據庫中的用戶賬戶。 這是咱們的方法:

methods: {    orderRecipe(item) {        if (this.isAuthenticated) {            this.$store.dispatch('addRecipe', item);        } else {            this.$router.push('/sign-in');        }    }}

Open up the store.js file. We need to create a new action to add recipes. In this action, we are going to use firebase to add the recipe to a database called users. When the user was registered in firebase they were assigned a unique userid. We will be using this uid to store the name of the recipe in the database.

打開store.js文件。 咱們須要建立一個新操做來添加配方。 在此操做中,咱們將使用firebase將配方添加到名爲users的數據庫中。 在Firebase中註冊用戶後,會爲其分配一個惟一的用戶ID。 咱們將使用該uid將配方名稱存儲在數據庫中。

In this action, we will be using state to get the value of the currently selected user. The user in state is an object. That object has a key called user. In that object, we will find the uid. We use that to push the title of the selected recipe into the database. Here is the action:

在此操做中,咱們將使用state來獲取當前所選用戶的值。 處於stateuser是一個對象。 該對象具備一個稱爲用戶的密鑰。 在該對象中,咱們將找到uid 。 咱們用它來將所選配方的標題推送到數據庫中。 這是動做:

addRecipe({ state }, payload) {    firebase        .database()        .ref('users')        .child(state.user.user.uid)        .push(payload.recipe.label);}

Now start your server and log in. Select a diet from the menu page. Then order a couple of recipes. The recipes you ordered should be shown in the database in firebase.

如今啓動服務器並登陸。從菜單頁面選擇一種飲食。 而後點幾個食譜。 您訂購的食譜應顯示在firebase的數據庫中。

Now that we have the recipes added to the database, we actually need to display them on the profile page for the user. Open up the About.vue file. Whenever this page is loaded it should fetch all the user’s recipes. To do this we add mounted() in our script. This will call a method called getRecipes.

如今咱們已經將配方添加到數據庫中,實際上,咱們須要在用戶的我的資料頁面上顯示它們。 打開About.vue文件。 每當加載此頁面時,它都應獲取全部用戶的食譜。 爲此,咱們在腳本中添加mounted() 。 這將調用一個名爲getRecipes的方法。

Let’s create that method now. In the method, we are going to call an action in our Vuex store that will get all the user’s recipes. We have not created this action in the store yet but in simple terms, this action will get the user’s recipes. Then it will store them in a variable in state called userRecipes.

如今建立該方法。 在該方法中,咱們將在Vuex存儲中調用一個操做,該操做將獲取全部用戶的食譜。 咱們還沒有在商店中建立此操做,但簡單來講,此操做將獲取用戶的食譜。 而後它將它們存儲在stateuserRecipes的變量中。

Before we leave About.vue, add a computed property for userRecipes. This will return the userRecipes from state in our store. This is what About.vue script should look like:

在離開About.vue以前,爲userRecipes添加一個計算屬性。 這將從咱們商店的state返回userRecipes 。 這是About.vue腳本應以下所示:

export default {    name: 'About',    computed: {        userRecipes() {            return this.$store.state.userRecipes;        }    },    mounted() {        this.getRecipes();    },    methods: {        getRecipes() {            this.$store.dispatch('getUserRecipes');        }    }};

Next, open up your store.js file. We need to create the getUserRecipes action. When the user logins we store a variable in state called user. This variable will have the unique user ID assigned to that user when it was registered in firebase. We want to get all the recipes in the users database that have this user ID. Once we get all the recipes we want to set userRecipes to contain them. Here is the getUserRecipes action:

接下來,打開store.js文件。 咱們須要建立getUserRecipes操做。 當用戶登陸時,咱們會存儲一個state爲user的變量。 在Firebase中註冊時,此變量將具備分配給該用戶的惟一用戶ID。 咱們但願在用戶數據庫中得到具備該用戶ID的全部配方。 一旦得到全部配方,咱們便但願將userRecipes設置爲包含它們。 這是getUserRecipes操做:

getUserRecipes({ state, commit }) {    return firebase        .database()        .ref('users/' + state.user.user.uid)        .once('value', snapshot => {            commit('setUserRecipes', snapshot.val());        });}

In our mutations, we need to add a setUserRecipes. It looks like this:

在咱們的變異中,咱們須要添加一個setUserRecipes 。 看起來像這樣:

setUserRecipes(state, payload) {    state.userRecipes = payload;}

We also need to add a userRecipes in state. We set its initial value to an empty array. Here is my entire state object:

咱們還須要在state添加一個userRecipes 。 咱們將其初始值設置爲一個空數組。 這是個人整個狀態對象:

state: {    recipes: [],    apiUrl: 'https://api.edamam.com/search',    user: null,    isAuthenticated: false,    userRecipes: []},

Now that we are getting the recipes we need to display them on the page to the user. So go back to your About.vue file. In the template, we are going to loop through all the user’s recipes and display them. I am going to show you my code for the template first then explain what I have done:

如今咱們已經得到了食譜,咱們須要將其顯示在頁面上給用戶。 所以,請返回您的About.vue文件。 在模板中,咱們將遍歷全部用戶的食譜並顯示它們。 我將首先向您展現個人模板代碼,而後說明我作了什麼:

<template>    <v-container >        <v-layout column>;            <h1 class="title my-3">My Recipes</h1>            <div v-for="(item, idx) in userRecipes" class="subheading mb-2" :key="idx">                {
   
   
   

  {item}}            </div>        </v-layout>    </v-container></template>

I have set the layout to be column. I did this because I want each recipe to be listed on the page. To make things look clearer I have added a title. I added my-3 to add margin-top and margin-bottom so that there is spacing between the title and the list of recipes. Next, I looped through each recipe and display it. This is what the user sees if they have recipes:

我將佈局設置爲column 。 我這樣作是由於我但願每一個食譜都在頁面上列出。 爲了使事情看起來更清楚,我添加了一個標題。 我添加了my-3,以在頁邊距的頂部和頁邊距的底部添加空白,以便在標題和配方列表之間留有間隔。 接下來,我遍歷每一個食譜並顯示它。 這是用戶看到的是否有食譜的信息:

This is great, but when if a user logs in and they do not have any recipes? They see the title 「My Recipes」 and a blank page. This is not a user-friendly design. So let’s change it to display something more friendly.

很好,可是若是用戶登陸而且他們沒有任何食譜,該怎麼辦? 他們看到標題「個人食譜」和空白頁。 這不是用戶友好的設計。 所以,讓咱們對其進行更改以顯示更友好的內容。

We will display a button that will take the user to the menu page. In our template, we will add this button. To make the button redirect to the menu page we can add to=」/menu」 to the button. Here is my final template for the About.vue component.

咱們將顯示一個按鈕,該按鈕會將用戶帶到menu頁面。 在咱們的模板中,咱們將添加此按鈕。 爲了使按鈕重定向到菜單頁面,咱們能夠在按鈕上添加to=」/menu」 。 這是About.vue組件的最終模板。

<template>    <v-container >        <v-layout column>;            <h1 class="title my-3">My Recipes</h1>            <div v-for="(item, idx) in userRecipes" class="subheading mb-2" :key="idx">                {
   
   
   

  {item}}            </div>            &lt;v-flex mt-4>                <v-btn color="primary" to="/menu">Go To Menu</v-btn>            </v-flex>        </v-layout>    </v-container></template>

在導航中顯示我的資料 (Showing Profile in Navigation)

The last thing we need to add is the ability to show a link to the profile in the navigation. Just like the logout button, this should only be shown if the user is authenticated.

咱們須要添加的最後一件事是可以在導航中顯示指向配置文件的連接。 就像註銷按鈕同樣,僅在用戶經過身份驗證時才顯示。

Open up the AppNavigation components. We are going to group the profile button and the logout button in a div. This is the same thing we did earlier for the Sign In and Join buttons. Add a div and move the logout button to be inside this div. Add another button for profile. This button will be flat just like the Sign In button.

打開AppNavigation組件。 咱們將在div中將配置文件按鈕和註銷按鈕分組。 這與咱們以前對「 Sign In和「 Join按鈕所作的操做相同。 添加一個div並將註銷按鈕移到該div內。 爲profile添加另外一個按鈕。 該按鈕將與「 Sign In按鈕同樣平坦。

Here is what my AppNavigation looks like now:

這是我如今的AppNavigation外觀:

<template>    <span>        <v-navigation-drawer app v-model="drawer" class="brown lighten-2" dark disable-resize-watcher>            <v-list>                <template v-for="(item, index) in items">                    <v-list-tile :key="index">                        <v-list-tile-content>                            {
   
   
   

  {item.title}}                        </v-list-tile-content>                    <;/v-list-tile>                    <v-divider :key="`divider-${index}`"></v-divider>                </template>            </v-list>        </v-navigation-drawer>        <v-toolbar app color="brown darken-4" dark>            <v-toolbar-side-icon class="hidden-md-and-up" @click="drawer = !drawer"></v-toolbar-side-icon>            <v-spacer class="hidden-md-and-up"></v-spacer>            <router-link to="/"&gt;                <v-toolbar-title to="/">{
   
   
   

  {appTitle}}</v-toolbar-title>;            </router-link>            <;v-btn flat class="hidden-sm-and-down" to="/menu">Menu</v-btn>            <v-spacer class="hidden-sm-and-down"></v-spacer>            <;div v-if="!isAuthenticated" class="hidden-sm-and-down"&gt;                <v-btn flat to="/sign-in">SIGN IN</v-btn>                <v-btn color="brown lighten-3" to="/join">JOIN</v-btn>            </div>            <div v-else>                <v-btn flat to="/about">PROFILE</v-btn>                <v-btn outline color="white" @click="logout">Logout</v-btn>            </div>        </v-toolbar>    </span></template>

添加路線守衛 (Adding Route Guards)

Currently, the user can navigate to the profile page by typing it into the URL of the browser We don’t want to let users do this if they are not logged in. Vue Router provides the ability to add route guards before navigating to a URL. We want to test if a user is authenticated before allowing them to redirect to the /about page.

當前,用戶能夠經過在瀏覽器的URL中鍵入我的資料頁面來導航到我的資料頁面。若是用戶未登陸,咱們不想讓他們這樣作。VueRouter提供了在導航到URL以前添加路由保護的功能。 。 咱們要在容許用戶重定向到/about頁面以前測試用戶是否已經過身份驗證。

Open up the router.js file. Route guards work in conjunction with meta tags. Find the /about route. We will add a authRequired meta tag to it. The route should look like this:

打開router.js文件。 路由衛士與元標記結合使用。 找到/about路線。 咱們將向其添加一個authRequired元標記。 路線應以下所示:

{    path: '/about',    name: 'about',    component: () =&gt; import('./views/About.vue'),    meta: {        authRequired: true    }},

Route guards are checked in a method called beforeEach that is part of Vue Router. This method is passed three parameters:

路由保護是經過Vue路由器中稱爲beforeEach的方法進行檢查的。 此方法傳遞了三個參數:

  • the route you are going to

    你要去的路線
  • the route you came from

    您來自的路線
  • a next method that continues with the current route

    下一條繼續當前路線的方法

Our beforeEach method will check every route that we are going to to see if it contains the meta tag of authRequired. If it does, it will check to see if the user is Authenticated. If the user is not authenticated it will redirect them to the /sign-in page. If the user is logged in then it will allow the route to proceed. If a user routes to any page that does not have the authRequired meta tag then the route will proceed.

咱們的beforeEach方法將檢查咱們將要查看的每條路由,看看它是否包含authRequired的元標記。 若是是這樣,它將檢查用戶是否已經過身份驗證。 若是用戶未經過身份驗證,它將把他們重定向到/sign-in頁面。 若是用戶已登陸,則它將容許路由繼續進行。 若是用戶路由到沒有authRequired元標記的任何頁面,則路由將繼續。

Here is the method I have added to my router to do this checking:

這是我添加到路由器中以執行此檢查的方法:

router.beforeEach((to, from, next) => {    if (to.matched.some(record => record.meta.authRequired)) {        if (!store.state.user) {            next({                path: '/sign-in'            });        } else {            next();        }    } else {        next();    }});

獲取代碼 (Get the Code)

Even though this is a 4-part series, you can get the finished code in my GitHub account. Please help me out and star the repo when you get the code.

即便這是一個四部分的系列,您也能夠在個人GitHub賬戶中得到完成的代碼。 獲取代碼後,請幫助我,並給存儲庫加註星標

摘要 (Summary)

In this part of this series, you have learned:

在本系列的這一部分中,您瞭解了:

  • What is firebase

    什麼是firebase
  • Using firebase to authenticate users who sign in with email and password

    使用Firebase對使用電子郵件和密碼登陸的用戶進行身份驗證
  • Using firebase to store the recipes a user has ordered

    使用Firebase存儲用戶訂購的食譜
  • Using route guards to not users access pages if they are not authenticated

    若是用戶未經過身份驗證,則使用路由防禦不讓用戶訪問頁面
  • Display user’s list of recipes from the database on firebase

    從Firebase上的數據庫中顯示用戶的配方列表

If you enjoyed this article please clap for it. If you think somebody else would benefit from this article please share it with them.

若是您喜歡這篇文章,請爲它鼓掌。 若是您認爲其餘人將從本文中受益,請與他們分享。

If you have any questions or find anything wrong with the code, please leave a comment. If there are other topics you would like for me to write about, please leave a comment.

若是您有任何疑問或代碼有任何問題,請發表評論。 若是您但願我撰寫其餘主題,請發表評論。

Here are other articles I have written that you might want to read.

這是我寫過的其餘文章,您可能想閱讀。

How to add Internationalization to a Vue Application¡Hola! Bonjour. Ciao. 你好. Here is how you add internationalization to Vue.medium.freecodecamp.orgInstantiation Patterns in JavaScriptInstantiation patterns are ways to create something in JavaScript. JavaScript provides four different methods to create…medium.comHere are 5 Layouts That You Can Make With FlexBoxThe CSS Flexible Box Layout — Flexbox — provides a simple solution to the design and layout problems designers and…hackernoon.com

如何將國際化添加到Vue應用程序中 ¡ 你好。 再見。 你好。 這是將國際化添加到Vue的方法。 medium.freecodecamp.org JavaScript中的 實例 化模式 實例化模式是在JavaScript中建立內容的方法。 JavaScript提供了四種建立方法…… medium.com 您可使用FlexBox進行5種佈局 CSS FlexBox佈局(Flexbox)爲設計人員和設計師提供了一種解決設計和佈局問題的簡單解決方案 。hackernoon.com

Follow Me On Twitter!

在推特上關注我!

翻譯自: https://www.freecodecamp.org/news/how-to-build-a-spa-using-vue-js-vuex-vuetify-and-firebase-adding-authentication-with-firebase-d9932d1e4365/

vue firebase