vue crud_使用Vue和Deepstream构建实时CRUD应用

vue crud

Vue is the JavaScript UI tool that parades itself as progressive because it is approachable so one can get started in just a day. On the other hand, it has every feature to cater for your front-end needs, making it versatile.

Vue是一种JavaScript UI工具,自称为渐进式工具,因为它易于接近,因此一天之内就可以入门。 另一方面,它具有满足您的前端需求的所有功能,使其用途广泛。

Realtime technologies are gradually taking a new shape; realtime servers now serve as an abstraction for handling realtime related tasks. deepstream is an open, free and blazingly fast realtime server that you can install on your machine.

实时技术正在逐渐形成新的形态。 实时服务器现在充当处理实时相关任务的抽象。 deepstream是一个开放 ,免费,快速的实时服务器,您可以将其安装在计算机上。

This article demonstrates who we can build realtime apps using deepstream and Vue as our front end tool. The image below is a GIF of what we are up to:

本文演示了谁可以使用Deepstream和Vue作为前端工具来构建实时应用程序。 下图是我们所做的GIF:

Before we get dirty with codes, let's have a reason to do so.

在弄清代码之前,让我们有理由这样做。

为什么选择Vue ( Why Vue )

Vue.js Homepage

Vue is so far, in my humble opinion, the simplest UI library out in the wild to get your hands dirty with. It is easy to get started and handles most of the tough concepts that come in mind when considering a UI library. These includes: data binding, server-side rendering, state management.

以我的拙见,到目前为止,Vue是最简单的UI库,它可以让您不费吹灰之力。 它很容易上手,并且可以处理考虑UI库时想到的大多数棘手概念。 其中包括:数据绑定,服务器端呈现,状态管理。

Vue acts on the complexity of the existing UI library and simplifies those complexities to make our lives less frustrating as software engineers. It also has been backed by one of our favorite backend tool, Laravel -- making integration straightforward. This of course does NOT mean you cannot integrate with any other backend platform.

Vue处理现有UI库的复杂性,并简化了这些复杂性,从而使我们的生活不再像软件工程师那样令人沮丧。 它还得到了我们最喜欢的后端工具之一Laravel的支持 -使集成变得简单。 当然,这并不意味着您不能与任何其他后端平台集成。

为什么要深入 ( Why deepstream )

deepstream Homepage

deepstream is a standalone server -- faster than most of the our realtime solutions -- that allows you to provision realtime server using persisted state as Data Sync, pub/sub pattern as events or request/response pattern as RPCs.

deepstream是一个独立服务器,比大多数实时解决方案要快 ,它使您可以使用持久状态(如数据同步),发布/订阅模式(如事件)或请求/响应模式(如RPC)来配置实时服务器。

With these varieties of options, you are assured that deepstream can integrate in whatever nature of app you are building. Including chats, realtime news updates, stock information, CRUD/CMS apps, data visualization, data monitoring, etc.

通过这些多样化的选择,可以确保Deepstream可以集成到您正在构建的任何应用程序性质中。 包括聊天,实时新闻更新,股票信息,CRUD / CMS应用程序,数据可视化,数据监视等。

设置Vue和Deepstream ( Setup Vue and deepstream )

Installing both Vue and deepstream is quite a straightforward process; few commands on your CLI and you're good to go.

安装Vue和Deepstream是一个非常简单的过程。 CLI上的几个命令就可以了。

deepstream can be installed on Linux, Windows, and OSX; it can also be installed using Docker and npm. For this article, we will download deepstream for our OS. Unzip the file and run the following command on the unzipped directory to start the server:

deepstream可以安装在Linux,Windows和OSX上; 也可以使用Docker和npm进行安装。 对于本文,我们将为我们的操作系统下载Deepstream 。 解压缩文件并在解压缩的目录上运行以下命令以启动服务器:

./deepstream

vue-cli is a CLI tool that makes scaffolding a Vue project easy and fast. We need to install this CLI tool then we can use the tool to create a new project for our demo app:

vue-cli是一个CLI工具,可轻松快速地搭建Vue项目。 我们需要安装此CLI工具,然后我们可以使用该工具为演示应用程序创建一个新项目:

npm install -g vue-cli

The CLI tool is installed globally so we can access it from anywhere in our machine. Vue project scaffolds come in different templates, we need something simple and the following command will do just that for us:

