博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
firebase vue_使用Vue和Firebase,Pt 3构建Google Keep Clone
阅读量:2510 次
发布时间:2019-05-11

本文共 30326 字,大约阅读时间需要 101 分钟。

firebase vue

In the we added the missing Update and Delete functionality, as well as refactoring our code to be more DRY. In this final part we are going to integrate the Vue-router to route between our authentication-page and our notes-page. As we add the ability to sign up and sign in, we are also going to introduce some Firebase security rules. With the security rules in place we’ll make sure that everyone’s notes are separate and private .We'll also add a way to search through the notes. The application will look like this at the end of this part.

在我们添加了缺少的“ 更新删除”功能,并将代码重构为更干的形式。 在最后一部分中,我们将集成Vue-router以在我们的身份验证页面和便笺页面之间路由。 随着我们增加了注册和登录的功能,我们还将引入一些Firebase安全规则。 有了适当的安全规则,我们将确保每个人的注释都独立且私密。我们还将添加一种搜索注释的方式。 本部分末尾的应用程序将如下所示。

Result of part 3

But before all that, let's create something to give more feedback to the user.

但是在此之前,让我们创建一些东西来向用户提供更多反馈。

( )

This component will accept an array of alerts through the alerts-property and visualize them at the top of the screen. Every alert consists out of a type (success, error, ...) which will be visualized by a different color, and the actual message.

该组件将通过警报属​​性接受一系列警报,并将其可视化在屏幕顶部。 每个警报都由一种类型 (成功,错误等)组成,该类型将以不同的颜色以及实际的消息显示

Create the Alerts-component at src/components/Alerts.vue. Tell the component to accept a alerts-property and iterate over the alerts in the template. By binding the type to the class, you can dynamically set the class. Depending on the class you can change the background color of the alert.

src/components/Alerts.vue创建Alerts-component。 告诉组件接受警报属性并遍历模板中的警报。 通过将类型绑定到类,可以动态设置类。 根据类别,您可以更改警报的背景颜色。

src/components/Alerts.vue

src/components/Alerts.vue

Add an expand transition that will animate the alerts as they are created or removed. The animation is very simple. You can't hardcode the height since you don't know how tall the alerts will be beforehand, so this should be set to auto (the initial value). You also can't animate between auto and 0 to create an expanding/shrinking animation. So instead you can animate the max-height from a value that is certain to always be bigger than the height, and animate it to 0.

添加一个扩展过渡,以便在创建或删除警报时为其设置动画。 动画非常简单。 您无法对高度进行硬编码,因为您事先不知道警报的高度,因此应将其设置为auto(初始值)。 您也不能在“自动”和“ 0”之间进行动画处理以创建展开/收缩的动画。 因此,相反,您可以从一定总是大于高度的值对最大高度进行动画处理,并将其动画化为0。

Now in App-component, add an empty alerts-array to the data. Listen to the alert-event and push them onto the alerts-array. By default set a timeout of 1500ms to remove the alert. Import the Alerts-component and put it at the top of the template. Don't forget to bind the alerts in the viewmodel to the alerts-attribute.

现在在App组件中,向数据添加一个空的Alerts数组。 听警报事件并将其推送到警报阵列。 默认情况下,将超时设置为1500ms以删除警报。 导入Alerts组件并将其放在模板的顶部。 不要忘记将视图模型中的警报绑定到alert-attribute。

src/App.vue

src/App.vue

Now you have created a very reusable way to give feedback about operations to the user. There are actually quite a few instances where we should do this. Currently, you are throwing the exceptions instead of handling them in the callbacks of create, update, and delete. Replace those throws by firing an alert-event up the parent-chain. Optionally, you can also let the user know if the operation was successful, though they already get direct feedback by seeing the notes being created, updated, or deleted.

现在,您已经创建了一种非常可重用的方式来向用户提供有关操作的反馈。 实际上,在很多情况下,我们应该这样做。 当前,您将引发异常,而不是在create,update和delete的回调中处理它们。 通过在父链上触发警报事件来替换那些抛出。 您也可以选择让用户知道操作是否成功,尽管他们已经通过查看正在创建,更新或删除的注释获得了直接反馈。

