成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

急速JavaScript全棧教程

騫諱護(hù) / 1556人閱讀

摘要:使用訪問后端服務(wù)使用的美化組件的方法整合全棧服務(wù)其中的指的是。所幸是在這個(gè)教程內(nèi),你不需要學(xué)習(xí)太多就可以把案例跑起來(lái)。另外一個(gè)組件負(fù)責(zé)顯示全部項(xiàng)目,并接受刪除事件,刪除指定的項(xiàng)目。它們分別是組件和組件這兩個(gè)組件的代碼實(shí)現(xiàn),分別在文件和內(nèi)。

自從一年前發(fā)布了Vuejs小書的電子書,也有些日子沒有碰過它們了,現(xiàn)在因?yàn)轫?xiàng)目的緣故,需要使用JavaScript全棧開發(fā)。所以,我得把這個(gè)全棧環(huán)境搭建起來(lái)。

整個(gè)系列,是會(huì)采用我的一貫風(fēng)格,就是不疾不徐,娓娓道來(lái),學(xué)習(xí)完畢,你可以掌握我提到的全系列的知識(shí),并且得到一個(gè)可以直接拷貝的代碼模板,并把它用到你的項(xiàng)目中。

完成操練下來(lái),得半小時(shí)到一個(gè)小時(shí)吧。騰出你的時(shí)間再來(lái)學(xué)習(xí)。

前端的復(fù)雜度

很多人是看不起JavaScript開發(fā)的。這玩意不就是玩具嘛,一些腳本和標(biāo)簽而已。說這話的時(shí)候,他們可能是就翹起二郎腿的,或者抱著膀子的。

然而,前端因?yàn)檫€在快速發(fā)展,因此很多東西在變,構(gòu)造環(huán)境的選擇比較多,技術(shù)種類也不少,很多事情得自己做。因此它其實(shí)并不比那么簡(jiǎn)單的。這篇文章的圖,可以窺視到前端復(fù)雜的一角了。Modern Frontend Developer in 2018。

我看了不少資料,很多都是講解這張圖中的一個(gè)技術(shù),講解全棧的肯定是有的,但是往往過于復(fù)雜。本文試圖通過一組文章,把JavaScript的全棧開發(fā)做一個(gè)全景的展示,力圖使用一個(gè)案例,全須全尾的貫穿整個(gè)系列,便于初學(xué)者對(duì)技術(shù)的急速理解。

大綱

所以,文章會(huì)包括這些:

使用Vuejs腳手架,快速搭建一個(gè)CRD用戶界面。會(huì)使用vuex管理狀態(tài),使用vue-router管理路由。

使用Mongodb存儲(chǔ)和提供后端CRD服務(wù)。

使用Nodejs搭建后端CRD服務(wù)。

使用Fecth|Axios訪問后端CRD服務(wù)

使用bulfy的美化組件的方法

整合全棧服務(wù)

其中的CRD指的是Create、Read、Delete。針對(duì)的數(shù)據(jù)對(duì)象,就是一個(gè)Todo對(duì)象,看起來(lái)是這樣的:

{id:1,subject:"Loving"}

如果是多個(gè)數(shù)據(jù)對(duì)象,看起來(lái)是這樣的:

[
  {id:1,subject:"Loving"},
  {id:1,subject:"Writing"},
  {id:1,subject:"Preying"}
]

這個(gè)看起來(lái)很簡(jiǎn)單平實(shí)的JS對(duì)象,會(huì)在一組組函數(shù)、模塊和對(duì)象之間流動(dòng),甚至跨越網(wǎng)絡(luò)邊界,從內(nèi)存到硬盤。它會(huì)被存儲(chǔ)在Mongodb內(nèi),也會(huì)從Mongodb提取出來(lái),在用戶界面、HTTP客戶端,HTTP服務(wù)器傳遞。

整個(gè)App看起來(lái)就是一臺(tái)機(jī)器,可以說代碼在運(yùn)轉(zhuǎn)這個(gè)機(jī)器,但是也不妨說是數(shù)據(jù)在驅(qū)動(dòng)這個(gè)它。

使用Vuejs腳手架,快速搭建Todo App界面

我們給自己命題,做一個(gè)TODO應(yīng)用,它看起來(lái)是這樣的:

用戶可以看到一個(gè)編輯框,和一個(gè)清單。

在編輯框內(nèi)加入新的todo項(xiàng)目,按回車即可加入到列表

列表內(nèi)每個(gè)項(xiàng)目有一個(gè)按鈕,點(diǎn)擊按鈕,可以刪除當(dāng)前項(xiàng)目

環(huán)境要求

說起來(lái)搭建JS全棧開發(fā)環(huán)境,涉及到的東西真的不少。大的選擇是這樣的:

前端采用Vuejs

后端采用Nodejs

存儲(chǔ)使用Mongodb。

大的選擇定了,小的配套也就跟著來(lái),前端配套的話需要一系列的技術(shù),特別是前端,對(duì)應(yīng)著Vuejs,配套管理路由、狀態(tài)、組件的都有相應(yīng)的技術(shù)手段。自己搭配的話,還是非常麻煩的。

幸好Vuejs還有一個(gè)前端腳手架工具vue-cli,它可以把以上的組件整合起來(lái)到一個(gè)工程內(nèi)。一個(gè)最為基礎(chǔ)的vue-cli工程腳手架的創(chuàng)建,現(xiàn)在得需要160M左右的空間占用。在我的電腦和網(wǎng)絡(luò)情況下,需要2分半的時(shí)間才會(huì)完成。