CLI工具已全局安装,因此我们可以从计算机上的任何位置访问它。 Vue项目支架有不同的模板,我们需要一些简单的东西,以下命令将为我们完成这些工作:

vue init webpack my-project

用Vue进行CRUD ( Just CRUD with Vue )

Before we attempt a realtime app, let's create a platform for that first. A CRUD (Create, Read Update and Delete) app for managing books will be a good idea.

在尝试实时应用程序之前,让我们首先为其创建一个平台。 一个用于管理书籍的CRUD(创建,读取更新和删除)应用程序将是一个好主意。

创造 (Creating)

The App.vue file in the src folder is our main and only component which is enough for what we are trying to build. Open the file and create a simple form:

src文件夹中的App.vue文件是我们的主要组件,也是唯一App.vue我们要构建内容的组件。 打开文件并创建一个简单的表单:

<!-- ./src/App.vue -->
<template>
  <div id="app">
    <h1> {{ title }} </h1>
    <h3>New Book</h3>
    <form v-on:submit.prevent="onSubmit">
      <div>
        <input name="title" type="text" placeholder="title" v-model="book.title" />
      </div>
      <div>
        <input name="year" type="text" placeholder="year" v-model="book.year" />
      </div>
      <div>
        <input name="author" type="text" placeholder="author" v-model="book.author" />
      </div>
      <div>
        <label for="read">Read?</label>
        <input type="checkbox" v-model="book.read" id="read" name="read" />
      </div>
      <button v-if="updating">Update</button>
      <button v-else>Add</button>
    </form>
  </div>
</template>

<script>

export default {
  name: 'app',
  data () {
    return {
      title: 'My Books Manager',
      updating: false,
      book: {
        title: '',
        year: '',
        author: '',
        read: false
      }
    }
  }
}
</script>

The file App.vue is known as Vue's Single File Component which is a great strategy from structuring Vue apps by allowing each component to be stored in a file while its template, style, and logic live in the file.

App.vue文件被称为Vue的单个文件组件 ,这是从结构化Vue应用程序开始的一种出色策略,它允许将每个组件存储在文件中,而其模板,样式和逻辑仍在文件中。

We have a basic form with Vue bindings. Each of the form control is bound to a property (using v-model) in the book object returned by Vue's data method. The method also returns a title which we use as the app's header and an updating flag which we use to toggle Add and Update buttons in the form. The toggle is achieved using Vue's v-if...v-else directives.

我们有一个带有Vue绑定的基本形式。 每个表单控件都绑定到Vue的data方法返回的book对象中的属性(使用v-model )。 该方法还返回一个标题(我们用作应用程序的标题)和一个updating标志(用于切换表单中的AddUpdate按钮)。 使用Vue的v-if...v-else指令可实现切换。

When the button(s) is clicked, an onSubmit method will be called because that is what the form's submit event binding is bound to. We need to create this method:

单击按钮后,将调用onSubmit方法,因为这是表单的提交事件绑定所绑定的方法。 我们需要创建此方法:

export default {
  name: 'app',
  data () {
    return {
      // . . .
      updateIndex: 0,
      books: [],
      book: {
        title: '',
        year: '',
        author: '',
        read: false
      }
    }
  },
  methods: {
      onSubmit() {
        if(this.updating) {
          this.onUpdate();
          return;
        }
        this.books.push(this.book);
        this.book = {
          title: '',
          year: '',
          author: '',
          read: false
        }
      }
  }
}

onSubmit will check if we are updating or not. If we are updating, it would delegate to another method, onUpdate, to handle updating. Otherwise, it would push the new values to the books array.

onSubmit将检查我们是否正在更新。 如果我们正在更新,它将委派给另一个方法onUpdate来处理更新。 否则,它将把新值推送到books数组。

(Reading)

The books array can be iterated and its values printed using a table. The iteration is achievable using the v-for Vue directive as show:

可以对books数组进行迭代,并使用表来打印其值。 可以使用v-for Vue指令实现迭代v-for如下所示:

