自從一年前發佈了Vuejs小書的電子書,也有些日子沒有碰過它們了,如今由於項目的緣故,須要使用JavaScript全棧開發。因此,我得把這個全棧環境搭建起來。javascript
整個系列,是會採用個人一向風格,就是不疾不徐,娓娓道來,學習完畢,你能夠掌握我提到的全系列的知識,而且獲得一個能夠直接拷貝的代碼模板,並把它用到你的項目中。css
完成操練下來,得半小時到一個小時吧。騰出你的時間再來學習。html
不少人是看不起JavaScript開發的。這玩意不就是玩具嘛,一些腳本和標籤而已。說這話的時候,他們多是就翹起二郎腿的,或者抱着膀子的。前端
然而,前端由於還在快速發展,所以不少東西在變,構造環境的選擇比較多,技術種類也很多,不少事情得本身作。所以它其實並不比那麼簡單的。這篇文章的圖,能夠窺視到前端複雜的一角了。Modern Frontend Developer in 2018。vue
我看了很多資料,不少都是講解這張圖中的一個技術,講解全棧的確定是有的,可是每每過於複雜。本文試圖經過一組文章,把JavaScript的全棧開發作一個全景的展現,力圖使用一個案例,全須全尾的貫穿整個系列,便於初學者對技術的急速理解。java
因此,文章會包括這些:node
其中的CRD指的是Create、Read、Delete。針對的數據對象,就是一個Todo對象,看起來是這樣的:webpack
{id:1,subject:"Loving"}ios
若是是多個數據對象,看起來是這樣的:git
[ {id:1,subject:"Loving"}, {id:1,subject:"Writing"}, {id:1,subject:"Preying"} ]
這個看起來很簡單平實的JS對象,會在一組組函數、模塊和對象之間流動,甚至跨越網絡邊界,從內存到硬盤。它會被存儲在Mongodb內,也會從Mongodb提取出來,在用戶界面、HTTP客戶端,HTTP服務器傳遞。
整個App看起來就是一臺機器,能夠說代碼在運轉這個機器,可是也不妨說是數據在驅動這個它。
咱們給本身命題,作一個TODO應用,它看起來是這樣的:
用戶能夠看到一個編輯框,和一個清單。
提及來搭建JS全棧開發環境,涉及到的東西真的很多。大的選擇是這樣的:
大的選擇定了,小的配套也就跟着來,前端配套的話須要一系列的技術,特別是前端,對應着Vuejs,配套管理路由、狀態、組件的都有相應的技術手段。本身搭配的話,仍是很是麻煩的。
幸虧Vuejs還有一個前端腳手架工具vue-cli,它能夠把以上的組件整合起來到一個工程內。一個最爲基礎的vue-cli工程腳手架的建立,如今得須要160M左右的空間佔用。在個人電腦和網絡狀況下,須要2分半的時間纔會完成。
爲了給前端開發提供工具鏈和開發便利性,咱們經常須要webpack&babel。有了它們,就可使用ES6的語法,以及代碼更新後自動刷新等。這些都是很是便利的特性,用了就離不開的。有了vue-cli,對webpack&babel的瞭解能夠降到最低,可是也不能不學,稍微須要一些定製的配置,也是必需要掌握的,起碼得知道如何啓動一個開發服務器,已經發布build,還有把前端服務通過proxyChain跳轉到後端服務去等等。所幸是在這個教程內,你不須要學習太多就能夠把案例跑起來。
接下來看後端,通常習慣就是使用Nodejs+Express.js的搭配。這個沒有多少說的,都是老東西了。爲了訪問Mongodb,也須要一套框架,基於Callback的,或者基於Promise+Await+Async的,也是須要選擇的。
爲了便於理解,我會用一個最小的案例完成整個開發過程,就是案例在現實中並不存在,可是也是有用的,就是你能夠當它們是模板,直接拷貝代碼,而後填充你的內容。天下代碼一大抄嘛,沒有什麼不對的,畢竟這些寫代碼是最快的。這個案例的數據模型就是對一個{id,name}的對象進行CRD(建立刪除列表)。
安裝環境相對簡單,特別是若是使用Mac OS X的話。有一些工具鏈能夠幫助快速搭建環境。固然Windows也並很少麻煩就是了,它經常提供的是一個安裝程序,大部分時間,你須要的就是點擊下一步。
這裏以MAC爲例,講解安裝。
安裝和運行Mongodb Daemon:
brew install mongodb mongodb
訪問驗證,首先執行Mongodb Shell:
mongo
輸入命令,查詢數據庫清單:
> show dbs local 0.000GB
可以看到這些信息,說明mongodb安裝成功。
安裝並驗證:
$brew install nodejs $node -v 10.7.0
可以看到這些信息,說明Node.js安裝成功。
首先安裝vue-cli,方法和通常的NPM模塊同樣的,咱們安裝的版本是3.0:
npm i @vue/cli
查看版本:
vue -V 3.0.0
看到以下信息,說明成功。而後建立App的腳手架代碼:
vue create todoapp
注意,在此建立過程當中,命令行會指示你作出選擇,咱們會選擇Manual select feature,而後選擇router和vuex,其餘不選。而後並執行此代碼:
cd todoapp npm run serve
能夠在瀏覽器中訪問localhost:8080看到Vue的啓動畫面。說明建立腳手架成功。
此時,vue-cli已經幫助安裝了vuex和router的模塊依賴。本節一次性的安裝所有剩餘的所有NPM依賴,省得之後用一個安裝一個,麻煩並且囉嗦。
npm install buefy --save npm install axios --save
buefy是一個基於Bulma的Vuejs用戶界面組件庫。此次的UI的CSS方案,使用Bulma,Vuejs若是想要以定製組件的形式去使用它的話,那麼須要安裝Buefy模塊。實際上,我研究過Bulma和Bootstrap,還寫了一本免費的電子書,我以爲Bulma相對於Bootstrap的優點在於1.不依賴任何JS框架2.用戶接口設計更加簡明。這就是我如今選擇使用Bulma的緣由。
Axios是一個封裝了HTTPClient的庫,提供了promise接口。咱們使用它訪問後端的HTTP Server的數據。以前提到的數據對象,就是由Axios提取到客戶端,也會是經過Axios把數據對象提交到服務器的。
首先,咱們從狀態開始。咱們以前提到的Vuex,是Vuejs管理狀態的官方插件。所謂的狀態,就是應用程序的數據對象們。也就是咱們提到的Todo對象和Todo對象集合。咱們在App用戶界面上看到的不少數據都是來自於狀態對象。狀態對象在src/store.js。不只僅是的應用狀態信息,還有和對這些的操做函數。既然須要一個todo項目清單,所以應該加入以下代碼:
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屬性,就是咱們的主要的數據對象了。state.msg這是提供了一個App的標題字符串。mutations屬性內是對數據修改提供的方法,好比
有時候,對數據的修改多是比較消耗時間的,所以爲了不阻塞客戶端的主線程,這個對象也提供了異步的方法,actions對象內就是對應修改操做的異步方法,這裏的方法功能上和mutations一致,可是是異步的。Vuex提供了相似:
context.commit()
的語法,提供和actions和mutations方法的對接。第一個參數是mutations的方法名稱,以後的參數最爲mutations方法的參數傳遞給mutations方法。
特別說下,mutations內的add()方法,其中用戶界面會提供一個Todo.subject屬性,而ID是須要自動生成的,咱們這裏臨時使用subject的值做爲id,就是一個偷懶,只要subject不要輸入重複,也暫時能夠矇混過關。由於知道本項目內的後臺存儲會採用Mongodb,在Mongodb內插入一個新的對象後,會自動生成一個ID,咱們的Todo對象的id會採用這個ID。這裏就沒有必要本身生成了。
在src/views/home.vue內,粘貼爲以下代碼:
<template> <div class="home"> <h1>{{msg}}</h1> <NewTodo></NewTodo> <TodoList></TodoList> </div> </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的解說。
就是說,咱們這個Todo App劃分爲爲兩個組件,其中一個組件負責顯示編輯框,並接受回車事件,把新的Todo項目加入到應用狀態內。另一個組件負責顯示所有Todo項目,並接受刪除事件,刪除指定的Todo項目。它們分別是NewTodo組件和TodoList組件:
<NewTodo></NewTodo> <TodoList></TodoList>
這兩個組件的代碼實現,分別在文件src/components/NewTodo.vue
和src/components/TodoList.vue
內。NewTodo代碼:
<template> <div class="home"> <form @submit.prevent="add1"> <input type="text" name="newTodo" placeholder="new todo" v-model="newtodo"> </form> </div> </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> <div 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> </div> </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文件內,添加以下代碼,引入Buefy:
import Buefy from 'buefy' import 'buefy/lib/buefy.css' Vue.use(Buefy)
如今可使用Buefy組件了。咱們能夠把NewTodo組件內的標準的input變成組件化的input,把標籤換成b-input便可。代碼以下:
<b-input type="text" name="newTodo" placeholder="new todo" v-model="newtodo"></b-input>
如今看瀏覽器,input變成了比較有吸引力的Bulma風格的控件了。
訪問網絡使用axios。須要首先找到src/home.vue在代碼的開頭部分引用此庫:
import axios from 'axios'
在Vue單頁組件內使用此庫了。好比在src/home.vue內代碼對象中加入新方法:
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)) }
咱們來看看適應效果。啓動cli-service:
npm run serve
而後打開瀏覽器,輸入地址localhost:8080
,若是能夠在瀏覽器內看到咱們指望的用戶界面,而且均可以看到console打印了Bitcoin,那麼就說明用戶界面代碼和初步的訪問HTTP網絡的axios代碼以及狀態管理功能都是成功了的。
如今,咱們已經能夠看到UI了,可是用戶界面內的數據來自於客戶端,而不是來自於服務器。咱們的數據固然應該來源於服務器的了。所以咱們須要啓動給一個本身的服務器,這個服務器能夠接受客戶在界面上錄入的新的Todo對象,也能夠提供後端數據庫內的Todo清單。
爲了測試的目的,經常須要準備一個todo應用的後臺JSON服務,能夠經過HTTP方式,提供todo項目的增長刪除修改和查詢。
這樣的服務器,使用了nodejs做爲服務器端,而且使用了兩個node模塊,可使用npm安裝它們:
npm install express body-parser
body-parser是一箇中間件,能夠解析請求內容並把解析結果放到req.body屬性內。最多見的作法就是解析json內容。
代碼以下(文件名爲: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) })
可使用命令執行:
node jsonserver.js
能夠經過curl命令驗證服務的有效性:
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
建立一個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>
能夠提供建立,刪除,列表的測試,其中部分結果在console內顯示。
提及來,JS訪問HTTP的庫真的是很多,這裏 提到的庫都有9種。其中的fetch api使用起來很是的簡潔趁手,但是它不支持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.
相比fetch,使用axios必須依賴於外部文件。爲了方便,咱們直接使用unpkg網站提供的庫文件。
axios的語法和fetch的大同小異,看着也是比較簡潔美觀的。如下代碼,把create和remove函數的內部實現換掉,其餘不變。
<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>
如今,後端也是能夠跑起來了的。
每次執行命令:npm run serve,都會啓動vue定製腳手架的服務器代碼,它會提供很多方便開發的特性。可是我但願一部分URL能夠轉發到我本身的服務器內。好比把全部的/api打頭的URL所有轉過來。只要在工程根目錄內加入此文件vue.config.js
,錄入以下內容:
module.exports = { devServer: { proxy: { "/api": { target: "http://localhost:8181", secure: false } } } };
咱們本身的測試服務器在這裏:
var http = require('http'); http.createServer(function (req, res) { res.write('Hello World!'); res.end(); }).listen(8181);
咱們的定製服務器,就能夠監聽8181的本地機器端口,等待客戶端的匹配的URL轉發過來,並轉發咱們服務器的響應代碼到客戶端。
可是正常開發過程當中,是須要本身的服務器端代碼的,如何在利用Vue腳手架服務器的方便性的基礎上,加入本身的代碼呢。作法是另外作一個定製的服務器,而後讓vue定製腳手架的服務器轉發URL到此服務器。
爲了測試的目的,咱們把函數mounted
修改成:
mounted(){ var url = '/api/1' axios ({ url:url, method: 'get', }) .then( res => {console.log(res.data)} ) .catch( err => console.error(err)) }
便可看到瀏覽器console內打印Hello World!
。
咱們已經經過配置,要求cli-service轉移所有api打頭的URL到App Server。只要在工程根目錄內加入此文件vue.config.js
,錄入以下內容:
module.exports = { devServer: { proxy: { "/api/*": { target: "http://localhost:8181/api", secure: false } } } };
如今,咱們能夠修改前端的Axios使用代碼,分別替代前端代碼的數據裝入、數據刪除、數據添加的代碼,讓這些代碼能夠支持網絡操做。爲了不網絡操做代碼和業務邏輯代碼混合在一塊兒,我決定包裝三個網絡操做函數,並把它們放置到src/store.js文件內:
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)) }
分別完成添加、刪除、查找的任務,當完成工做後,都會調用一個callback函數,在此函數內,能夠消費訪問網絡後獲得的響應數據。
而後把文件內src/store.js的mutations對象改爲以下代碼:
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內加入一個新函數,並經過mapActions引入src/store.js的load()函數到當前對象內:
methods:{ ...mapActions([ 'remove','load' ]) }, mounted(){ this.load() }
以便在啓動後調用this.load()裝入它。
要完成後端到數據庫的整合,須要作以下的修改:
所以,如今咱們須要添加三個函數,分別作針對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)); }
這三個函數的功能和使用方法以下:
這裏的代碼自己並不複雜,可是由於涉及到如何訪問Mongodb,所以涉及到比較多的概念,這裏不作具體的解釋,你能夠先把它們用起來。若是完成了本教程後,但願對Mongodb的訪問作具體瞭解的話,能夠查看後文附錄的「Mongodb快速參考」。
而且和App Server對應的代碼接駁,把原來的路由代碼替換以下:
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() }) })
本文會把一個對象todo對象(有屬性{id,name})存儲到Mongodb,作查詢刪除的測試(Create Remove Delete = CRD)。這個測試包括使用Mongodb Shell,使用CallBack古典風格的訪問代碼,以及使用Await/Async的現代風格的代碼。完成這個這個驗證後,就能夠掌握最初步的Mongodb了。
我使用的Nodejs是10.7 。操做系統環境爲Mac OS X High Sierra。
安裝和運行Mongodb Daemon
brew install mongodb mongodb
首先執行Mongodb Shell:
mongo
輸入命令,查詢數據庫清單:
> show dbs local 0.000GB
建立一個數據庫
use todos
(若database不存在,則會建立一個,此時若不作任何操做直接退出,則MongoDB會刪除該數據庫)
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})
刪除數據庫
db.todo.drop()
使用nodejs執行相似Shell對對象的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(); }); }); }); })
代碼很是簡單,無需更多解釋。此代碼使用了mongodb模塊,須要首先安裝:
npm init -y npm i mongodb --save
而後使用node index.js
運行便可看到效果:
Database created! Number of documents inserted: 2 [ { _id: 5b72ab9e3245f169ef5f43d2, id: 1, name: 'reco' }, { _id: 5b72ab9e3245f169ef5f43d3, id: 2, name: 'rita' } ] document deleted
使用Await/Async特性,能夠有效的減小代碼中的回調地獄現象。一樣的功能,可使用這樣的代碼:
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));
執行此代碼,輸出以下:
Number of documents inserted: 2 [ { _id: 5b72ae8a1c674a6ac1c5aa6e, id: 1, name: 'reco' }, { _id: 5b72ae8a1c674a6ac1c5aa6f, id: 2, name: 'rita' } ] document deleted
Vuejs自己要學的還真很多,這也是我會編寫一本書來介紹它的緣由。可是說到入門的話,我卻是寫過一篇簡單的介紹文章。不妨去閱讀看看。
上面的文章,也就對Vuejs瞭解個大概,提起一個興趣。若是真的想要學習Vuejs的話,仍是得看書的。這裏也放一個個人書的廣告,歡迎參閱。
麻雀雖小五臟俱全,雖然是一個小小的示例的應用,可是每樣技術也都須要用到,遇到的技術問題也是要一個個的解決的。這裏列出我遇到的問題,做爲索引,也算記錄我在寫做過程當中解決的問題,也能夠做爲你學習完畢後的一個查漏補缺的索引,在這裏從新看到問題,而後使用代碼驗證本身對問題的理解和學習。
這個App雖然很小,可是並不是一次寫成的,我以前已經完成了若干個更加細小的、特定方面的文章,也寫了一些代碼。固然外部參考確定也是很多,特別是Medium和Stack Overflow網站,對我支持不少。這裏列出關鍵的一些參考文章。
](https://medium.com/@thejasonf...