前端 Vuejs

vue-router,前端路由管理

vuex,前端數(shù)據(jù)管理,專業(yè)一點(diǎn)的說法,就是狀態(tài)管理,這些數(shù)據(jù),可能是屬性,數(shù)組,對(duì)象等等,可以跨組件訪問,而不像是data函數(shù)那樣提供的數(shù)據(jù)只能被本組件訪問,可以想到,稍微大一點(diǎn)的前端工程都必須前端狀態(tài)管理的。

axios,前端HTTP訪問,以promise的形式,封裝了類似fetch,AJAX的能力

buefy,前端微型框架,可以使用自定義標(biāo)簽使用自定義組件,并且CSS框架為Bulma

Bulma,盡管使用了微框架,只是讓對(duì)CSS framework的了解降到最低,但是不是說就不需要了解了。還是得學(xué)習(xí)的。Bulma相對(duì)于老牌的Bootstrap,是不需要依賴于JS框架,也沒有任何JS代碼,因此可以和任何一框架很好的結(jié)合,比如這里的Vuejs。這就是我選擇它的原因

后端 cli-service

為了給前端開發(fā)提供工具鏈和開發(fā)便利性,我們常常需要webpack&babel。有了它們,就可以使用ES6的語(yǔ)法,以及代碼更新后自動(dòng)刷新等。這些都是非常便利的特性,用了就離不開的。有了vue-cli,對(duì)webpack&babel的了解可以降到最低,但是也不能不學(xué),稍微需要一些定制的配置,也是必須要掌握的,起碼得知道如何啟動(dòng)一個(gè)開發(fā)服務(wù)器,已經(jīng)發(fā)布build,還有把前端服務(wù)經(jīng)過proxyChain跳轉(zhuǎn)到后端服務(wù)去等等。所幸是在這個(gè)教程內(nèi),你不需要學(xué)習(xí)太多就可以把案例跑起來(lái)。

App Server + Mongodb

接下來(lái)看后端,一般習(xí)慣就是使用Nodejs+Express.js的搭配。這個(gè)沒有多少說的,都是老東西了。為了訪問Mongodb,也需要一套框架,基于Callback的,或者基于Promise+Await+Async的,也是需要選擇的。

為了便于理解,我會(huì)用一個(gè)最小的案例完成整個(gè)開發(fā)過程,就是案例在現(xiàn)實(shí)中并不存在,但是也是有用的,就是你可以當(dāng)它們是模板,直接拷貝代碼,然后填充你的內(nèi)容。天下代碼一大抄嘛,沒有什么不對(duì)的,畢竟這些寫代碼是最快的。這個(gè)案例的數(shù)據(jù)模型就是對(duì)一個(gè){id,name}的對(duì)象進(jìn)行CRD(創(chuàng)建刪除列表)。

安裝運(yùn)行環(huán)境

安裝環(huán)境相對(duì)簡(jiǎn)單,特別是如果使用Mac OS X的話。有一些工具鏈可以幫助快速搭建環(huán)境。當(dāng)然Windows也并不多麻煩就是了,它常常提供的是一個(gè)安裝程序,大部分時(shí)間,你需要的就是點(diǎn)擊下一步。

這里以MAC為例,講解安裝。

mongodb

安裝和運(yùn)行Mongodb Daemon:

brew install mongodb
mongodb

訪問驗(yàn)證,首先執(zhí)行Mongodb Shell:

mongo

輸入命令,查詢數(shù)據(jù)庫(kù)清單:

> show dbs
local           0.000GB

能夠看到這些信息,說明mongodb安裝成功。

Node.js

安裝并驗(yàn)證:

$brew install nodejs
$node -v
10.7.0

能夠看到這些信息,說明Node.js安裝成功。

開始前端編碼 安裝編碼環(huán)境

首先安裝vue-cli,方法和一般的NPM模塊一樣的,我們安裝的版本是3.0:

npm i @vue/cli 

查看版本:

vue -V
3.0.0

看到如下信息,說明成功。然后創(chuàng)建App的腳手架代碼:

vue create todoapp

注意,在此創(chuàng)建過程中,命令行會(huì)指示你做出選擇,我們會(huì)選擇Manual select feature,然后選擇router和vuex,其他不選。然后并執(zhí)行此代碼:

cd todoapp
npm run serve

可以在瀏覽器中訪問localhost:8080看到Vue的啟動(dòng)畫面。說明創(chuàng)建腳手架成功。

此時(shí),vue-cli已經(jīng)幫助安裝了vuex和router的模塊依賴。本節(jié)一次性的安裝全部剩余的全部NPM依賴,免得以后用一個(gè)安裝一個(gè),麻煩而且啰嗦。

  npm install buefy --save
npm install axios --save 

buefy是一個(gè)基于Bulma的Vuejs用戶界面組件庫(kù)。這次的UI的CSS方案,使用Bulma,Vuejs如果想要以定制組件的形式去使用它的話,那么需要安裝Buefy模塊。實(shí)際上,我研究過Bulma和Bootstrap,還寫了一本免費(fèi)的電子書,我覺得Bulma相對(duì)于Bootstrap的優(yōu)勢(shì)在于1.不依賴任何JS框架2.用戶接口設(shè)計(jì)更加簡(jiǎn)明。這就是我現(xiàn)在選擇使用Bulma的原因。