<template>
  <div id="app">
    <h1> {{ title }} </h1>
    <h3>New Book</h3>
    <!-- For markup truncated -->
    <h3>All Books</h3>
    <table>
      <tr>
        <th>Title</th>
        <th>Year</th>
        <th>Author</th>
        <th>Read</th>
        <td>Update</td>
        <td>Delete</td>
      </tr>
      <tr v-for="(b, index) in books">
        <td>{{ b.title }}</td>
        <td>{{ b.year }}</td>
        <td>{{ b.author }}</td>
        <td v-if="b.read"></td>
        <td v-else> </td>
        <td v-on:click.prevent="onEdit(index)"><a></a></td>
        <td v-on:click.prevent="onDelete(index)"><a></a></td>
      </tr>
    </table>
  </div>
</template>

Something extra to the table's data rows -- two links to handle editing (not updating) and deleting a record. Each of them calls the onEdit and onDelete methods respectively. You can start using the form and see the results appear in the table:

该表的数据行有一些多余的东西-两个链接来处理编辑(而不是更新)和删除记录。 它们每个都分别调用onEditonDelete方法。 您可以开始使用该表格,并在表格中看到结果:

更新中 (Updating)

Updating takes two stages -- selecting the record from the table that we need to update which will make it appear in the form and mutating the array to update the value.

更新分两个阶段-从我们需要更新的表中选择记录,使其记录在表单中,并对数组进行变异以更新值。

The onEdit handler is responsible for the first stage:

onEdit处理程序负责第一阶段:

data () {
    return {
      updating: false,
      updateIndex: 0,
      books: [],
      book: {
        title: '',
        year: '',
        author: '',
        read: false
      }
    }
  },
 methods: {
     // . . .
     onEdit(index) {
       this.updating = true;
       this.updateIndex = index;
       this.book = this.books[index];
     },
 }

onEdit first raises the updating flag, then sets updateIndex to the index being edited and the replaces the book model with the record found in the index being updated.

onEdit首先会引发updating标志,然后将updateIndex设置为正在编辑的索引,然后将book模型替换为在要更新的索引中找到的记录。

updateIndex is used to keep track of what is being updated when onUpdate is called:

updateIndex用于跟踪调用onUpdate时正在更新的内容:

onUpdate() {
   this.updating = false;
   this.books[this.updateIndex] = this.book;
   this.book = {
     title: '',
     year: '',
     author: '',
     read: false
   }
 },

onUpdate now resets the updating flag, mutates the array to update the book and then empties the book model.

现在, onUpdate重置updating标志,对数组进行突变以更新书籍,然后清空book模型。

删除中 (Deleting)

This is the simplest; we utilize the array splice method to remove an item from the array based on there index:

这是最简单的。 我们利用数组splice方法根据那里的索引从数组中删除一个项目:

onDelete(index) {
 // Remove one item starting at
 // the specified index
 this.books.splice(index, 1)
}

借助Deepstream实现实时 ( Going Realtime with deepstream )

We have just built a working app, but that was not the goal. We need to let all connected clients know when a record is added, updated and deleted by updating the table holding these records. This is where deepstream steps in to help out. At the moment, if we try such, other connected clients stays dumb:

我们刚刚构建了一个可运行的应用程序,但这不是目标。 我们需要通过更新保存这些记录的表来让所有连接的客户端知道何时添加,更新和删除记录。 这是深流可以帮助您的地方。 目前,如果我们尝试这样做,其他连接的客户端将保持哑巴:

深流客户,记录和列表 (deepstream Clients, Records & Lists)

In the beginning of this post, we setup a deepstream server and left it running. In fact, the server is running on localhost at a given port, 6020. This server is just idle hoping for a client to connect and start exchanging data.

在本文的开头,我们设置了一个Deepstream服务器并使其运行。 实际上,服务器在本地主机上的给定端口6020 。 该服务器只是空闲状态,希望客户端连接并开始交换数据。

A deepstream client can come in any form, ranging from web, desktop, mobile and to even IoT. Our concern is Web for today, so we need to use deepstream's JS SDK to connect to the listening server. You can install the SDK by running:

深度客户端可以以任何形式出现,包括Web,桌面,移动甚至是IoT。 今天我们关注的是Web,因此我们需要使用deepstream的JS SDK连接到侦听服务器。 您可以通过运行以下命令安装SDK:

npm install --save deepstream.io-client-js

Records in deepstream are like records in any other form of representing data. It is a single entity and store a given information item. The only difference is that deepstream records are live which means that data stored on records can be subscribed to by clients and the clients will be notified with payload at the slightest change.