src/components/Create.vue

src/components/Create.vue

...export default {
... methods: {
createNote () {
if (this.title.trim() || this.content.trim()) {
noteRepository.create({
title: this.title, content: this.content}, (err) => {
if (err) return this.$dispatch('alert', {
type: 'error', message: 'Failed to create note'}) this.title = '' this.content = '' this.$dispatch('alert', {
type: 'success', message: 'Note was successfully created'}) }) } } }}

src/components/Note.vue

src/components/Note.vue

...export default {
... methods: {
remove () {
noteRepository.remove(this.note, (err) => {
if (err) return this.$dispatch('alert', {
type: 'error', message: 'Failed to remove note'}) }) } }}

src/components/UpdateModal.vue

src/components/UpdateModal.vue

...export default {
... methods: {
remove () {
noteRepository.remove(this.note, (err) => {
if (err) return this.$dispatch('alert', {
type: 'error', message: 'Failed to remove note'}) this.dismissModal() }) }, update () {
noteRepository.update(this.note, (err) => {
if (err) return this.$dispatch('alert', {
type: 'error', message: 'Failed to update note'}) this.dismissModal() this.$dispatch('alert', {
type: 'success', message: 'Note was successfully updated'}) }) }, ... }}

Now to test out errors, you can simply revoke all write access in the Firebase rules. Go to the (legacy) console, click 'Security and Rules' and change the rules to the following.

现在要测试错误,您只需撤销Firebase规则中的所有写访问权限即可。 转到(旧版)控制台,单击“安全和规则”,然后将规则更改为以下内容。

{
"rules": {
".read": true, ".write": false }}

When you test out create, edit, and delete, the error-alerts should appear. These action might cause strange behavior because they are being performed optimistically. This means that when you perform an operation, it will locally be executed without waiting for Firebase to check if the operation was successful in the database. If the operation was unsuccessful, it will undo the action. When you delete a note, Firebase will call 'child_removed', but when it fails in the database it will call 'child_added' again to undo the local operation. Revert the rules to the original values when you're done testing out the alerts.

当您测试创建,编辑和删除时,错误提示应该出现。 这些动作可能会导致奇怪的行为,因为它们被乐观地执行。 这意味着执行操作时,将在本地执行该操作,而无需等待Firebase检查数据库中的操作是否成功。 如果操作失败,它将撤消该操作。 当您删除便笺时,Firebase会调用“ child_removed”,但是在数据库中失败时,它将再次调用“ child_added”以撤消本地操作。 测试完警报后,将规则恢复为原始值。

Now you have a simple reusable way to give feedback to the user. This will come in handy in the login/signup form.

现在,您可以使用一种简单的可重用方法来向用户提供反馈。 这将在登录/注册表单中派上用场。

( )

Until now, there wasn't a real need for routing, but to introduce the login/signup form which is a completely different "page," you'll need a way to route between different views/pages. The library makes it very easy to route between views, and even nested views. (My favourite aspect of the vue-router is how easy it is to integrate authentication with routes)

到目前为止,还没有真正的路由选择,但是要引入完全不同的“页面”登录/注册表单,您需要一种在不同的视图/页面之间进行路由的方法。 通过库,可以非常轻松地在视图之间甚至在嵌套视图之间进行路由。 (我最喜欢的vue-router方面是将身份验证与路由集成起来非常容易)

First, install the vue-router library.

首先,安装vue-router库。

npm install vue-router --save

Second, setup the router in main.js and add one route for the NotesPage that you'll need to make in a second. (when the list of routes gets long, it might be a better option to create a routes.js file that you load in main.js)

其次,在main.js中设置路由器,并为NotesPage添加一条路由,这将在一秒钟内完成。 (当路由列表很长时,创建在main.js中加载的route.js文件可能是一个更好的选择)

src/main.js

src/main.js

import Vue from 'vue'import VueRouter from 'vue-router'import App from './App'import NotesPage from './components/pages/Notes'Vue.use(VueRouter)let app = Vue.extend({
components: {
App }})let router = new VueRouter()router.map({
'/notes': {
name: 'notes', component: NotesPage }})router.alias({
'/': '/notes'})router.start(app, 'body')