Axios是一個(gè)封裝了HTTPClient的庫(kù),提供了promise接口。我們使用它訪問后端的HTTP Server的數(shù)據(jù)。之前提到的數(shù)據(jù)對(duì)象,就是由Axios提取到客戶端,也會(huì)是通過Axios把數(shù)據(jù)對(duì)象提交到服務(wù)器的。

前端編碼

首先,我們從狀態(tài)開始。我們之前提到的Vuex,是Vuejs管理狀態(tài)的官方插件。所謂的狀態(tài),就是應(yīng)用程序的數(shù)據(jù)對(duì)象們。也就是我們提到的Todo對(duì)象和Todo對(duì)象集合。我們?cè)贏pp用戶界面上看到的很多數(shù)據(jù)都是來(lái)自于狀態(tài)對(duì)象。狀態(tài)對(duì)象在src/store.js。不僅僅是的應(yīng)用狀態(tài)信息,還有和對(duì)這些的操作函數(shù)。既然需要一個(gè)todo項(xiàng)目清單,因此應(yīng)該加入如下代碼:

import Vue from "vue"
import Vuex from "vuex"
Vue.use(Vuex)
const defaultTodo = [
      {id:1,subject:"Eating"},
      {id:2,subject:"Loving"},
      {id:3,subject:"Preying"},
    ]
function indexById(todos,id){
  for (var i = 0; i < todos.length; i++) {
    if (id == todos[i].id)
      return i
  }
  return -1
}
import axios from "axios"
export default new Vuex.Store({
  state: {
    msg:"Todo App",
    todos:defaultTodo
  },
  mutations: {
    add(state,subject){
      var todo = {id:subject,subject:subject}
      state.todos.push(todo)
    },
    remove(state,id){
      state.todos.splice(indexById(state.todos,id),1)
    },
    reload(state){
      state.todos = defaultTodo
    }
  },
  actions: {
  add: (context, link) => {
      context.commit("add", link)
    },
    remove: (context, link) => {
      context.commit("remove", link)
    },
    reload: (context) => {
      context.commit("reload")
    }
  }
})

其中的state.todos屬性,就是我們的主要的數(shù)據(jù)對(duì)象了。state.msg這是提供了一個(gè)App的標(biāo)題字符串。mutations屬性內(nèi)是對(duì)數(shù)據(jù)修改提供的方法,比如

我們需要添加一個(gè)todo,使用add()方法,相應(yīng)的

刪除一個(gè)todo,使用remove()方法

刷新一個(gè)todo列表,就會(huì)使用load()方法

有時(shí)候,對(duì)數(shù)據(jù)的修改可能是比較消耗時(shí)間的,因此為了避免阻塞客戶端的主線程,這個(gè)對(duì)象也提供了異步的方法,actions對(duì)象內(nèi)就是對(duì)應(yīng)修改操作的異步方法,這里的方法功能上和mutations一致,但是是異步的。Vuex提供了類似:

context.commit()

的語(yǔ)法,提供和actions和mutations方法的對(duì)接。第一個(gè)參數(shù)是mutations的方法名稱,之后的參數(shù)最為mutations方法的參數(shù)傳遞給mutations方法。

特別說下,mutations內(nèi)的add()方法,其中用戶界面會(huì)提供一個(gè)Todo.subject屬性,而ID是需要自動(dòng)生成的,我們這里臨時(shí)使用subject的值作為id,就是一個(gè)偷懶,只要subject不要輸入重復(fù),也暫時(shí)可以蒙混過關(guān)。因?yàn)橹辣卷?xiàng)目?jī)?nèi)的后臺(tái)存儲(chǔ)會(huì)采用Mongodb,在Mongodb內(nèi)插入一個(gè)新的對(duì)象后,會(huì)自動(dòng)生成一個(gè)ID,我們的Todo對(duì)象的id會(huì)采用這個(gè)ID。這里就沒有必要自己生成了。

在src/views/home.vue內(nèi),粘貼為如下代碼:



...mapState,mapActions的解說。

就是說,我們這個(gè)Todo App劃分為為兩個(gè)組件,其中一個(gè)組件負(fù)責(zé)顯示編輯框,并接受回車事件,把新的Todo項(xiàng)目加入到應(yīng)用狀態(tài)內(nèi)。另外一個(gè)組件負(fù)責(zé)顯示全部Todo項(xiàng)目,并接受刪除事件,刪除指定的Todo項(xiàng)目。它們分別是NewTodo組件和TodoList組件:



這兩個(gè)組件的代碼實(shí)現(xiàn),分別在文件src/components/NewTodo.vuesrc/components/TodoList.vue內(nèi)。NewTodo代碼:



TodoList代碼:





在src/main.js文件內(nèi),添加如下代碼,引入Buefy:

import Buefy from "buefy"
import "buefy/lib/buefy.css"
Vue.use(Buefy)

現(xiàn)在可以使用Buefy組件了。我們可以把NewTodo組件內(nèi)的標(biāo)準(zhǔn)的input變成組件化的input,把標(biāo)簽換成b-input即可。代碼如下:


現(xiàn)在看瀏覽器,input變成了比較有吸引力的Bulma風(fēng)格的控件了。
訪問網(wǎng)絡(luò)使用axios。需要首先找到src/home.vue在代碼的開頭部分引用此庫(kù):