深度流中的记录就像以任何其他形式表示数据的记录一样。 它是单个实体,并存储给定的信息项。 唯一的区别是深度流记录是实时的,这意味着存储在记录中的数据可以由客户端订阅,并且客户端将以最小的更改通知有效负载。

Lists, on the other hand, help group records so they can be treated like a collection. Lists are as well live so they can be subscribed to for realtime changes and updates. We will utilize these deepstream features in our app to make the app realtime.

另一方面,列表有助于对记录进行分组,因此可以将它们视为集合。 列表也是实时的,因此可以订阅它们以进行实时更改和更新。 我们将在我们的应用程序中利用这些深度流功能来使应用程序实时化。

认证方式 (Authentication)

Authentication just like in every other situation allows you to confirm that a user is actually who she claims to be. Your regular HTTP authentication differ a little from the how deepstream will handle authentication. However, the good thing is, it is easy to hook them together.

就像在所有其他情况下一样,身份验证使您可以确认用户确实是她声称的身份。 您的常规HTTP身份验证与Deepstream处理身份验证的方式略有不同。 但是,好处是,将它们钩在一起很容易。

For every deepstream connecting client, an authentication is required. This does not necessarily mean that a credential must be provided; performing a login can just be anonymous and that applies to our case at the moment.

对于每个深度连接客户端,都需要进行身份验证。 这并不一定意味着必须提供凭据。 执行登录只能是匿名的,目前适用于我们的案例。

import * as ds from 'deepstream.io-client-js';

export default {
  name: 'app',
  data () {
    return {
      ds: ds('localhost:6020'),
      books$$: null
      // . . .
    }
  },
  created () {
    this.ds.login({}, () => {
      console.log('logged in');
    });
  },
  methods: {/* . . .*/}
}

First we import the installed client, then we create a member variable ds to hold a reference to the deepstream while passing in the server's URL.

首先,我们导入已安装的客户端,然后创建一个成员变量ds ,以在传入服务器URL的同时保留对深度流的引用。

The created function is a lifecycle method which is called by Vue when the component is ready. This makes created a good candidate to handle deepstreawm authentication. Authentication is performed by calling deepstream.login method which receives a credential and a callback.

created函数是生命周期方法,当组件准备就绪时,Vue会调用该方法。 这使得created一个很好的候选处理deepstreawm认证。 通过调用deepstream.login方法执行身份验证, deepstream.login方法接收凭据和回调。

The books$$ property will keep a reference to the deepstream list we are yet to create.

books$$属性将保留对我们尚未创建的深度列表的引用。

We will revisit the CRUD process and update them with respect to deepstream but before that, we need to make all the connected clients listen to value changes so they can update accordingly

我们将重新审视CRUD流程并针对深流进行更新,但是在此之前,我们需要让所有连接的客户端都倾听价值变化,以便他们可以相应地更新

列表和记录订阅 (List and Records Subscriptions)

created () {
    this.ds.login({}, () => {
      console.log('logged in');
    });

    this.books$$ = this.ds.record.getList('books');
    /*
    * Entry added
    */
    this.books$$.on('entry-added', (recordName, index) => {
       this.ds.record.getRecord(recordName).whenReady(record => {

        // The scond paramaeter,
        // a boolean, is a flag to specify whether 
        // the callback should be invoked immediatly
        // with the current value
         record.subscribe(data => {
              if(!data.id) {
                if(data.title) {
                  data.id = record.name;
                  this.books.push(data);
                }
              } else {

              this.books = this.books.map(b => {
                      if(data.id == b.id) {
                            b = data;
                        }
                        console.log(b)
                          return b;
                    });
              }
         }, true) 
       });
    });
    /*
     * Entry removed
     */

    this.books$$.on('entry-removed', (recordName, index) => {
       this.ds.record.getRecord(recordName).whenReady(record => {
         record.subscribe(data => {
             this.books.splice(this.books.indexOf(data, 1));
         }, true) 
       });
    });
  },
  • Lists and records API live on the record object. To create or retrieve an existing list, we use the getList method passing in, a name of our choice.

    record对象上实时列出并记录API。 要创建或检索现有列表,我们使用传入的getList方法,这是我们选择的名称。
  • entry-added event listens to record addition to the created list. So when a record is added to the list, the event is triggered.

    entry-added事件侦听将记录添加到创建的列表中。 因此,将记录添加到列表时,将触发事件。
  • When a record is added, whenReady ensures the record is ready before we subscribe to it using the subscribe method.

    添加记录时, whenReady确保记录已准备好,然后再使用whenReady方法进行subscribe
  • subscribe takes a callback which checks if the data exists and updates it. If the record's data does not exist, it updates the record with the incoming data while setting the data's id to the record name (id). The books array is updated as data comes in.

    subscribe一个回调,该回调检查数据是否存在并对其进行更新。 如果记录的数据不存在,则它将传入的数据更新记录,同时将数据的id设置为记录名称(id)。 数据输入时, books数组会更新。
  • entry-removed is the opposite of what we saw. It listens for when we remove a record so as to remove the record's data from the books array.

    entry-removed与我们所看到的相反。 它在我们删除记录时侦听,以便从books数组中删除记录的数据。