The vue-router library will use the <router-view> element to inject the correct view in the app. Add the <router-view> element to src/App.vue and move all the Notes related code to a new component under src/components/pages/Notes.vue. Your files should look like this.

vue-router库将使用<router-view>元素在应用程序中注入正确的视图。 将<router-view>元素添加到src/App.vue并将所有与Notes相关的代码移动到src/components/pages/Notes.vue下的新组件。 您的文件应如下所示。

src/App.vue

src/App.vue

src/components/pages/Notes.vue

src/components/pages/Notes.vue

That should be all you need to do to get the router working. When you browse to '#!/ or '#!/notes' everything should be working as before. Though the router isn't really useful for only one page. Let's make the page for authorization!

那应该是使路由器工作所需要做的全部工作。 当您浏览到'#!/或'#!/ notes'时,所有内容都应该像以前一样工作。 尽管路由器并不是只对一页有用。 让我们进行授权页面!

( )

The authorization page will offer a form for the user to sign up or sign in. The user will be able to sign up with email + password or via any of the other third-party providers (Facebook, Google, etc.). The form will look like this (the yellow background is because of Chrome's autofill).

授权页面将为用户提供一个表格,用于注册或登录。用户将能够使用电子邮件+密码或通过任何其他第三方提供商(Facebook,Google等)进行注册。 表单看起来像这样(黄色背景是因为Chrome的自动填充功能)。

Auth form

For now, simply create a form that asks for an email and password without implementing any of the logic.

现在,只需创建一个要求输入电子邮件和密码的表单即可,而无需执行任何逻辑。

src/components/pages/Auth.vue

src/components/pages/Auth.vue

The confirm-password field and register submit button is only shown when 'wantsToSignUp' is true. So when the user clicks the register button, it will set it to true and a confirm password field shows up and the register button takes up the full width of the card.

仅当'wantsToSignUp'为true时,才会显示确认密码字段和注册提交按钮。 因此,当用户单击注册按钮时,它将设置为true,并显示确认密码字段,并且注册按钮占据了卡的整个宽度。

Now that you have a second page, you can bind it to a new route in main.js.

现在您有了第二页,可以将其绑定到main.js的新路由。

src/main.js

src/main.js

import Vue from 'vue'import VueRouter from 'vue-router'import App from './App'import NotesPage from './components/pages/Notes'import AuthPage from './components/pages/Auth'Vue.use(VueRouter)let app = Vue.extend({
components: {
App }})let router = new VueRouter()router.map({
'/notes': {
name: 'notes', component: NotesPage }, '/auth': {
name: 'auth', component: AuthPage }})router.alias({
'/': '/notes'})router.start(app, 'body')

Now you should be able to navigate between the #!/notes and #!/auth. Because the Notes-component (Index.vue) isn't always loaded immediately anymore, you'll have to update our code a little. In previous parts we assumed the NoteRepository would be constructed and used immediately. Due to the changes, the existing notes will not trigger the 'added'-event in Index.vue. Therefore you need to call attachFirebaseListeners in the ready-method of the Notes-component and remove it from the NoteRepository component. It should look like this.

现在您应该可以在#!/notes#!/auth之间导航。 由于Notes组件(Index.vue)不再总是立即加载,因此您必须稍微更新一下我们的代码。 在前面的部分中,我们假设NoteRepository将被立即构建和使用。 由于所做的更改,现有注释将不会在Index.vue中触发“添加”事件。 因此,您需要在Notes组件的就绪方法中调用attachFirebaseListeners并将其从NoteRepository组件中删除。 它应该看起来像这样。

src/data/NoteRepository.js

src/data/NoteRepository.js

class NoteRepository extends EventEmitter {
constructor () {
super() // firebase reference to the notes this.ref = new Firebase('https://
.firebaseio.com/notes') }}

src/components/notes/Index.vue

src/components/notes/Index.vue

...export default {
... ready () {
this.masonry = new Masonry(this.$els.notes, {
itemSelector: '.note', columnWidth: 240, gutter: 16, fitWidth: true }) noteRepository.on('added', (note) => {
this.notes.unshift(note) // add the note to the beginning of the array }) noteRepository.on('changed', ({
key, title, content}) => {
let note = noteRepository.find(this.notes, key) // get specific note from the notes in our VM by key note.title = title note.content = content }) noteRepository.on('removed', ({
key}) => {
let note = noteRepository.find(this.notes, key) // get specific note from the notes in our VM by key this.notes.$remove(note) // remove note from notes array }) noteRepository.attachFirebaseListeners() }}

Now everything should be working fine, even after coming from a different route. Next up is creating an Authentication module and wiring it up to the authentication page.

现在,即使来自其他路线,一切也应该正常工作。 下一步是创建一个身份验证模块,并将其连接到身份验证页面。

( )

Just like with the NotesRepository, it's a good idea to keep your Firebase code contained in a seperate module instead of directly interacting with Firebase inside your components. Create a module for Authentication under src/data/Auth.js. This module will be responsible for:

就像使用NotesRepository一样,最好将Firebase代码保留在单独的模块中,而不是直接与组件内部的Firebase交互。 在src/data/Auth.js下创建用于身份验证的模块。 该模块将负责:

  • offering callbacks to listen in to changes to the authenticated user

    提供回调以侦听已认证用户的更改
  • offering information about the authenticated user

    提供有关已认证用户的信息
  • logging in and registering with
    • Email + Password
    • Social provider like Facebook, Twitter, etc.

    登录并注册
    • 邮箱+密码
    • 社交提供者,例如Facebook,Twitter等。
  • logging users out

    注销用户

Fortunately, Firebase makes it really easy by handling all the hard work for you.

幸运的是,Firebase通过为您处理所有艰苦的工作使它变得非常容易。

src/data/Auth.js

src/data/Auth.js

import Firebase from 'firebase'export default {
ref: new Firebase('https://
.firebaseio.com/'), // calls callback when user signs in or out onAuth (authCallback) {
this.ref.onAuth(authCallback) }, // get's authenticated user getAuth () {
return this.ref.getAuth() }, signInWithPassword (credentials) {
return this.ref.authWithPassword(credentials) }, signUpWithPassword (credentials) {
return this.ref.createUser(credentials) // this will create a Firebase user for authentication, this is separate from our own user objects }, signInWithProvider (provider, callback) {
// provider => 'google', 'facebook', 'github', etc. this.ref.authWithOAuthPopup(provider, (error, authData) => {
if (error) {
if (error.code === 'TRANSPORT_UNAVAILABLE') {
// fall-back to browser redirects, and pick up the session // automatically when we come back to the origin page this.ref.authWithOAuthRedirect(provider, (error) => {
if (callback) callback(error, authData) }) } } else if (authData) {
if (callback) callback(null, authData) } }) }, signOut () {
this.ref.unauth() }}