import axios from "axios"

在Vue單頁(yè)組件內(nèi)使用此庫(kù)了。比如在src/home.vue內(nèi)代碼對(duì)象中加入新方法:

mounted(){
  var url  = "https://api.coindesk.com/v1/bpi/currentprice.json"
  axios ({
        url:url,
        method: "get",
    })
    .then( res => {console.log(res.data.chartName)} )
    .catch( err => cosole.error(err))
}

我們來(lái)看看適應(yīng)效果。啟動(dòng)cli-service:

npm run serve

然后打開瀏覽器,輸入地址localhost:8080,如果可以在瀏覽器內(nèi)看到我們期望的用戶界面,并且都可以看到console打印了Bitcoin,那么就說明用戶界面代碼和初步的訪問HTTP網(wǎng)絡(luò)的axios代碼以及狀態(tài)管理功能都是成功了的。

后端編碼

現(xiàn)在,我們已經(jīng)可以看到UI了,但是用戶界面內(nèi)的數(shù)據(jù)來(lái)自于客戶端,而不是來(lái)自于服務(wù)器。我們的數(shù)據(jù)當(dāng)然應(yīng)該來(lái)源于服務(wù)器的了。因此我們需要啟動(dòng)給一個(gè)自己的服務(wù)器,這個(gè)服務(wù)器可以接受客戶在界面上錄入的新的Todo對(duì)象,也可以提供后端數(shù)據(jù)庫(kù)內(nèi)的Todo清單。

為了測(cè)試的目的,常常需要準(zhǔn)備一個(gè)todo應(yīng)用的后臺(tái)JSON服務(wù),可以通過HTTP方式,提供todo項(xiàng)目的增加刪除修改和查詢。

這樣的服務(wù)器,使用了nodejs作為服務(wù)器端,并且使用了兩個(gè)node模塊,可以使用npm安裝它們:

npm install express body-parser

body-parser是一個(gè)中間件,可以解析請(qǐng)求內(nèi)容并把解析結(jié)果放到req.body屬性內(nèi)。最常見的做法就是解析json內(nèi)容。

代碼如下(文件名為:jsonserver.js):

  var express = require("express");
  var app = express();
  var path = require("path")
  var bodyParser = require("body-parser")
  app.use(bodyParser.json())
  var todos = []
  var public = path.join(__dirname, "/")
  app.use("/",express.static(public))
  const defaultTodo = [
    {id:1,subject:"Eating"},
    {id:2,subject:"Loving"},
    {id:3,subject:"Preying"},
  ]
  function rs(){
    todos = defaultTodo
  }
  function indexById(id){
    for (var i = 0; i < todos.length; i++) {
      if (id ==todos[i].id)return i
    }
    return -1
  }
  rs()
  app.delete("/api/todo/:id", function (req, res) {
    var userkey = +req.params.id
    todos.splice(indexById(userkey),1)
    res.end( JSON.stringify(todos));
    rs()
  })
  app.get("/api/todos", function (req, res) {
    res.end( JSON.stringify(todos));
  })
  app.post("/api/todo", function (req, res) {
    todos.push(req.body)
    res.end(JSON.stringify(todos))
    rs()
  })
  var server = app.listen(8081, function () {
    var host = server.address().address
    var port = server.address().port
    console.log("listening at http://%s:%s", host, port)
  })

可以使用命令執(zhí)行:

node jsonserver.js

Curl命令驗(yàn)證

可以通過curl命令驗(yàn)證服務(wù)的有效性:

GET操作

 $curl http://localhost:8081/todo/1
 $curl http://localhost:8081/todos

DELETE操作

  $ curl -X "DELETE" http://localhost:8081/api/todo/1

POST操作

$curl -X POST  -H "Content-Type: application/json" -d "{"subject":"s4"}" http://localhost:8081/api/todo

前端HTML驗(yàn)證

創(chuàng)建一個(gè)index.html文件,并放置到和jsonserver.js代碼同一目錄,代碼如下:

todos
todo/1



可以提供創(chuàng)建,刪除,列表的測(cè)試,其中部分結(jié)果在console內(nèi)顯示。

說起來(lái),JS訪問HTTP的庫(kù)真的是不少,這里 提到的庫(kù)都有9種。其中的fetch api使用起來(lái)非常的簡(jiǎn)潔趁手,可是它不支持IE。如果你需要支持IE的話,使用Axios更好。這就是為什么Vuejs官方推薦Axios的原因吧:

The Fetch API is a powerful native API for these types of requests. You may have heard that one of the benefits of the Fetch API is that you don’t need to load an external resource in order to use it, which is true! Except… that it’s not fully supported yet, so you will still need to use a polyfill. There are also some gotchas when working with this API, which is why many prefer to use axios for now. This may very well change in the future though.
axios訪問方法

相比f(wàn)etch,使用axios必須依賴于外部文件。為了方便,我們直接使用unpkg網(wǎng)站提供的庫(kù)文件。

axios的語(yǔ)法和fetch的大同小異,看著也是比較簡(jiǎn)潔美觀的。以下代碼,把create和remove函數(shù)的內(nèi)部實(shí)現(xiàn)換掉,其他不變。


todos
todo/1



現(xiàn)在,后端也是可以跑起來(lái)了的。

整合:前端后端 建立cli-service到App Server的通道