创造 (Creating)

The onSubmit method will have to take a new shape. We won't be pushing data to books directly because that's already being done by the subscription. We just need to call a method that creates a record with data and adds the record to the list we created:

onSubmit方法将必须采用新的形状。 我们不会直接将数据推送到books ,因为订阅已经完成了。 我们只需要调用一个方法即可创建带有数据的记录,并将该记录添加到我们创建的列表中:

onSubmit() {
   const recordName = this.book.id || 'book/' + this.ds.getUid();

   this.ds.record.has(recordName, (err, has) => {
     if(has){
       this.onUpdate();
       return;
     } else {
        const bookRecord = this.ds.record.getRecord(recordName);
         bookRecord.set(this.book);

         this.books$$.addEntry(recordName)

         this.book = {
           title: '',
           year: '',
           author: '',
           read: false
         }
     }
   })
 },

We create/get a record using a UUID or the Id attached to data if data exists. The had method is used to check if the record exists or not. If it exists, we call the onUpdate method, else, we set the record to the new book and update the books$$ list with addEntry.

我们使用数据的UUID或ID创建/获取记录(如果存在数据)。 had方法用于检查记录是否存在。 如果存在,则调用onUpdate方法,否则,将记录设置为book并使用addEntry更新books$$列表。

更新中 ( Updating )

onUpdate() {
   const recordName = this.books[this.updateIndex].id;
   const bookRecord = this.ds.record.getRecord(recordName);
   bookRecord.set(this.book);
   this.book = {
     title: '',
     year: '',
     author: '',
     read: false
   }

   this.updating = false;
 }

onSubmit delegates updating to the onUpdate if the record name in question exists.

如果存在相关记录名,则onSubmit委派更新到onUpdate

onUpdate retrieves the record name from the books array using the updateIndex. We get the record that the record name belongs to and the update the record with the book changes. No need to do anything on the list, it will behave accordingly.

onUpdate使用updateIndex从books数组中检索记录名称。 我们得到记录名称所属的记录,并随着book变化更新记录。 无需执行列表中的任何操作,它将表现相应。

删除中 (Deleting)

The onDelete method just calls removeEntry from the list to remove a record:

onDelete方法只是调用removeEntry从列表中删除一条记录:

onDelete(index) {
  this.books$$.removeEntry(this.books[index].id);
 }

结论 ( Conclusion )

Building realtime apps keeps getting better with advent of more advanced solutions. You can as well perform HTTP auth or JWT auth as well as connect your database to deepstream when you need to persist data.

随着更多高级解决方案的出现,构建实时应用程序将变得越来越好。 您还可以执行HTTP身份验证JWT身份验证 ,以及在需要持久存储数据时将数据库连接到深流

It's fascinating how we could build better UI apps using two simple to integrate platforms, Vue and deepstream. Vue is not just the only kid welcomed to the party. You can integrate deepstream with any other UI library out there using the same strategy of initialization and authentication.

令人着迷的是,我们如何使用两个简单的集成平台Vue和Deepstream构建更好的UI应用程序。 Vue不仅是参加聚会的唯一孩子。 您可以使用相同的初始化和身份验证策略将deepstream与其他任何UI库集成。

翻译自: https://scotch.io/tutorials/build-a-realtime-crud-app-with-vue-deepstream

vue crud

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值