Now wire it up to your Auth page. Bind the signInWithPassword() method to the signin-button and the signInWithPassword() method with the second register-button. In case of an error, you can simply pass on the error-message that Firebase provides to the alerts. If you need to internationalize your app, you can use the error-code to map to your own translated messages.

现在将其连接到您的“身份验证”页面。 将signInWithPassword()方法绑定到登录按钮,并将signInWithPassword()方法与第二个注册按钮绑定。 如果发生错误,您只需将Firebase提供给警报的错误消息传递给其他人。 如果您需要国际化您的应用程序,则可以使用错误代码映射到您自己的翻译消息。

src/components/pages/Auth.vue

src/components/pages/Auth.vue

To take advantage of the Email + Password authentication, you need to enable it in the Firebase console. Go to the 'Email & Password' section under 'Login & Auth', and there enable the checkbox. Now you should be able to register and login. When you register, you will see them populate in the Firebase console. You can also reset a user's password or even delete the user from the Firebase console.

要利用电子邮件+密码身份验证,您需要在Firebase控制台中启用它。 转到“登录和验证”下的“电子邮件和密码”部分,然后启用该复选框。 现在您应该可以注册和登录了。 注册时,您会在Firebase控制台中看到它们。 您还可以重设用户密码,甚至从Firebase控制台中删除该用户。