每次執(zhí)行命令:npm run serve,都會(huì)啟動(dòng)vue定制腳手架的服務(wù)器代碼,它會(huì)提供不少方便開發(fā)的特性。但是我希望一部分URL可以轉(zhuǎn)發(fā)到我自己的服務(wù)器內(nèi)。比如把所有的/api打頭的URL全部轉(zhuǎn)過來(lái)。只要在工程根目錄內(nèi)加入此文件vue.config.js,錄入如下內(nèi)容:

module.exports = {
  devServer: {
    proxy: {
      "/api": {
        target: "http://localhost:8181",
        secure: false
      }
    }
  }
};

我們自己的測(cè)試服務(wù)器在這里:

var http = require("http");
http.createServer(function (req, res) {
  res.write("Hello World!"); 
  res.end(); 
}).listen(8181); 

我們的定制服務(wù)器,就可以監(jiān)聽8181的本地機(jī)器端口,等待客戶端的匹配的URL轉(zhuǎn)發(fā)過來(lái),并轉(zhuǎn)發(fā)我們服務(wù)器的響應(yīng)代碼到客戶端。

但是正常開發(fā)過程中,是需要自己的服務(wù)器端代碼的,如何在利用Vue腳手架服務(wù)器的方便性的基礎(chǔ)上,加入自己的代碼呢。做法是另外做一個(gè)定制的服務(wù)器,然后讓vue定制腳手架的服務(wù)器轉(zhuǎn)發(fā)URL到此服務(wù)器。

為了測(cè)試的目的,我們把函數(shù)mounted修改為:

mounted(){
  var url  = "/api/1"
  axios ({
        url:url,
        method: "get",
    })
    .then( res => {console.log(res.data)} )
    .catch( err => console.error(err))
}

即可看到瀏覽器console內(nèi)打印Hello World!。

整合前端到后端

我們已經(jīng)通過配置,要求cli-service轉(zhuǎn)移全部api打頭的URL到App Server。只要在工程根目錄內(nèi)加入此文件vue.config.js,錄入如下內(nèi)容:

module.exports = {
  devServer: {
    proxy: {
      "/api/*": {
        target: "http://localhost:8181/api",
        secure: false
      }
    }
  }
};

現(xiàn)在,我們可以修改前端的Axios使用代碼,分別替代前端代碼的數(shù)據(jù)裝入、數(shù)據(jù)刪除、數(shù)據(jù)添加的代碼,讓這些代碼可以支持網(wǎng)絡(luò)操作。為了避免網(wǎng)絡(luò)操作代碼和業(yè)務(wù)邏輯代碼混合在一起,我決定包裝三個(gè)網(wǎng)絡(luò)操作函數(shù),并把它們放置到src/store.js文件內(nèi):

import axios from "axios"
function httpadd(subject,cb){
  axios ({
        method: "POST",
        url:"/api/todo",
        headers:[{"Content-Type":"application/json"}],
        data: {subject:subject}
      })
      .then( res => cb(res.data))
      .catch( err => console.error(err))
}
function httpremove(id,cb){
  axios ({
        url:"/api/todo/"+id,
        method: "delete",
      })
      .then( res => {
          cb()
      })
      .catch( err => console.error(err))
}
function httpreload(cb){
  axios ({
        url:"/api/todos",
        method: "get",
      })
      .then( res => {
          cb(res.data)
      })
      .catch( err => console.error(err))
}

分別完成添加、刪除、查找的任務(wù),當(dāng)完成工作后,都會(huì)調(diào)用一個(gè)callback函數(shù),在此函數(shù)內(nèi),可以消費(fèi)訪問網(wǎng)絡(luò)后得到的響應(yīng)數(shù)據(jù)。

然后把文件內(nèi)src/store.js的mutations對(duì)象改成如下代碼:

 mutations: {
  add(state,subject){
    httpadd(subject,function(todo){
      state.todos.push(todo)
    })
  },
  remove(state,id){
    httpremove(id,function(){
      state.todos.splice(indexById(state.todos,id),1)  
    })
  },
  reload(state){
    httpreload(function(todos){
      // console.log(todos)
      state.todos = todos
    })
    // state.todos = defaultTodo
  }
},

最后,在TodoList內(nèi)加入一個(gè)新函數(shù),并通過mapActions引入src/store.js的load()函數(shù)到當(dāng)前對(duì)象內(nèi):

  methods:{
    ...mapActions([
      "remove","load"
    ])
  },
  mounted(){
    this.load()
  }

以便在啟動(dòng)后調(diào)用this.load()裝入它。

整合:后端和數(shù)據(jù)庫(kù)

要完成后端到數(shù)據(jù)庫(kù)的整合,需要做如下的修改:

原本在后端App Server內(nèi)Todo數(shù)據(jù)數(shù)組,現(xiàn)在應(yīng)該從Mongodb獲得

原本在添加Todo對(duì)象的時(shí)候只是添加到AppServer對(duì)象內(nèi),現(xiàn)在需要同時(shí)寫入Mongodb

原本在刪除時(shí)只是從數(shù)組刪除,現(xiàn)在需要同時(shí)在Mongodb內(nèi)刪除

因此,現(xiàn)在我們需要添加三個(gè)函數(shù),分別做針對(duì)Mongodb的獲取清單、添加和刪除的工作:

