久久久久久久视色,久久电影免费精品,中文亚洲欧美乱码在线观看,在线免费播放AV片

<center id="vfaef"><input id="vfaef"><table id="vfaef"></table></input></center>

    <p id="vfaef"><kbd id="vfaef"></kbd></p>

    
    
    <pre id="vfaef"><u id="vfaef"></u></pre>

      <thead id="vfaef"><input id="vfaef"></input></thead>

    1. 站長(zhǎng)資訊網(wǎng)
      最全最豐富的資訊網(wǎng)站

      直擊JavaScript全棧教程

      直擊JavaScript全棧教程

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

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

      前端的復(fù)雜度

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

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

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

      大綱

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

      1. 使用Vuejs腳手架,快速搭建一個(gè)CRD用戶(hù)界面。會(huì)使用vuex管理狀態(tài),使用vue-router管理路由。
      2. 使用Mongodb存儲(chǔ)和提供后端CRD服務(wù)。
      3. 使用Nodejs搭建后端CRD服務(wù)。
      4. 使用Fecth|Axios訪問(wèn)后端CRD服務(wù)
      5. 使用bulfy的美化組件的方法
      6. 整合全棧服務(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)存到硬盤(pán)。它會(huì)被存儲(chǔ)在Mongodb內(nèi),也會(huì)從Mongodb提取出來(lái),在用戶(hù)界面、HTTP客戶(hù)端,HTTP服務(wù)器傳遞。

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

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

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

      直擊JavaScript全棧教程

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

      1. 在編輯框內(nèi)加入新的todo項(xiàng)目,按回車(chē)即可加入到列表
      2. 列表內(nèi)每個(gè)項(xiàng)目有一個(gè)按鈕,點(diǎn)擊按鈕,可以刪除當(dāng)前項(xiàng)目

      環(huán)境要求

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

      1. 前端采用Vuejs
      2. 后端采用Nodejs
      3. 存儲(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

      1. vue-router,前端路由管理
      2. vuex,前端數(shù)據(jù)管理,專(zhuān)業(yè)一點(diǎn)的說(shuō)法,就是狀態(tài)管理,這些數(shù)據(jù),可能是屬性,數(shù)組,對(duì)象等等,可以跨組件訪問(wèn),而不像是data函數(shù)那樣提供的數(shù)據(jù)只能被本組件訪問(wèn),可以想到,稍微大一點(diǎn)的前端工程都必須前端狀態(tài)管理的。
      3. axios,前端HTTP訪問(wèn),以promise的形式,封裝了類(lèi)似fetch,AJAX的能力
      4. buefy,前端微型框架,可以使用自定義標(biāo)簽使用自定義組件,并且CSS框架為Bulma
      5. Bulma,盡管使用了微框架,只是讓對(duì)CSS framework的了解降到最低,但是不是說(shuō)就不需要了解了。還是得學(xué)習(xí)的。Bulma相對(duì)于老牌的Bootstrap,是不需要依賴(lài)于JS框架,也沒(méi)有任何JS代碼,因此可以和任何一框架很好的結(jié)合,比如這里的Vuejs。這就是我選擇它的原因

      后端 cli-service

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

      App Server + Mongodb

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

      為了便于理解,我會(huì)用一個(gè)最小的案例完成整個(gè)開(kāi)發(fā)過(guò)程,就是案例在現(xiàn)實(shí)中并不存在,但是也是有用的,就是你可以當(dāng)它們是模板,直接拷貝代碼,然后填充你的內(nèi)容。天下代碼一大抄嘛,沒(méi)有什么不對(duì)的,畢竟這些寫(xiě)代碼是最快的。這個(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

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

      mongo

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

      > show dbs local           0.000GB

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

      Node.js

      安裝并驗(yàn)證:

      $brew install nodejs $node -v 10.7.0

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

      開(kāi)始前端編碼

      安裝編碼環(huán)境

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

      npm i @vue/cli

      查看版本:

      vue -V 3.0.0

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

      vue create todoapp

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

      cd todoapp npm run serve

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

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

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

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

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

      前端編碼

      首先,我們從狀態(tài)開(kāi)始。我們之前提到的Vuex,是Vuejs管理狀態(tài)的官方插件。所謂的狀態(tài),就是應(yīng)用程序的數(shù)據(jù)對(duì)象們。也就是我們提到的Todo對(duì)象和Todo對(duì)象集合。我們?cè)贏pp用戶(hù)界面上看到的很多數(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屬性?xún)?nèi)是對(duì)數(shù)據(jù)修改提供的方法,比如

      1. 我們需要添加一個(gè)todo,使用add()方法,相應(yīng)的
      2. 刪除一個(gè)todo,使用remove()方法
      3. 刷新一個(gè)todo列表,就會(huì)使用load()方法

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

      context.commit()

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

      特別說(shuō)下,mutations內(nèi)的add()方法,其中用戶(hù)界面會(huì)提供一個(gè)Todo.subject屬性,而ID是需要自動(dòng)生成的,我們這里臨時(shí)使用subject的值作為id,就是一個(gè)偷懶,只要subject不要輸入重復(fù),也暫時(shí)可以蒙混過(guò)關(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。這里就沒(méi)有必要自己生成了。

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

      <template>   <p class="home">     <h1>{{msg}}</h1>     <NewTodo></NewTodo>     <TodoList></TodoList>   </p> </template> <script> import NewTodo from '@/components/NewTodo.vue' import TodoList from '@/components/TodoList.vue' import {mapState,mapActions} from 'vuex' export default {   name: 'home',   computed:mapState(['todos','msg']),   components: {     TodoList,NewTodo   },   data(){       return{newtodo:''}   },   methods:{       ...mapActions([       'remove',       'add'     ]),       add1:function(){           this.add(this.newtodo)           this.newtodo = ''       }   } } </script>

      …mapState,mapActions的解說(shuō)。

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

      <NewTodo></NewTodo> <TodoList></TodoList>

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

      <template>   <p class="home">     <form @submit.prevent="add1">         <input type="text" name="newTodo" placeholder="new todo" v-model="newtodo">     </form>   </p> </template> <script> import {mapState,mapActions} from 'vuex' export default {   name: 'newtodo',   computed:mapState(['todos','msg']),   data(){       return{newtodo:''}   },   methods:{       ...mapActions([       'add'     ]),       add1:function(){           this.add(this.newtodo)           this.newtodo = ''       }   } } </script>

      TodoList代碼:

      <template>   <p class="hello">     <ul>       <li v-for="(todo,index) in todos" v-bind:key="todo.id">         {{todo.subject}}<button @click="remove(todo.id)" class="rm">remove</button>       </li>     </ul>   </p> </template> <script> import {mapState,mapActions} from 'vuex' export default {   name: 'todolist',   computed:mapState(['todos','msg']),   components: {   },   methods:{     ...mapActions([       'remove','reload'     ])   },   mounted(){     this.reload()   } } </script> <style scoped> </style>

      在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即可。代碼如下:

      <b-input type="text" name="newTodo" placeholder="new todo" v-model="newtodo"></b-input>

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

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

      后端編碼

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

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

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

      npm install express body-parser

      body-parser是一個(gè)中間件,可以解析請(qǐng)求內(nèi)容并把解析結(jié)果放到req.body屬性?xún)?nèi)。最常見(jiàn)的做法就是解析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)證

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

      1. GET操作

         $curl http://localhost:8081/todo/1  $curl http://localhost:8081/todos
      2. DELETE操作

          $ curl -X "DELETE" http://localhost:8081/api/todo/1
      3. 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代碼同一目錄,代碼如下:

      <a href='/todos'>todos</a> <a href='/todo/1'>todo/1</a> <button onclick='remove()'>remove 1</button> <button onclick='create()'>create</button> <script>   function remove(){     fetch (       '/api/todo/1',       {         method: 'DELETE',       }     )     .then( res => console.log(res.json()))     .catch( err => cosole.error(err))   }   function create(){     fetch (       '/api/todo',       {         method: 'POST',         headers: {           'Content-Type': 'application/json'         },         body: JSON.stringify({id: "4", subject: "s4"})       }     )     .then( res => console.log(res.json()))     .catch( err => cosole.error(err))   } </script>

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

      說(shuō)起來(lái),JS訪問(wèn)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訪問(wèn)方法

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

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

      <script src="https://unpkg.com/axios/dist/axios.min.js"></script> <a href='/todos'>todos</a> <a href='/todo/1'>todo/1</a> <button onclick='remove()'>remove 1</button> <button onclick='create()'>create</button> <script>   function remove(){     axios ({         url:'/api/todo/1',         method: 'DELETE',     })     .then( res => console.log(res.json()))     .catch( err => cosole.error(err))   }   function create(){     axios ({         method: 'POST',         url:'/api/todo',         headers: {           'Content-Type': 'application/json'         },         data: JSON.stringify({subject: "s4"})     })     .then( res => console.log(res.json()))     .catch( err => cosole.error(err))   } </script>

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

      整合:前端后端

      建立cli-service到App Server的通道

      每次執(zhí)行命令:npm run serve,都會(huì)啟動(dòng)vue定制腳手架的服務(wù)器代碼,它會(huì)提供不少方便開(kāi)發(fā)的特性。但是我希望一部分URL可以轉(zhuǎn)發(fā)到我自己的服務(wù)器內(nèi)。比如把所有的/api打頭的URL全部轉(zhuǎn)過(guò)來(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)聽(tīng)8181的本地機(jī)器端口,等待客戶(hù)端的匹配的URL轉(zhuǎn)發(fā)過(guò)來(lái),并轉(zhuǎn)發(fā)我們服務(wù)器的響應(yīng)代碼到客戶(hù)端。

      但是正常開(kāi)發(fā)過(guò)程中,是需要自己的服務(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)通過(guò)配置,要求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èn)網(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ù),并通過(guò)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ù)的整合,需要做如下的修改:

      1. 原本在后端App Server內(nèi)Todo數(shù)據(jù)數(shù)組,現(xiàn)在應(yīng)該從Mongodb獲得
      2. 原本在添加Todo對(duì)象的時(shí)候只是添加到AppServer對(duì)象內(nèi),現(xiàn)在需要同時(shí)寫(xiě)入Mongodb
      3. 原本在刪除時(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ù)的功能和使用方法如下:

      1. 函數(shù)allDoc會(huì)從Mongodb內(nèi)獲取全部todo集合,并通過(guò)callback傳遞這個(gè)集合給調(diào)用者函數(shù)。
      2. 函數(shù)deleteDoc會(huì)從Mongodb內(nèi)刪除指定id的todo條目,完成刪除后,通過(guò)callback通知調(diào)用者。
      3. 函數(shù)deleteDoc會(huì)向Mongodb內(nèi)添加一個(gè)todo條目,完成添加后,通過(guò)callback通知調(diào)用者,并傳遞新的todo對(duì)象給調(diào)用者。

      這里的代碼本身并不復(fù)雜,但是因?yàn)樯婕暗饺绾卧L問(wèn)Mongodb,因此涉及到比較多的概念,這里不做具體的解釋?zhuān)憧梢韵劝阉鼈冇闷饋?lái)。如果完成了本教程后,希望對(duì)Mongodb的訪問(wèn)做具體了解的話,可以查看后文附錄的“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,做查詢(xún)刪除的測(cè)試(Create Remove Delete = CRD)。這個(gè)測(cè)試包括使用Mongodb Shell,使用CallBack古典風(fēng)格的訪問(wèn)代碼,以及使用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

      訪問(wèn)驗(yàn)證

      首先執(zhí)行Mongodb Shell:

      mongo

      輸入命令,查詢(xún)數(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"})

      查詢(xún) :

      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方式訪問(wèn)Mongodb

      使用nodejs執(zhí)行類(lèi)似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ú)需

      贊(0)
      分享到: 更多 (0)
      網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)