Email & Password Firebase console

When users are not authenticated, they should not be able to access the notes-page, but currently that's still possible. Let's take care of that. Set the auth: true to the notes-route in src/main.js . To enforce authentication, you can attach a callback that gets called before a route changes. Check if you're dealing with an authenticated route, if so, check if the user is authenticated. Redirect the user to the auth-page if he is not authenticated. Otherwise you can just call next to complete the routing change.

如果用户未通过身份验证,则他们应该不能访问notes-page,但是目前仍然可以进行。 让我们来照顾它。 将auth: true设置为src/main.js的notes-route。 要强制执行身份验证,您可以附加在路由更改之前调用的回调。 检查您是否正在处理经过身份验证的路由,如果是,请检查用户是否已通过身份验证。 如果用户未通过身份验证,则将其重定向到身份验证页面。 否则,您可以直接致电以完成路由更改。

src/main.js

src/main.js

...import Auth from './data/Auth'...router.map({
'/notes': {
name: 'notes', component: NotesPage, auth: true // this route requires the user to be signed in }, '/auth': {
name: 'auth', component: AuthPage }})router.alias({
'/': '/notes'})router.beforeEach((transition) => {
if (transition.to.auth && !Auth.getAuth()) {
transition.redirect('/auth') } else {
transition.next() }})...

When you browse to the notes-page without being authenticated, you will be redirected to the authentication-page. Now you can register and login. After you are logged in, you are automatically redirected to the notes-page!

当您浏览未经过身份验证的注释页面时,您将被重定向到身份验证页面。 现在您可以注册并登录。 登录后,您将自动重定向到notes-page!

第三方供应商 (Third party providers)

For every provider icon, you can just pass the provider name to signInWithProvider(). Though, to get these providers to work, you need to perform some extra actions in the Firebase console too. I'll go over how to do it with Twitter, but it's pretty similar for other providers. Visit the to learn more about how to implement the other providers.

对于每个提供程序图标,您只需将提供程序名称传递给signInWithProvider() 。 但是,要使这些提供程序正常工作,您还需要在Firebase控制台中执行一些额外的操作。 我将介绍如何使用Twitter进行操作,但对于其他提供商来说却非常相似。 访问以了解有关如何实施其他提供商的更多信息。

Go to the Twitter section under 'Login & Auth' in the Firebase console and enable the checkbox. There is a link provided on the side that will give you more information on how to get an api key and secret.

转到Firebase控制台中“登录和验证”下的Twitter部分,然后启用该复选框。 侧面提供了一个链接,该链接将为您提供有关如何获取api密钥和机密的更多信息。

Twitter provider

Go the and click the create application button. Give the application a name, description, and fill in your Firebase hosting link as website. The most important part is setting the callback url to the following url: https://auth.firebase.com/v2/<YOUR-FIREBASE-APP>/auth/twitter/callback.

转到 ,然后单击“创建应用程序”按钮。 给应用程序起一个名称,描述,并在网站上填写您的Firebase托管链接。 最重要的部分是将回调URL设置为以下URL: https://auth.firebase.com/v2/<YOUR-FIREBASE-APP>/auth/twitter/callback : https://auth.firebase.com/v2/<YOUR-FIREBASE-APP>/auth/twitter/callback YOUR-FIREBASE-APP>/ https://auth.firebase.com/v2/<YOUR-FIREBASE-APP>/auth/twitter/callback twitter/callback。

Once you created the app in Twitter, navigate to the 'Keys and access tokens'. There you will find your api key and secret.

在Twitter中创建应用程序后,导航至“键和访问令牌”。 在这里,您会找到自己的api密钥和机密。

Twitter app keys

After copying over the key and secret to the Firebase console, your users will be able to sign in using Twitter! Visit the to learn more about how to implement the other providers.

将密钥和机密复制到Firebase控制台后,您的用户将可以使用Twitter登录! 访问以了解有关如何实施其他提供商的更多信息。