var mongo = require("mongodb")
function insertDoc(subject,callback){
  const connectionString = "mongodb://localhost:27017";
  (async () => {
      const client = await MongoClient.connect(connectionString,
          { useNewUrlParser: true });
      const dbo = client.db("todos");
      try {
         var res = await dbo.collection("todo").insertOne(
          {subject:subject})
         callback(undefined,res.insertedId)
      }
      catch(err){
        callback(err)
      }
      finally {
          client.close();
      }
  })().catch(err => console.error(err));
}
function deleteDoc(_id,callback){
  const MongoClient = mongo.MongoClient;
  const connectionString = "mongodb://localhost:27017";
  (async () => {
      const client = await MongoClient.connect(connectionString,
          { useNewUrlParser: true });
      const dbo = client.db("todos");
      try {
              var myquery = {_id:new mongo.ObjectID(_id)}
              var r = await dbo.collection("todo").deleteMany(myquery)
        }
        catch(err){
        callback(err)
      }
      finally {
            client.close();
            callback()
        }
  })().catch(err => console.error(err));
}
function allDoc(callback){
  const MongoClient = mongo.MongoClient;
  const connectionString = "mongodb://localhost:27017";
  (async () => {
      const client = await MongoClient.connect(connectionString,
          { useNewUrlParser: true });
      const dbo = client.db("todos");
      try {
             var r = await dbo.collection("todo").find().toArray()
             var ts = []
             for (var i = 0; i < r.length; i++) {
               ts.push({id:r[i]._id,subject:r[i].subject})
             }
             callback(undefined,ts)
        }
        catch(err){
        callback(err)
      }
      finally {
            client.close();
        }
  })().catch(err => console.error(err));
}

這三個(gè)函數(shù)的功能和使用方法如下:

函數(shù)allDoc會(huì)從Mongodb內(nèi)獲取全部todo集合,并通過callback傳遞這個(gè)集合給調(diào)用者函數(shù)。

函數(shù)deleteDoc會(huì)從Mongodb內(nèi)刪除指定id的todo條目,完成刪除后,通過callback通知調(diào)用者。

函數(shù)deleteDoc會(huì)向Mongodb內(nèi)添加一個(gè)todo條目,完成添加后,通過callback通知調(diào)用者,并傳遞新的todo對(duì)象給調(diào)用者。

這里的代碼本身并不復(fù)雜,但是因?yàn)樯婕暗饺绾卧L問Mongodb,因此涉及到比較多的概念,這里不做具體的解釋,你可以先把它們用起來(lái)。如果完成了本教程后,希望對(duì)Mongodb的訪問做具體了解的話,可以查看后文附錄的“Mongodb快速參考”。

并且和App Server對(duì)應(yīng)的代碼接駁,把原來(lái)的路由代碼替換如下:

app.delete("/api/todo/:id", function (req, res) {
  var userkey = req.params.id
  deleteDoc(userkey,function(){
    todos.splice(indexById(userkey),1)
    res.end( JSON.stringify(todos));
  })
})
app.get("/api/todos", function (req, res) {
  allDoc(function(err,todos){
    res.end( JSON.stringify(todos));  
  })
})
app.post("/api/todo", function (req, res) {
  insertDoc(req.body.subject,function(err,_id){
    var obj ={id:_id,subject:req.body.subject}
  todos.push(obj)
  res.end(JSON.stringify(obj))
    rs()
  })
})

 
Mongodb快速參考

本文會(huì)把一個(gè)對(duì)象todo對(duì)象(有屬性{id,name})存儲(chǔ)到Mongodb,做查詢刪除的測(cè)試(Create Remove Delete = CRD)。這個(gè)測(cè)試包括使用Mongodb Shell,使用CallBack古典風(fēng)格的訪問代碼,以及使用Await/Async的現(xiàn)代風(fēng)格的代碼。完成這個(gè)這個(gè)驗(yàn)證后,就可以掌握最初步的Mongodb了。

我使用的Nodejs是10.7 。操作系統(tǒng)環(huán)境為Mac OS X High Sierra。

準(zhǔn)備環(huán)境

安裝和運(yùn)行Mongodb Daemon

brew install mongodb
mongodb

訪問驗(yàn)證

首先執(zhí)行Mongodb Shell:

mongo

輸入命令,查詢數(shù)據(jù)庫(kù)清單:

> show dbs
local           0.000GB

創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)

use todos

(若database不存在,則會(huì)創(chuàng)建一個(gè),此時(shí)若不做任何操作直接退出,則MongoDB會(huì)刪除該數(shù)據(jù)庫(kù))

db.todos.insert({id:1,name:"reco"})
db.todos.insert({id:2,name:"rita"})

查詢 :

db.todos.find()

{ "_id" : ObjectId("5b727c0846b6c71a98d3af52"), "id" : 1, "name" : "reco" }
{ "_id" : ObjectId("5b727c7046b6c71a98d3af53"), "id" : 2, "name" : "reta" }

刪除記錄:

db.todo.remove({id:1})

刪除數(shù)據(jù)庫(kù)

db.todo.drop()
使用nodejs方式訪問Mongodb

使用nodejs執(zhí)行類似Shell對(duì)對(duì)象的CRD,代碼如下:

var MongoClient = require("mongodb").MongoClient;
var url = "mongodb://localhost:27017/todos";
MongoClient.connect(url, function(err, db) {
  if (err) throw err;
  console.log("Database created!");
  var dbo = db.db("todos");
  // var myobj = { id: 1, name: "reco" };
  // dbo.collection("todo").insertOne(myobj, function(err, res) {
  //   if (err) throw err;
  //   console.log("1 document inserted");
  //   db.close();
  // });
   var myobj = [
    { id: 1, name: "reco"},
    { id: 2, name: "rita"},
  ];
  dbo.collection("todo").insertMany(myobj, function(err, res) {
    if (err) throw err;
    console.log("Number of documents inserted: " + res.insertedCount);
    dbo.collection("todo").find({}).toArray(function(err, result) {
      if (err) throw err;
      console.log(result);
        var myquery = { id: 1 };
      dbo.collection("todo").deleteMany(myquery, function(err, obj) {
        if (err) throw err;
        console.log("document deleted");
        db.close();
      });
    });    
  });
})

代碼非常簡(jiǎn)單,無(wú)需更多解釋。此代碼使用了mongodb模塊,需要首先安裝:

npm init -y
npm i mongodb --save

然后使用node index.js運(yùn)行即可看到效果:

Database created!
Number of documents inserted: 2
[ { _id: 5b72ab9e3245f169ef5f43d2, id: 1, name: "reco" },
  { _id: 5b72ab9e3245f169ef5f43d3, id: 2, name: "rita" } ]
document deleted
利用高級(jí)異步特性

使用Await/Async特性,可以有效的減少代碼中的回調(diào)地獄現(xiàn)象。同樣的功能,可以使用這樣的代碼:

const MongoClient = require("mongodb").MongoClient;
const connectionString = "mongodb://localhost:27017";
(async () => {
    const client = await MongoClient.connect(connectionString,
        { useNewUrlParser: true });
    const dbo = client.db("todos");
    try {
       var res = await dbo.collection("todo").insertMany(
        [{id:1,name:"reco"}, {id:2,name:"rita"}]);
       console.log("Number of documents inserted: " + res.insertedCount);
       var r = await dbo.collection("todo").find().toArray()
       console.log(r);
       var myquery = { id: 1 };
     var r = await dbo.collection("todo").deleteMany(myquery)
     console.log("document deleted");
    }
    finally {
        client.close();
    }
})().catch(err => console.error(err));

執(zhí)行此代碼,輸出如下:

Number of documents inserted: 2
[ { _id: 5b72ae8a1c674a6ac1c5aa6e, id: 1, name: "reco" },
  { _id: 5b72ae8a1c674a6ac1c5aa6f, id: 2, name: "rita" } ]
document deleted
Vuejs快速參考

Vuejs本身要學(xué)的還真不少,這也是我會(huì)編寫一本書來(lái)介紹它的原因。但是說到入門的話,我倒是寫過一篇簡(jiǎn)單的介紹文章。不妨去閱讀看看。

上面的文章,也就對(duì)Vuejs了解個(gè)大概,提起一個(gè)興趣。如果真的想要學(xué)習(xí)Vuejs的話,還是得看書的。這里也放一個(gè)我的書的廣告,歡迎參閱。

購(gòu)買

問題索引

麻雀雖小五臟俱全,雖然是一個(gè)小小的示例的應(yīng)用,但是每樣技術(shù)也都需要用到,遇到的技術(shù)問題也是要一個(gè)個(gè)的解決的。這里列出我遇到的問題,作為索引,也算記錄我在寫作過程中解決的問題,也可以作為你學(xué)習(xí)完畢后的一個(gè)查漏補(bǔ)缺的索引,在這里重新看到問題,然后使用代碼驗(yàn)證自己對(duì)問題的理解和學(xué)習(xí)。

使用Nodejs如何搭建一個(gè)RESTFUL的服務(wù)?

如何把cli-service中來(lái)自客戶端但是需要去應(yīng)用服務(wù)器的URL訪問轉(zhuǎn)移到應(yīng)用服務(wù)器?

如何解析前端提交的Json?

如何打包Json到響應(yīng)內(nèi)?

如何創(chuàng)建一個(gè)唯一的ID?本來(lái)是用于創(chuàng)建一個(gè)唯一ID,這樣就不必使用MongoDB生成的ObjectID了,因此插入效率會(huì)更高。但是,最后還是按慣例采用了Mongo的了。

如何加入新的單頁(yè)組件?

在哪里插入獲取服務(wù)端數(shù)據(jù)的代碼?

如何使用Buefy?

在Vuejs應(yīng)用中內(nèi)使用Buefy?

在Vuejs單頁(yè)組件內(nèi)使用Buefy?

如何關(guān)閉input的自動(dòng)完成特性?這個(gè)自動(dòng)完成每次當(dāng)你輸入的時(shí)候,都會(huì)顯示一個(gè)曾經(jīng)的輸入的列表,真的很煩。

如何在組件之間共享狀態(tài)?

為何需要共享前端狀態(tài)?

如何區(qū)別使用同步和異步狀態(tài)操作?

如何映射狀態(tài)操作到組件內(nèi),以方便組件對(duì)方法的調(diào)用?

如何訪問Mongo?

如何安裝Mongo,并快速驗(yàn)證Mongo?

如何命令行插入、刪除、列表一個(gè)Collection?

有哪些訪問Mongo的Nodejs庫(kù),差別在哪里?

如何使用Await風(fēng)格的代碼做插入刪除和列表?

如何獲取插入項(xiàng)目后的項(xiàng)目ID?