Now the users can sign in and sign up with email and password, or sign in with Twitter! Awesome job! But how does the user logout, and see what account he logged in with? Let's build that header you saw earlier.

现在,用户可以登录并使用电子邮件和密码登录,或使用Twitter登录! 好工作! 但是,用户如何注销并查看他使用哪个帐户登录? 让我们构建您之前看到的标头。

( )

The header-bar will be responsible for 3 things:

标题栏将负责三件事:

  1. Providing some information about the authenticated user (name, email, picture)

    提供有关经过身份验证的用户的一些信息(姓名,电子邮件,图片)
  2. Giving the user a way to sign out of the app

    为用户提供一种退出应用程序的方法
  3. A generic search bar where other parts of the app can listen to. The notes-component will react to the search by filtering its’ notes.

    应用的其他部分可以收听的通用搜索栏。 notes组件将通过过滤其笔记来响应搜索。

Create a new component under src/components/HeaderBar.vue.

The reason that I'm calling this component HeaderBar instead of Header, is because <header> is an existing HTML5 element and we want to prevent collision between the two.
In the ready-method, check if the user is signed in and listen to any authentication changes.
Get the user info and for each provider, grab the provider specific information, and show it to the user on the right of the header. Luckily, Firebase is very consistent in the information it provides for each 3rd party provider. Rest assured, there is always a displayName and profileImageURL property.
Only the Password-provider doesn't have a displayName. In that case you can grab the email address instead. If the user uses Password authentication, then his Gravatar image will be used, but if he doesn't have a Gravatar, Firebase provides a default image.

src/components/HeaderBar.vue下创建一个新组件。

之所以将其称为HeaderBar而不是Header ,是因为<header>是现有HTML5元素,并且我们希望防止两者之间发生冲突。
在就绪方法中,检查用户是否已登录并收听任何身份验证更改。
获取用户信息,并获取每个提供者的信息,获取提供者的特定信息,然后在标题右侧将其显示给用户。 幸运的是,Firebase在为每个第三方提供商提供的信息中非常一致。 请放心,总会有displayNameprofileImageURL属性。
只有密码提供者没有displayName 。 在这种情况下,您可以改为获取电子邮件地址。 如果用户使用密码身份验证,则将使用其Gravatar图像,但是如果他没有Gravatar,则Firebase将提供默认图像。

Next to the users info, you can use another icon from FontAwesome to create a SignOut-button. Bind a method to this button and use Auth.signOut() method. Redirect the user back to the authentication page after that.

在用户信息旁边,您可以使用FontAwesome中的另一个图标来创建“退出”按钮。 将方法绑定到此按钮,然后使用Auth.signOut()方法。 之后,将用户重定向到身份验证页面。

Use an input for the searchbar and center it. Bind it to searchQuery and listen to any changes. When the query changes, fire an event upwards with the query. To prevent the event from being fired too often, you can use the debounce attribute. This is a Vue feature that will prevent the binding from updating on every keyup, but instead will wait to see if there's another change coming within the timespan you provide.

使用输入作为搜索栏并将其居中。 将其绑定到searchQuery并收听所有更改。 查询更改时,将向上触发查询事件。 为了防止事件触发得太频繁,可以使用debounce属性。 这是一个Vue功能,它将阻止绑定在每次键入时更新,但是将等待您提供的时间跨度内是否还有其他更改。

src/components/HeaderBar.vue

src/components/HeaderBar.vue

Now include the HeaderBar into src/App.vue and you should have a nice header when you are logged in. Also listen to the 'search'-event and propagate it downwards so the Notes-component can listen to it too.

现在将HeaderBar包含到src/App.vue并且在登录时应该有一个不错的标头。还要监听'search'事件并将其向下传播,以便Notes组件也可以监听它。

src/App.vue

src/App.vue

When the user receives an alert, it will show up on top of the header. Let's change the position of the alerts underneath the header.

当用户收到警报时,它将显示在标题的顶部。 让我们更改标题下方的警报位置。

src/components/Alerts.vue

src/components/Alerts.vue

.alerts{
position: fixed; top: 50px; left: 0; right: 0; z-index: 1;}

Now the alerts show up nicely underneath the header.