如何使用ObjectId查詢對(duì)應(yīng)的項(xiàng)目?

如何訪問網(wǎng)絡(luò),包括curl、axios、fetch等幾種方法?

如何提交Get請(qǐng)求?

如何提交Put請(qǐng)求?

如何在Body內(nèi)提交json?

如何指定請(qǐng)求頭內(nèi)容類型為json?

如何獲取響應(yīng)中的Json數(shù)據(jù)?

參考文章

這個(gè)App雖然很小,但是并非一次寫成的,我之前已經(jīng)完成了若干個(gè)更加細(xì)小的、特定方面的文章,也寫了一些代碼。當(dāng)然外部參考肯定也是不少,特別是Medium和Stack Overflow網(wǎng)站,對(duì)我支持很多。這里列出關(guān)鍵的一些參考文章。

這里會(huì)使用vuex管理狀態(tài),之前有寫過文章,到底Vuex是什么,閱讀量和評(píng)價(jià)還不少呢。當(dāng)然,我舉例的案例,有些勉強(qiáng),為了用而用,實(shí)際案例并不需要Vuex,使用組件內(nèi)狀態(tài)即可。

使用Mongodb存儲(chǔ)和提供后端CRD服務(wù)

使用Nodejs搭建{id,name}的對(duì)象的后端CRD服務(wù)。計(jì)劃參考之前我自己的2篇文章和一個(gè)SO關(guān)于如何在AJAX內(nèi)創(chuàng)建PUT請(qǐng)求的問答

準(zhǔn)備 JSON 服務(wù)器并訪問它

vuejs api server開發(fā)小抄

Axios PUT request to serveraxios-put-request-to-server

使用Fecth|Axios訪問后端CRD服務(wù)。此文章列舉了幾種訪問網(wǎng)絡(luò)庫(kù)的方法,給了我一個(gè)全局的視野,因此我很受益于它。[Fetch vs. Axios.js for making http requests

](https://medium.com/@thejasonf...

使用buefy的美化組件的方法。這個(gè)很小眾了,因此就只能看看官方文檔了。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/108462.html

相關(guān)文章

  • 急速JavaScript全棧教程

    摘要:使用訪問后端服務(wù)使用的美化組件的方法整合全棧服務(wù)其中的指的是。所幸是在這個(gè)教程內(nèi),你不需要學(xué)習(xí)太多就可以把案例跑起來(lái)。另外一個(gè)組件負(fù)責(zé)顯示全部項(xiàng)目,并接受刪除事件,刪除指定的項(xiàng)目。它們分別是組件和組件這兩個(gè)組件的代碼實(shí)現(xiàn),分別在文件和內(nèi)。 自從一年前發(fā)布了Vuejs小書的電子書,也有些日子沒有碰過它們了,現(xiàn)在因?yàn)轫?xiàng)目的緣故,需要使用JavaScript全棧開發(fā)。所以,我得把這個(gè)全棧環(huán)境...

    xingqiba 評(píng)論0 收藏0
  • 預(yù)告:JavaScript模塊全覽

    摘要:之前寫的文章急速全棧教程得到了不錯(cuò)的閱讀量,霸屏掘金頭條天,點(diǎn)贊過千,閱讀近萬(wàn),甚至還有人在評(píng)論區(qū)打廣告,可見也是一個(gè)小小的生態(tài)了。今天看到的霸屏的,也是講全棧的,見參考文章接下來(lái)要寫的是模塊。全局命名污染和命名沖突依賴管理。 之前寫的文章急速Js全棧教程得到了不錯(cuò)的閱讀量,霸屏掘金頭條3天,點(diǎn)贊過千,閱讀近萬(wàn),甚至還有人在評(píng)論區(qū)打廣告,可見也是一個(gè)小小的生態(tài)了;)??磥?lái)和JS全棧有關(guān)...

    focusj 評(píng)論0 收藏0
  • 您的四月份前端補(bǔ)給包已到,請(qǐng)查收~

    摘要:版本發(fā)布月日,官博發(fā)文宣告正式發(fā)布。官方文檔提供了如下的示例終端上的輸出熱門文章我在阿里云做前端抓住我們核心的競(jìng)爭(zhēng)力,并同時(shí)發(fā)現(xiàn)業(yè)務(wù)中的問題,跨端推進(jìn)解決,這是最好的出路。 showImg(https://segmentfault.com/img/remote/1460000019038442); 【阿里云 TXD 前端月刊】- 熱門前端技術(shù)快報(bào),聚焦業(yè)界新視界;前端領(lǐng)域急速發(fā)展的節(jié)奏...

    wushuiyong 評(píng)論0 收藏0
  • 您的四月份前端補(bǔ)給包已到,請(qǐng)查收~

    摘要:版本發(fā)布月日,官博發(fā)文宣告正式發(fā)布。官方文檔提供了如下的示例終端上的輸出熱門文章我在阿里云做前端抓住我們核心的競(jìng)爭(zhēng)力,并同時(shí)發(fā)現(xiàn)業(yè)務(wù)中的問題,跨端推進(jìn)解決,這是最好的出路。 showImg(https://segmentfault.com/img/remote/1460000019038442); 【阿里云 TXD 前端月刊】- 熱門前端技術(shù)快報(bào),聚焦業(yè)界新視界;前端領(lǐng)域急速發(fā)展的節(jié)奏...

    amc 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<