现在,警报可以很好地显示在标题下方。

Header-bar with alert

Lastly, listen to the 'search'-event in src/components/notes/Index.vue and bind it to a new data property searchQuery. For filtering you can take advantage of an amazing Vue feature (one of my favourite) called computed properties. Instead of normal property, with computed properties, you can write functions and still use them as properties inside the Vue instance. If you are using any variables from outside the function, Vue will detect any changes and recalculate your computed property automatically!

最后,听src/components/notes/Index.vue的“搜索”事件并将其绑定到新的数据属性searchQuery 。 为了进行过滤,您可以利用称为计算属性的惊人Vue功能(我最喜欢的功能之一)。 您可以编写函数并将其用作Vue实例内部的属性,而不是具有计算属性的常规属性。 如果您正在使用函数外部的任何变量,Vue将检测到任何更改并自动重新计算您的计算属性!

Create a computed property filteredNotes() and use the filter-function to filter through the notes. If the searchQuery is found in either the title or content, than that note should be part of the filteredNotes. If the query is just a simple string, all notes should be part of the filteredNotes. Now you can watch the filteredNotes and iterate over the filteredNotes in the template.

创建一个计算的属性filteredNotes()并使用filter函数过滤注释。 如果在标题或内容中找到了searchQuery,则该注释应成为filterNotes的一部分。 如果查询只是一个简单的字符串,则所有注释都应该是filteredNotes的一部分。 现在您可以观看filteredNotes并遍历模板中的filteredNotes。

src/components/notes/Index.vue

src/components/notes/Index.vue

If the user types into the searchbar, the notes will be filtered! Sweet!

Currently, every user still shares one set of notes, so let's head over the final part and secure those notes!

如果用户在搜索栏中键入内容,便笺将被过滤! 甜!

当前,每个用户仍共享一组笔记,因此让我们结束最后一部分并保护这些笔记吧!

( )

At the moment, every user can see everyone’s notes, but users should only see their own notes. So instead of sharing one big set of notes, update the NotesRepository to have a set of notes for every user. Every user will have it's own user object inside the users object, and inside the user object you can put the set of notes.

目前,每个用户都可以看到每个人的注释,但用户只能看到自己的注释。 因此,与其共享大量便笺,不如更新NotesRepository以为每个用户提供一组便笺。 每个用户都会在用户对象内部拥有自己的用户对象,并且可以在用户对象内部放置注释集。

Inside src/data/NoteRepository create a getter for the uid and a getter for the new notesRef that will dynamically return a reference to the currently authenticated user's notes. Next update the code to use the notesRef instead.

里面src/data/NoteRepository创建了一个getter uid和新的吸notesRef ,将动态返回到当前已验证用户的笔记参考。 接下来更新代码以改为使用notesRef。

src/data/NoteRepository.js

src/data/NoteRepository.js

import Firebase from 'firebase'import EventEmitter from 'events'// extend EventEmitter so user of NoteRepository can react to our own defined events (ex: noteRepository.on('added'))class NoteRepository extends EventEmitter {
get uid () {
return this.ref.getAuth().uid } get notesRef () {
return this.ref.child(`users/${
this.uid}/notes`) } constructor () {
super() // firebase reference to the notes this.ref = new Firebase('https://
.firebaseio.com') // will have same result as new Firebase('https://resplendent-heat-896.firebaseio.com/').child('notes') } // creates a note create ({
title = '', content = ''}, onComplete) {
this.notesRef.push({
title, content}, onComplete) } // updates a note update ({
key, title = '', content = ''}, onComplete) {
this.notesRef.child(key).update({
title, content}, onComplete) // key is used to find the child, a new note object is made without the key, to prevent key being inserted in Firebase // new Firebase(`https://
.firebaseio.com/notes/${key}`).update(...) } // removes a note remove ({
key}, onComplete) {
this.notesRef.child(key).remove(onComplete) } // attach listeners to Firebase attachFirebaseListeners () {
this.notesRef.on('child_added', this.onAdded, this) this.notesRef.on('child_removed', this.onRemoved, this) this.notesRef.on('child_changed', this.onChanged, this) } // dettach listeners from Firebase detachFirebaseListeners () {
this.notesRef.off('child_added', this.onAdded, this) this.notesRef.off('child_removed', this.onRemoved, this) this.notesRef.off('child_changed', this.onChanged, this) } onAdded (snapshot) {
// process data let note = this.snapshotToNote(snapshot) // propagate event outwards with note this.emit('added', note) } onRemoved (oldSnapshot) {
let note = this.snapshotToNote(oldSnapshot) this.emit('removed', note) } onChanged (snapshot) {
let note = this.snapshotToNote(snapshot) this.emit('changed', note) } // processes the snapshots to consistent note with key snapshotToNote (snapshot) {
// we will need the key often, so we always want to have the key included in the note let key = snapshot.key() let note = snapshot.val() note.key = key return note } // Finds the index of the note inside the array by looking for its key findIndex (notes, key) {
return notes.findIndex(note => note.key === key) } // Finds the note inside the array by looking for its key find (notes, key) {
return notes.find(note => note.key === key) }}export default new NoteRepository() // this instance will be shared across imports

Now this works great, but other users are still able to access the data of other users. Introduce a security rule that only the authenticated user can read and write from his own user object. Go to the 'Security & Rules' section in the Firebase console and write the following rules.

现在,这很好用,但是其他用户仍然可以访问其他用户的数据。 引入一个安全规则,只有经过身份验证的用户才能从其自己的用户对象读取和写入。 转到Firebase控制台中的“安全和规则”部分,并编写以下规则。

{
"rules": {
"users": {
"$uid": {
".read": "$uid === auth.uid", ".write": "$uid === auth.uid" } } }}

By prefixing the uid with a dollar sign, you can use '$uid' as a variable which will be set to the key of every user object. Then in the read, write rules, check if the uid of the accessing user matches the $uid, if so allow the operation. And that's all you need to do to secure the notes!

通过在uid前面加一个美元符号,可以将“ $ uid”用作变量,该变量将设置为每个用户对象的键。 然后在读写规则中,检查访问用户的uid是否与$ uid匹配,如果允许,则允许操作。 这就是保护笔记所需要做的全部!

( )

In this last part, we secured the app and provided multiple ways for user to authenticate to use the app. During the course of this series, we familiarized ourselves with the many features Vue and Firebase gives us. Firebase really did all the heavy lifting and provided us with a very easy to use api to authenticate the users!

在最后一部分中,我们保护了应用程序的安全,并提供了多种方式供用户进行身份验证以使用该应用程序。 在本系列课程的过程中,我们熟悉了Vue和Firebase为我们提供的许多功能。 Firebase确实完成了所有繁重的工作,并为我们提供了一个非常易于使用的api来对用户进行身份验证!

I hope the series was helpful and that you'll give both Vue and Firebase a try for your next project. Don't hesitate to let me know about it!

我希望该系列对您有所帮助,并且您将为下一个项目尝试一下Vue和Firebase。 不要犹豫,让我知道!

翻译自:

firebase vue

转载地址:http://jiywd.baihongyu.com/

你可能感兴趣的文章
Springboot上传文件出现MultipartException
查看>>
NHibernate错误:Could not compile the mapping document的解决
查看>>
关于vue的源码调试
查看>>
003.第一个动画:绘制直线
查看>>
K2BPM怎么让金融数据更有意义?
查看>>
史玉柱自述:我是如何带队伍的
查看>>
靶形数独【贪心+深搜】
查看>>
读大道至简第三章有感
查看>>
BeforeFieldInit的小叙
查看>>
TeamViewer的下载地址,低调低调
查看>>
005 线程ID和线程的优先级
查看>>
POJ 3067 Japan (树状数组 && 控制变量)
查看>>
python基础条件和循环
查看>>
an exciting trip
查看>>
【转】xmind8 破解激活教程
查看>>
Mysql用命令方式启动服务
查看>>
【贪心】codeforces A. Heidi and Library (easy)
查看>>
【leetcode】lower_bound
查看>>
跨站请求伪造(CSRF)
查看>>
EF Code First数据库映射规则及配置
查看>>