1. 頁面的佈局 Vue中使用Bootstrap搭頁面 1. 安裝 1. npm install bootstrap@3.3.7 -S 2. 使用 1. import 'bootstrap/dist/css/bootstrap.min.css' 2. 組件的使用 1. 組件的定義 1. 新建一個xx.vue 2. 在裏面定義三個區域(template、script、style) 3. export default { name: "Note", // 告訴別人怎麼引用我 components: { // 告訴別人你加載我這個組建的時候 先要去找 NoteList NoteList, Zsq } } 2. 組件的使用 1. 導入 import NoteList from '@/components/NoteList.vue' 2. 使用 <NoteList></NoteList> 3. 組件的傳值 1. 父組件 -> 子組件 1. 父組件: v-bind:xx='值' 2. 子組件:使用props聲明 2. 子組件 -> 父組件 1. 子組件:$emit('事件名', 參數) 2. 父組件:v-on:事件名='方法名(參數)' 3. 任意組件間傳值 1. bus 2. VueX 3. marked的使用 1. 安裝 npm install marked --save 2. 使用 import marked from 'marked' marked(內容)
1. npm install xx -D --> 安裝當前項目用到的開發環境(好比webpack等) 2. npm install xx -S(--save) --> 安裝當前項目用到的依賴包(線上運行必需要有的包) 3. npm install xx -g --> 全局安裝,安裝完以後在cmd能夠直接當命令行工具使用的
安裝jquery依賴css
npm install jquery –save
進入目錄my-project\buildhtml
修改2處webpack.base.conf.js文件前端
//第一處,引入webpack var webpack = require('webpack')
第二處vue
// 第二處配置jquery插件 plugins: [ new webpack.ProvidePlugin({ $: "jquery", jQuery: "jquery", jquery: "jquery", "window.jQuery": "jquery" }) ],
webpack.base.conf.js完整代碼以下:node
'use strict' const path = require('path') const utils = require('./utils') const config = require('../config') const vueLoaderConfig = require('./vue-loader.conf') function resolve (dir) { return path.join(__dirname, '..', dir) } //第一處,引入webpack var webpack = require('webpack') module.exports = { context: path.resolve(__dirname, '../'), entry: { app: './src/main.js' }, output: { path: config.build.assetsRoot, filename: '[name].js', publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath }, resolve: { extensions: ['.js', '.vue', '.json'], alias: { 'vue$': 'vue/dist/vue.esm.js', '@': resolve('src'), } }, // 第二處配置jquery插件 plugins: [ new webpack.ProvidePlugin({ $: "jquery", jQuery: "jquery", jquery: "jquery", "window.jQuery": "jquery" }) ], module: { rules: [ { test: /\.vue$/, loader: 'vue-loader', options: vueLoaderConfig }, { test: /\.js$/, loader: 'babel-loader', include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')] }, { test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, loader: 'url-loader', options: { limit: 10000, name: utils.assetsPath('img/[name].[hash:7].[ext]') } }, { test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, loader: 'url-loader', options: { limit: 10000, name: utils.assetsPath('media/[name].[hash:7].[ext]') } }, { test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, loader: 'url-loader', options: { limit: 10000, name: utils.assetsPath('fonts/[name].[hash:7].[ext]') } } ] }, node: { // prevent webpack from injecting useless setImmediate polyfill because Vue // source contains it (although only uses it if it's native). setImmediate: false, // prevent webpack from injecting mocks to Node native modules // that does not make sense for the client dgram: 'empty', fs: 'empty', net: 'empty', tls: 'empty', child_process: 'empty' } }
須要在哪一個頁面用,直接python
import jQuery from 'jquery'
若是須要全局使用,在mian.js中導入jquery
昨天的文章,已經介紹了使用第一種方式,來引入highlightwebpack
下面介紹第二種:ios
安裝highlight.js依賴git
npm install highlight.js –save
在須要的頁面,增長如下代碼
import Vue from 'vue' import marked from 'marked' import highlightjs from 'highlight.js' import 'highlight.js/styles/monokai-sublime.css' //樣式文件 // 註冊highlightjs指令 Vue.directive('highlightjs',function (el) { let blocks = el.querySelectorAll('pre code'); blocks.forEach((block)=>{ highlightjs.highlightBlock(block) }) }) /*語法高亮*/ marked.setOptions({ highlight: (code) => highlightjs.highlightAuto(code).value })
修改NoteEdit.vue,完整代碼以下:
<template> <div class="row"> <!-- 左邊的 textarea 區域開始 --> <div class="col-md-6 height600"> <div class="input-group"> <span class="input-group-addon" id="basic-addon1">標題</span> <input type="text" class="form-control" placeholder="請輸入標題" aria-describedby="basic-addon1"> </div> <!-- textarea --> <textarea class="my-textarea" v-model="content" > </textarea> </div> <!-- 左邊的 textarea 區域結束 --> <!-- 右邊的 展現區 區域開始 --> <div class="col-md-6 height600"> <div> <button class="btn btn-success">添加</button> </div> <!--展現原始html使用v-html--> <div class="right-box my-textarea" v-html="markedDownContent" > </div> </div> <!-- 右變的 展現 區域結束 --> </div> </template> <script> import Vue from 'vue' import marked from 'marked' //導入marked模塊,用來處理makedown語法 //Web代碼語法高亮庫 import highlightjs from 'highlight.js' import 'highlight.js/styles/monokai.css' //樣式文件 // 註冊highlightjs指令 Vue.directive('highlightjs',function (el) { let blocks = el.querySelectorAll('pre code'); blocks.forEach((block)=>{ highlightjs.highlightBlock(block) }) }) /*語法高亮*/ marked.setOptions({ highlight: (code) => highlightjs.highlightAuto(code).value }) export default { name: 'NoteEdit', data:function () { return { content:'' } }, //增長計算屬性 computed:{ markedDownContent:function(){ return marked(this.content) } } } </script> <style> .my-textarea { margin-top: 15px; height: 80%; width: 100% } .height600 { height: 600px; } .right-box { border: 1px solid grey } </style>
訪問網頁,測試一段代碼
和昨天個人寫的博客
http://www.javashuo.com/article/p-vdknzfav-v.html
用的是同一個樣式文件,可是效果不同
我我的以爲,仍是黑色背景比較好看!
若是已經改了NoteEdit.vue使用了第二種方式,請先還原成第一種方式!由於接下來的代碼,可能會產生影響!
修改NoteEdit.vue,使用v-model獲取用戶輸入
<template> <div class="row"> <!-- 左邊的 textarea 區域開始 --> <div class="col-md-6 height600"> <div class="input-group"> <span class="input-group-addon" id="basic-addon1">標題</span> <input v-model="title" type="text" class="form-control" placeholder="請輸入標題" aria-describedby="basic-addon1"> </div> <!-- textarea --> <textarea class="my-textarea" v-model="content" > </textarea> </div> <!-- 左邊的 textarea 區域結束 --> <!-- 右邊的 展現區 區域開始 --> <div class="col-md-6 height600"> <div> <button v-on:click='addNote' class="btn btn-success">添加</button> </div> <!--展現原始html使用v-html--> <div class="right-box my-textarea" v-html="markedDownContent" v-highlight > </div> </div> <!-- 右變的 展現 區域結束 --> </div> </template> <script> //導入marked模塊,用來處理makedown語法 import marked from 'marked' export default { name: 'NoteEdit', data:function () { return { title:'', //聲明title變量 content:'' } }, //增長計算屬性 computed:{ markedDownContent:function(){ return marked(this.content) } }, methods:{ addNote:function(){ alert(this.title); //獲取標題 } } } </script> <style> .my-textarea { margin-top: 15px; height: 80%; width: 100% } .height600 { height: 600px; } .right-box { border: 1px solid grey } </style>
刷新網頁,效果以下:
如今須要將輸入的標題,添加到左側的列表組中
查看NoteList.vue,發現左側的列表組變量都是在NoteList數組中,增長到這個數組就能夠了。
這就須要用到組件間的傳值。以前咱們學到,組件之間傳值,使用bus。可是如今不用bus了,用vuex
vuex就是一個倉庫
先引用vuex官網的話:
Vuex 是一個專爲 Vue.js 應用程序開發的狀態管理模式。它採用集中式存儲管理應用的全部組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。
狀態管理模式、集中式存儲管理 一聽就很高大上,蠻嚇人的。在我看來 vuex 就是把須要共享的變量所有存儲在一個對象裏面,而後將這個對象放在頂層組件中供其餘組件使用。這麼說吧,將vue想做是一個js文件、組件是函數,那麼vuex就是一個全局變量,只是這個「全局變量」包含了一些特定的規則而已。
在vue的組件化開發中,常常會遇到須要將當前組件的狀態傳遞給其餘組件。父子組件通訊時,咱們一般會採用 props + emit 這種方式。但當通訊雙方不是父子組件甚至壓根不存在相關聯繫,或者一個狀態須要共享給多個組件時,就會很是麻煩,數據也會至關難維護,這對咱們開發來說就很不友好。vuex 這個時候就很實用,不過在使用vuex以後也帶來了更多的概念和框架,需慎重!
Talk is cheap,Show me the code. 先來一段代碼間隔下這麼多的文字:
const store = new Vuex.Store({ state: { name: 'weish', age: 22 }, getters: { personInfo(state) { return `My name is ${state.name}, I am ${state.age}`; } } mutations: { SET_AGE(state, age) { commit(age, age); } }, actions: { nameAsyn({commit}) { setTimeout(() => { commit('SET_AGE', 18); }, 1000); } }, modules: { a: modulesA } }
這個就是最基本也是完整的vuex代碼;vuex 包含有五個基本的對象:
E:\python_script\Vue\my-project>npm install vuex -D
提示如下信息,表示成功
+ vuex@3.0.1 added 1 package from 1 contributor and audited 8829 packages in 44.575s found 1 moderate severity vulnerability run `npm audit fix` to fix them, or `npm audit` for details
修改mian.js,導入vuex,並定義一個大倉庫
// The Vue build version to load with the `import` command // (runtime-only or standalone) has been set in webpack.base.conf with an alias. import Vue from 'vue' import App from './App' import router from './router' import jQuery from 'jquery' import Vuex from 'vuex' Vue.use(Vuex) //使用vuex //定義一個大倉庫,用來存放項目組件中用到的數據 const store = new Vuex.Store({ state:{ noteList:[ '吃飯','睡覺','打豆豆' ] }, }) Vue.config.productionTip = false //Web代碼語法高亮庫 import hljs from 'highlight.js' import 'highlight.js/styles/monokai.css' //樣式文件 Vue.directive('highlight',function (el) { let blocks = el.querySelectorAll('pre code'); blocks.forEach((block)=>{ hljs.highlightBlock(block) }) }) /* eslint-disable no-new */ new Vue({ el: '#app', router, store:store, //將上面定義的大倉庫與vue實例創建聯繫 components: { App }, template: '<App/>' })
修改NoteList.vue,刪除原來的數組,調用大倉庫的數組
注意數據名的大小寫
<template> <div> <div class="list-group"> <!-- 在子組件聲明 我須要被傳入的參數 v-for="(note, index) in NoteList" : NoteList是一個數組,note是數組每個元素 v-bind:name=note : 子組件聲明,被傳入的參數爲name,值爲note,也就是數組的元素 v-bind:key=index : for循環vue推薦綁定key,key用來標示for循環的每一項 --> <NoteItem v-for="(note, index) in noteList" v-bind:name='note' v-bind:key="index" ></NoteItem> </div> </div> </template> <script> //導入NoteItem組件 import NoteItem from '@/components/NoteItem.vue' export default { name: 'NoteList', components: { NoteItem }, data:function(){ return { } }, computed:{ noteList:function () { //從當前的vue實例的大倉庫裏找筆記列表 return this.$store.state.noteList } } } </script> <style> </style>
刷新網頁,效果和以前是同樣的。
Vuex 使用單一狀態樹——是的,用一個對象就包含了所有的應用層級狀態。至此它便做爲一個「惟一數據源 (SSOT)」而存在。這也意味着,每一個應用將僅僅包含一個 store 實例。單一狀態樹讓咱們可以直接地定位任一特定的狀態片斷,在調試的過程當中也能輕易地取得整個當前應用狀態的快照。
單狀態樹和模塊化並不衝突——在後面的章節裏咱們會討論如何將狀態和狀態變動事件分佈到各個子模塊中。
那麼咱們如何在 Vue 組件中展現狀態呢?因爲 Vuex 的狀態存儲是響應式的,從 store 實例中讀取狀態最簡單的方法就是在計算屬性中返回某個狀態:
// 建立一個 Counter 組件 const Counter = { template: `<div>{{ count }}</div>`, computed: { count () { return store.state.count } } }
每當 store.state.count
變化的時候, 都會從新求取計算屬性,而且觸發更新相關聯的 DOM。
然而,這種模式致使組件依賴全局狀態單例。在模塊化的構建系統中,在每一個須要使用 state 的組件中須要頻繁地導入,而且在測試組件時須要模擬狀態。
Vuex 經過 store
選項,提供了一種機制將狀態從根組件「注入」到每個子組件中(需調用 Vue.use(Vuex)
):
const app = new Vue({ el: '#app', // 把 store 對象提供給 「store」 選項,這能夠把 store 的實例注入全部的子組件 store, components: { Counter }, template: ` <div class="app"> <counter></counter> </div> ` })
經過在根實例中註冊 store
選項,該 store 實例會注入到根組件下的全部子組件中,且子組件能經過 this.$store
訪問到。讓咱們更新下 Counter
的實現:
const Counter = { template: `<div>{{ count }}</div>`, computed: { count () { return this.$store.state.count } } }
修改NoteEdit.vue,使用push添加到大倉庫的筆記列表
<template> <div class="row"> <!-- 左邊的 textarea 區域開始 --> <div class="col-md-6 height600"> <div class="input-group"> <span class="input-group-addon" id="basic-addon1">標題</span> <input v-model="title" type="text" class="form-control" placeholder="請輸入標題" aria-describedby="basic-addon1"> </div> <!-- textarea --> <textarea class="my-textarea" v-model="content" > </textarea> </div> <!-- 左邊的 textarea 區域結束 --> <!-- 右邊的 展現區 區域開始 --> <div class="col-md-6 height600"> <div> <button v-on:click='addNote' class="btn btn-success">添加</button> </div> <!--展現原始html使用v-html--> <div class="right-box my-textarea" v-html="markedDownContent" v-highlight > </div> </div> <!-- 右變的 展現 區域結束 --> </div> </template> <script> //導入marked模塊,用來處理makedown語法 import marked from 'marked' export default { name: 'NoteEdit', data:function () { return { title:'', //聲明title變量 content:'' } }, //增長計算屬性 computed:{ markedDownContent:function(){ return marked(this.content) } }, methods:{ addNote:function(){ //取新添加的筆記標題 //向大倉庫的noteList添加筆記 this.$store.state.noteList.push(this.title) alert(this.title); //獲取標題 } } } </script> <style> .my-textarea { margin-top: 15px; height: 80%; width: 100% } .height600 { height: 600px; } .right-box { border: 1px solid grey } </style>
刷新網頁效果以下:
如今有一個問題,組件能直接修改大倉庫的值。若是組件繁多,倉庫的值出現了異常,不知道是哪一個組件更新的。因此vuex爲了解決這個問題,規定修改倉庫的值,必須在倉庫裏面執行才能夠!它提供一個方法Mutation
更改 Vuex 的 store 中的狀態的惟一方法是提交 mutation。Vuex 中的 mutation 很是相似於事件:每一個 mutation 都有一個字符串的 事件類型 (type) 和 一個 回調函數 (handler)。這個回調函數就是咱們實際進行狀態更改的地方,而且它會接受 state 做爲第一個參數:
const store = new Vuex.Store({ state: { count: 1 }, mutations: { increment (state) { // 變動狀態 state.count++ } } })
你不能直接調用一個 mutation handler。這個選項更像是事件註冊:「當觸發一個類型爲 increment
的 mutation 時,調用此函數。」要喚醒一個 mutation handler,你須要以相應的 type 調用 store.commit 方法:
store.commit('increment')
修改main.js,增長mutation
// The Vue build version to load with the `import` command // (runtime-only or standalone) has been set in webpack.base.conf with an alias. import Vue from 'vue' import App from './App' import router from './router' import jQuery from 'jquery' import Vuex from 'vuex' Vue.use(Vuex) //使用vuex //定義一個大倉庫,用來存放項目組件中用到的數據 const store = new Vuex.Store({ state:{ noteList:[ '吃飯','睡覺','打豆豆' ] }, mutations:{ //修改倉庫中狀態的惟一方法就是經過提交mutations ADDNOTE: function (state, note) { // 將新筆記數據添加到noteList(同步操做) state.noteList.push(note) }, } }) Vue.config.productionTip = false //Web代碼語法高亮庫 import hljs from 'highlight.js' import 'highlight.js/styles/monokai.css' //樣式文件 Vue.directive('highlight',function (el) { let blocks = el.querySelectorAll('pre code'); blocks.forEach((block)=>{ hljs.highlightBlock(block) }) }) /* eslint-disable no-new */ new Vue({ el: '#app', router, store:store, //將上面定義的大倉庫與vue實例創建聯繫 components: { App }, template: '<App/>' })
修改NoteEdit.vue,調用 store.commit 方法,來執行mian.js中的ADDNOTE方法
<template> <div class="row"> <!-- 左邊的 textarea 區域開始 --> <div class="col-md-6 height600"> <div class="input-group"> <span class="input-group-addon" id="basic-addon1">標題</span> <input v-model="title" type="text" class="form-control" placeholder="請輸入標題" aria-describedby="basic-addon1"> </div> <!-- textarea --> <textarea class="my-textarea" v-model="content" > </textarea> </div> <!-- 左邊的 textarea 區域結束 --> <!-- 右邊的 展現區 區域開始 --> <div class="col-md-6 height600"> <div> <button v-on:click='addNote' class="btn btn-success">添加</button> </div> <!--展現原始html使用v-html--> <div class="right-box my-textarea" v-html="markedDownContent" v-highlight > </div> </div> <!-- 右變的 展現 區域結束 --> </div> </template> <script> //導入marked模塊,用來處理makedown語法 import marked from 'marked' export default { name: 'NoteEdit', data:function () { return { title:'', //聲明title變量 content:'' } }, //增長計算屬性 computed:{ markedDownContent:function(){ return marked(this.content) } }, methods:{ addNote:function(){ //取新添加的筆記標題 //向大倉庫的noteList添加筆記 // this.$store.state.noteList.push(this.title) //不規範的寫法 this.$store.commit('ADDNOTE',this.title) } } } </script> <style> .my-textarea { margin-top: 15px; height: 80%; width: 100% } .height600 { height: 600px; } .right-box { border: 1px solid grey } </style>
刷新網頁,再次驗證添加功能是否正常!
如今添加的數組,是在內存中,不是在數據庫中。那麼須要用django框架,來搭建一隔後端應用,用來保存數據!
如今已經寫好了一個項目vue_backend,github地址以下:
https://github.com/987334176/MyNotes/tree/master/%E5%90%8E%E7%AB%AFDjango/vue_backend
注意:必須使用django 1.11版本才能啓動
必須安裝模塊django-cors-headers
pip3 install django-cors-headers
查看版本,確保版本爲1.11,已經安裝django-cors-headers
打開sqlite3數據庫,查看app01_note表記錄
訪問個人筆記接口
http://127.0.0.1:8000/api/notes/
返回一段json數據
修改main.js
// The Vue build version to load with the `import` command // (runtime-only or standalone) has been set in webpack.base.conf with an alias. import Vue from 'vue' import App from './App' import router from './router' import jQuery from 'jquery' import Vuex from 'vuex' Vue.use(Vuex) //使用vuex //定義一個大倉庫,用來存放項目組件中用到的數據 const store = new Vuex.Store({ state:{ noteList:[ '吃飯','睡覺','打豆豆' ] }, mutations:{ //修改倉庫中狀態的惟一方法就是經過提交mutations ADDNOTE: function (state, note) { // 將新筆記數據添加到noteList(同步操做) state.noteList.push(note) }, } }) Vue.config.productionTip = false //Web代碼語法高亮庫 import hljs from 'highlight.js' import 'highlight.js/styles/monokai.css' //樣式文件 Vue.directive('highlight',function (el) { let blocks = el.querySelectorAll('pre code'); blocks.forEach((block)=>{ hljs.highlightBlock(block) }) }) /* eslint-disable no-new */ new Vue({ el: '#app', router, store:store, //將上面定義的大倉庫與vue實例創建聯繫 components: { App }, template: '<App/>', beforeMount: function () { //掛載以前操做 // 去後端拉取筆記數據 // 經過ajax拉取 var _this = this; jQuery.ajax({ url:'http://127.0.0.1:8000/api/notes/', type: 'get', success:function(res){ console.log('我要去後端拉取筆記數據啦!'); console.log(res); // 將獲取到的筆記數據 放到大倉庫中 _this.$store.state.noteList = res.data } }) } })
刷新網頁,查看console
從上面能夠看到數據庫的記錄了!
修改mian.js,獲取到後端的數據後,清空數組。更新大倉庫的數據
// The Vue build version to load with the `import` command // (runtime-only or standalone) has been set in webpack.base.conf with an alias. import Vue from 'vue' import App from './App' import router from './router' import jQuery from 'jquery' import Vuex from 'vuex' Vue.use(Vuex) //使用vuex //定義一個大倉庫,用來存放項目組件中用到的數據 const store = new Vuex.Store({ state:{ noteList:[] }, mutations:{ //修改倉庫中狀態的惟一方法就是經過提交mutations ADDNOTE: function (state, note) { // 將新筆記數據添加到noteList(同步操做) state.noteList.push(note) }, INITNOTELIST: function (state, noteList) { state.noteList = noteList //修改數組 } } }) Vue.config.productionTip = false //Web代碼語法高亮庫 import hljs from 'highlight.js' import 'highlight.js/styles/monokai.css' //樣式文件 Vue.directive('highlight',function (el) { let blocks = el.querySelectorAll('pre code'); blocks.forEach((block)=>{ hljs.highlightBlock(block) }) }) /* eslint-disable no-new */ new Vue({ el: '#app', router, store:store, //將上面定義的大倉庫與vue實例創建聯繫 components: { App }, template: '<App/>', beforeMount: function () { //掛載以前操做 // 去後端拉取筆記數據 // 經過ajax拉取 var _this = this; jQuery.ajax({ url:'http://127.0.0.1:8000/api/notes/', type: 'get', success:function(res){ console.log('我要去後端拉取筆記數據啦!'); console.log(res); // 將獲取到的筆記數據 放到大倉庫中 // _this.$store.state.noteList = res.data //獲取後端數據,調用commit,執行INITNOTELIST方法修改大倉庫 _this.$store.commit('INITNOTELIST', res.data) } }) } })
因爲後端的數據是一個數組,數組每個元素都是對象。修改NoteList.vue
<template> <div> <div class="list-group"> <!-- 在子組件聲明 我須要被傳入的參數 v-for="note in NoteList" : NoteList是一個數組對象,note是數組每個對象 v-bind:name=note.title : 子組件聲明,被傳入的參數爲name,值爲note.title,也就是對象的標題 v-bind:key=note.id : for循環vue推薦綁定key,key用來標示for循環的每一項 --> <NoteItem v-for="note in noteList" v-bind:name='note.title' v-bind:key="note.id" ></NoteItem> </div> </div> </template> <script> //導入NoteItem組件 import NoteItem from '@/components/NoteItem.vue' export default { name: 'NoteList', components: { NoteItem }, data:function(){ return { } }, computed:{ noteList:function () { //從當前的vue實例的大倉庫裏找筆記列表 return this.$store.state.noteList } } } </script> <style> </style>
刷新頁面,效果以下:
打開app01_note表,增長一條記錄
刷新頁面,會發現多了一條數據
Axios 是一個基於 promise 的 HTTP 庫,能夠用在瀏覽器和 node.js 中。
中文文檔連接以下:
https://www.kancloud.cn/yunye/axios/234845
vue中發送ajax請求推薦使用 axios
E:\python_script\Vue\my-project>npm install axios -D
出現如下信息,表示安裝成功
+ axios@0.18.0 added 1 package from 1 contributor and audited 8835 packages in 15.845s found 1 moderate severity vulnerability run `npm audit fix` to fix them, or `npm audit` for details
import axios from 'axios'
語法:
axios.get('/user?ID=12345') .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); });
.then 表示成功以後,要作的操做
.catch 表示成功以後,要作的操做
舉例:
修改mian.js,改成axios
// The Vue build version to load with the `import` command // (runtime-only or standalone) has been set in webpack.base.conf with an alias. import Vue from 'vue' import App from './App' import router from './router' import jQuery from 'jquery' import Vuex from 'vuex' import axios from 'axios' Vue.use(Vuex) //使用vuex //定義一個大倉庫,用來存放項目組件中用到的數據 const store = new Vuex.Store({ state:{ noteList:[] }, mutations:{ //修改倉庫中狀態的惟一方法就是經過提交mutations ADDNOTE: function (state, note) { // 將新筆記數據添加到noteList(同步操做) state.noteList.push(note) }, INITNOTELIST: function (state, noteList) { state.noteList = noteList //修改數組 } } }) Vue.config.productionTip = false //Web代碼語法高亮庫 import hljs from 'highlight.js' import 'highlight.js/styles/monokai.css' //樣式文件 Vue.directive('highlight',function (el) { let blocks = el.querySelectorAll('pre code'); blocks.forEach((block)=>{ hljs.highlightBlock(block) }) }) /* eslint-disable no-new */ new Vue({ el: '#app', router, store:store, //將上面定義的大倉庫與vue實例創建聯繫 components: { App }, template: '<App/>', beforeMount: function () { //掛載以前操做 // 去後端拉取筆記數據 // 經過ajax拉取 var _this = this; axios.get('http://127.0.0.1:8000/api/notes/') .then(function (res) { console.log('我要去後端拉取筆記數據啦!'); console.log(res.data.data) // 將獲取到的筆記數據 放到大倉庫中 // _this.$store.state.noteList = res.data //獲取後端數據,調用commit,執行INITNOTELIST方法修改大倉庫 _this.$store.commit('INITNOTELIST', res.data.data) }) .catch(function (error) { console.log(error); }); // jQuery.ajax({ // url:'http://127.0.0.1:8000/api/notes/', // type: 'get', // success:function(res){ // console.log('我要去後端拉取筆記數據啦!'); // console.log(res); // // 將獲取到的筆記數據 放到大倉庫中 // // _this.$store.state.noteList = res.data // //獲取後端數據,調用commit,執行INITNOTELIST方法修改大倉庫 // _this.$store.commit('INITNOTELIST', res.data) // } // }) } })
刷新頁面,效果以下:
因爲如今左側的列表組裏面存放的值,都是對象。因此頁面點擊添加按鈕,是沒有效果的!
修改NoteEdit.vue,改成增長對象
<template> <div class="row"> <!-- 左邊的 textarea 區域開始 --> <div class="col-md-6 height600"> <div class="input-group"> <span class="input-group-addon" id="basic-addon1">標題</span> <input v-model="title" type="text" class="form-control" placeholder="請輸入標題" aria-describedby="basic-addon1"> </div> <!-- textarea --> <textarea class="my-textarea" v-model="content" > </textarea> </div> <!-- 左邊的 textarea 區域結束 --> <!-- 右邊的 展現區 區域開始 --> <div class="col-md-6 height600"> <div> <button v-on:click='addNote' class="btn btn-success">添加</button> </div> <!--展現原始html使用v-html--> <div class="right-box my-textarea" v-html="markedDownContent" v-highlight > </div> </div> <!-- 右變的 展現 區域結束 --> </div> </template> <script> //導入marked模塊,用來處理makedown語法 import marked from 'marked' export default { name: 'NoteEdit', data:function () { return { title:'', //聲明title變量 content:'' } }, //增長計算屬性 computed:{ markedDownContent:function(){ return marked(this.content) } }, methods:{ addNote:function(){ var noteObj = { title: this.title, content: this.content, markdownContent: this.markedDownContent } // 把新添加的筆記對象 發送到後端 this.$store.commit('ADDNOTE',noteObj) } } } </script> <style> .my-textarea { margin-top: 15px; height: 80%; width: 100% } .height600 { height: 600px; } .right-box { border: 1px solid grey } </style>
刷新網頁,效果以下:
注意:此時添加的數據,只是在內存中,刷新網頁,就沒有了!
注意:必須指定axios發送的請求頭的數據類型爲application/x-www-form-urlencoded
django的request.POST才能接收到,不然只能用request.body接受,並用正則獲取(太麻煩了!)
設置post請求的請求頭
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
django只能接收一個字符串,因此發送數據時,使用內置默認qs轉換爲字符串,使用時,必須導入一下
import qs from 'qs'
語法:
qs.stringify(note)
修改mian.js,完整代碼以下:
// The Vue build version to load with the `import` command // (runtime-only or standalone) has been set in webpack.base.conf with an alias. import Vue from 'vue' import App from './App' import router from './router' import jQuery from 'jquery' import Vuex from 'vuex' import axios from 'axios' import qs from 'qs' Vue.use(Vuex) //使用vuex // 設置post請求的請求頭 axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'; //定義一個大倉庫,用來存放項目組件中用到的數據 const store = new Vuex.Store({ state:{ noteList:[] }, mutations:{ //修改倉庫中狀態的惟一方法就是經過提交mutations ADDNOTE: function (state, note) { // 先將新筆記數據post到後端 (異步操做) axios({ method: 'post', url: 'http://127.0.0.1:8000/api/add/', data: qs.stringify(note) // 將js對象轉換成字符串格式 }) .then(function (res) { //成功以後 console.log(res) // 提交mutation context.commit('ADDNOTE', note) }) .catch(function (error) { //失敗以後 console.log(error) }); // 將新筆記數據添加到noteList(同步操做) state.noteList.push(note) }, INITNOTELIST: function (state, noteList) { state.noteList = noteList //修改數組 } } }) Vue.config.productionTip = false //Web代碼語法高亮庫 import hljs from 'highlight.js' import 'highlight.js/styles/monokai.css' //樣式文件 Vue.directive('highlight',function (el) { let blocks = el.querySelectorAll('pre code'); blocks.forEach((block)=>{ hljs.highlightBlock(block) }) }) /* eslint-disable no-new */ new Vue({ el: '#app', router, store:store, //將上面定義的大倉庫與vue實例創建聯繫 components: { App }, template: '<App/>', beforeMount: function () { //掛載以前操做 // 去後端拉取筆記數據 // 經過ajax拉取 var _this = this; axios.get('http://127.0.0.1:8000/api/notes/') .then(function (res) { console.log('我要去後端拉取筆記數據啦!'); console.log(res.data.data) // 將獲取到的筆記數據 放到大倉庫中 // _this.$store.state.noteList = res.data //獲取後端數據,調用commit,執行INITNOTELIST方法修改大倉庫 _this.$store.commit('INITNOTELIST', res.data.data) }) .catch(function (error) { console.log(error); }); } })
從新添加一條數據,效果以下:
刷新頁面,記錄沒有丟失
查看app01_note表記錄,發現多了一條!
這裏有一個問題,如今異步的從操做都寫在了mutations裏面,好比POST請求操做
可是Vuex裏面規定,全部的異步操做,要放到actions裏面!不能放到mutations裏面
Action 相似於 mutation,不一樣在於:
讓咱們來註冊一個簡單的 action:
const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment (state) { state.count++ } }, actions: { increment (context) { context.commit('increment') } } })
Action 函數接受一個與 store 實例具備相同方法和屬性的 context 對象,所以你能夠調用 context.commit
提交一個 mutation,或者經過 context.state
和 context.getters
來獲取 state 和 getters。當咱們在以後介紹到 Modules時,你就知道 context 對象爲何不是 store 實例自己了。
實踐中,咱們會常常用到 ES2015 的 參數解構 來簡化代碼(特別是咱們須要調用 commit
不少次的時候):
actions: { increment ({ commit }) { commit('increment') } }
Action 經過 store.dispatch
方法觸發:
store.dispatch('increment')
乍一眼看上去感受畫蛇添足,咱們直接分發 mutation 豈不更方便?實際上並不是如此,還記得 mutation 必須同步執行這個限制麼?Action 就不受約束!咱們能夠在 action 內部執行異步操做:
actions: { incrementAsync ({ commit }) { setTimeout(() => { commit('increment') }, 1000) } }
Actions 支持一樣的載荷方式和對象方式進行分發:
// 以載荷形式分發 store.dispatch('incrementAsync', { amount: 10 }) // 以對象形式分發 store.dispatch({ type: 'incrementAsync', amount: 10 })
修改mian.js,將post請求部分代碼移植到actions中
// The Vue build version to load with the `import` command // (runtime-only or standalone) has been set in webpack.base.conf with an alias. import Vue from 'vue' import App from './App' import router from './router' import jQuery from 'jquery' import Vuex from 'vuex' import axios from 'axios' import qs from 'qs' Vue.use(Vuex) //使用vuex // 設置post請求的請求頭 axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'; // 定義一個大倉庫,用來存放我項目組件中用到的數據 const store = new Vuex.Store({ state: { noteList: [] }, mutations: { // 修改倉庫中狀態的惟一方法就是經過提交mutation ADDNOTE: function (state, note) { state.noteList.push(note) // 將新筆記數據添加到noteList(同步操做) }, INITNOTELIST: function (state, noteList) { state.noteList = noteList } }, actions: { // 拉取最新的筆記數據 getNoteList: function (context, noteList) { axios.get('http://127.0.0.1:8000/api/notes/') .then((res)=> { console.log('我要去後端拉取筆記數據啦!'); console.log(res.data.data) // 將獲取到的筆記數據 放到大倉庫中 // _this.$store.state.noteList = res.data context.commit('INITNOTELIST', res.data.data) }) .catch(function (error) { console.log(error); }); }, // 全部異步操做都放在這個actions中 addNote(context, note) { // 先將新筆記數據post到後端 (異步操做) axios({ method: 'post', url: 'http://127.0.0.1:8000/api/add/', data: qs.stringify(note) // 將js對象轉換成字符串格式 }) .then(function (res) { console.log(res) // 提交mutation context.commit('ADDNOTE', note) }) .catch(function (error) { console.log(error) }); }, } }) Vue.config.productionTip = false //Web代碼語法高亮庫 import hljs from 'highlight.js' import 'highlight.js/styles/monokai.css' //樣式文件 Vue.directive('highlight',function (el) { let blocks = el.querySelectorAll('pre code'); blocks.forEach((block)=>{ hljs.highlightBlock(block) }) }) /* eslint-disable no-new */ new Vue({ el: '#app', router, store:store, //將上面定義的大倉庫與vue實例創建聯繫 components: { App }, template: '<App/>', beforeMount: function () { //掛載以前操做 // 去後端拉取筆記數據 // 經過ajax拉取 var _this = this; axios.get('http://127.0.0.1:8000/api/notes/') .then(function (res) { console.log('我要去後端拉取筆記數據啦!'); console.log(res.data.data) // 將獲取到的筆記數據 放到大倉庫中 // _this.$store.state.noteList = res.data //獲取後端數據,調用commit,執行INITNOTELIST方法修改大倉庫 _this.$store.commit('INITNOTELIST', res.data.data) }) .catch(function (error) { console.log(error); }); } })
這樣的話,將異步限制在actions中。將同步操做限制在mutation中 。分工就明確了!
修改NoteEdit.vue,使用store.dispatch 方法觸發,帶一個參數過去
<template> <div class="row"> <!-- 左邊的 textarea 區域開始 --> <div class="col-md-6 height600"> <div class="input-group"> <span class="input-group-addon" id="basic-addon1">標題</span> <input v-model="title" type="text" class="form-control" placeholder="請輸入標題" aria-describedby="basic-addon1"> </div> <!-- textarea --> <textarea class="my-textarea" v-model="content" > </textarea> </div> <!-- 左邊的 textarea 區域結束 --> <!-- 右邊的 展現區 區域開始 --> <div class="col-md-6 height600"> <div> <button v-on:click='addNote' class="btn btn-success">添加</button> </div> <!--展現原始html使用v-html--> <div class="right-box my-textarea" v-html="markedDownContent" v-highlight > </div> </div> <!-- 右變的 展現 區域結束 --> </div> </template> <script> //導入marked模塊,用來處理makedown語法 import marked from 'marked' export default { name: 'NoteEdit', data:function () { return { title:'', //聲明title變量 content:'' } }, //增長計算屬性 computed:{ markedDownContent:function(){ return marked(this.content) } }, methods:{ addNote:function(){ var noteObj = { title: this.title, content: this.content, markdownContent: this.markedDownContent } // 把新添加的筆記對象 發送到後端 // this.$store.commit('ADDNOTE',noteObj) // 先分發action this.$store.dispatch('addNote',noteObj) } } } </script> <style> .my-textarea { margin-top: 15px; height: 80%; width: 100% } .height600 { height: 600px; } .right-box { border: 1px solid grey } </style>
刷新網頁,添加一條數據
再次刷新,網頁效果以下:
官方解釋:
prop 是單向綁定的:當父組件的屬性變化時,將傳導給子組件,可是不會反過來。這是爲了防止子組件無心修改了父組件的狀態——這會讓應用的數據流難以理解。
另外,每次父組件更新時,子組件的全部 prop 都會更新爲最新值。這意味着你不該該在子組件內部改變 prop。若是你這麼作了,Vue 會在控制檯給出警告。
看下圖
state,驅動應用的數據源;
view,以聲明方式將 state 映射到視圖;
actions,響應在 view 上的用戶輸入致使的狀態變化。
單向數據流指只能從一個方向修改數據,姑且咱們能夠這樣理解,以下圖所示。一個父組件下有兩個子組件1和子組件2,父組件能夠向子組件傳遞數據。假如子組件都獲取到了父組件的name,在子組件1中對name從新修改以後,子組件2和父組件中的值並不會發生改變,這正是由於Vue中的機制是單向數據流,子組件不能直接改變父組件的狀態。但反過來,若是是父組件中的name修改了,固然兩個子組件中的name也就改變了。
可是,當咱們的應用遇到多個組件共享狀態時,單向數據流的簡潔性很容易被破壞:
使用傳統方式將會很是繁瑣,一般會致使沒法維護的代碼
組件的共享狀態抽取出來,以一個全局單例模式管理,在這種模式下,咱們的組件樹構成了一個巨大的「視圖」,無論在樹的哪一個位置,任何組件都能獲取狀態或者觸發行爲!
另外,經過定義和隔離狀態管理中的各類概念並強制遵照必定的規則,咱們的代碼將會變得更結構化且易維護。
某些大神說,一看就明白了,不須要解釋。那我只能呵呵!
再來看下面一張圖
state:既然vuex是用來儲存數據的,那麼咱們的儲存地點就是這裏。
render: 頁面渲染
vue commponents: 頁面的組件,好比輸入值時
dispatch:組件分發給acitons
actions:專門用來提交mutations的,處理異步操做。它執行axios,請求後端服務器。拿到數據後,執行commit
mutations:對數據的處理都是在這裏進行,處理同步操做。拿到axios的返回數據後,更新state
devtools: vue-devtools是一款基於chrome遊覽器的插件,用於調試vue應用
mutate:state數據變化後,頁面執行render,開始從新渲染。
因此總的來講就是創建一個state,而後調用actions來提交mutations處理state中的數據,最後用getters獲得state中的數據。
至於爲何要用actions來提交mutations處理state中的數據,緣由是mutation 必須是同步函數,因此經過actions來調用mutations
state-->render-->vue components-->dispatch-->actions-->backend api-->commit-->mutations-->mutate
-->state-->render....
這張圖描述的很棒,完整的數據流閉環,整個應用的數據流是單向的。對咱們理解Vuex和Vue的組件間的通信關係頗有幫助。
網上找了一張圖,解釋了代碼執行過程
雖然 Vuex 能夠幫助咱們管理共享狀態,但也附帶了更多的概念和框架。這須要對短時間和長期效益進行權衡。
若是您不打算開發大型單頁應用,使用 Vuex 多是繁瑣冗餘的。確實是如此——若是您的應用夠簡單,您最好不要使用 Vuex。一個簡單的 store 模式就足夠您所需了。可是,若是您須要構建一箇中大型單頁應用,您極可能會考慮如何更好地在組件外部管理狀態,Vuex 將會成爲天然而然的選擇。引用 Redux 的做者 Dan Abramov 的話說就是:
Flux 架構就像眼鏡:您自會知道何時須要它。
修改NoteList.vue,改爲v-bind:note=note,此時等式右邊的note是一個對象。等式左邊的note是變量名
<template> <div> <div class="list-group"> <!-- 在子組件聲明 我須要被傳入的參數 v-for="note in NoteList" : NoteList是一個數組對象,note是數組每個對象 v-bind:note='note' : 子組件聲明,被傳入的參數爲note,值爲note(它是一個對象) v-bind:key=note.id : for循環vue推薦綁定key,key用來標示for循環的每一項 --> <NoteItem v-for="note in noteList" v-bind:note='note' v-bind:key="note.id" ></NoteItem> </div> </div> </template> <script> //導入NoteItem組件 import NoteItem from '@/components/NoteItem.vue' export default { name: 'NoteList', components: { NoteItem }, data:function(){ return { } }, computed:{ noteList:function () { //從當前的vue實例的大倉庫裏找筆記列表 return this.$store.state.noteList } } } </script> <style> </style>
在來修改NoteItem.vue,頁面渲染改爲note.title和note.id
props的值改爲note,由於父組件NoteList.vue將變量名改爲了note了。
<template> <div class="list-group-item">{{note.title}} <span class="glyphicon glyphicon-trash pull-right"></span> </div> </template> <script> export default { name: 'NoteItem', props: ['note'], // 在子組件聲明 我須要被傳入的參數 } </script> <style> </style>
刷新頁面,效果以下:
若是左側的筆記列表是空的,查看django後端是否啓動了。
瀏覽器打開控制檯,查看Console是否有錯誤!
要先發動ajax請求先去刪除筆記,後端返回成功後,再發送ajax請求去拉取最新的筆記數據
好比這樣:
removeNote:function(id){
// 刪除當前筆記 // 去數據庫刪除該id的筆記 this.$store.dispatch('removeNote', id) this.$store.dispatch('getNoteList') }
可是沒法知道removeNote執行,到底有沒有成功,由於它是異步操做!
這個時候,就須要用到組合action
Action 一般是異步的,那麼如何知道 action 何時結束呢?更重要的是,咱們如何才能組合多個 action,以處理更加複雜的異步流程?
首先,你須要明白 store.dispatch
能夠處理被觸發的 action 的處理函數返回的 Promise,而且 store.dispatch
仍舊返回 Promise:
actions: { actionA ({ commit }) { return new Promise((resolve, reject) => { setTimeout(() => { commit('someMutation') resolve() }, 1000) }) } }
如今你能夠:
store.dispatch('actionA').then(() => { // ... })
在另一個 action 中也能夠:
actions: { // ... actionB ({ dispatch, commit }) { return dispatch('actionA').then(() => { commit('someOtherMutation') }) } }
最後,若是咱們利用 async / await,咱們能夠以下組合 action:
// 假設 getData() 和 getOtherData() 返回的是 Promise actions: { async actionA ({ commit }) { commit('gotData', await getData()) }, async actionB ({ dispatch, commit }) { await dispatch('actionA') // 等待 actionA 完成 commit('gotOtherData', await getOtherData()) } }
一個 store.dispatch
在不一樣模塊中能夠觸發多個 action 函數。在這種狀況下,只有當全部觸發函數完成後,返回的 Promise 纔會執行。
修改NoteItem.vue,綁定點擊事件,執行dispatch
<template> <!--渲染name變量--> <div class="list-group-item">{{note.title}} <span v-on:click='removeNote(note.id)' class="glyphicon glyphicon-trash pull-right" ></span> </div> </template> <script> export default { name: 'NoteItem', props: ['note'], // 在子組件聲明 我須要被傳入的參數 methods:{ removeNote:function(id){ // 刪除當前筆記 // 去數據庫刪除該id的筆記 this.$store.dispatch('removeNote', id) .then(()=>{ this.$store.dispatch('getNoteList') // 再發送ajax請求去拉取最新的筆記數據 }) // 發動ajax請求先去刪除筆記 .catch(function(err){ console.log('這是在Noteitem組件中捕獲到的錯誤') console.log(err) }) } } } </script> <style> </style>
修改main.js,增長刪除方法
// The Vue build version to load with the `import` command // (runtime-only or standalone) has been set in webpack.base.conf with an alias. import Vue from 'vue' import App from './App' import router from './router' import jQuery from 'jquery' import Vuex from 'vuex' import axios from 'axios' import qs from 'qs' Vue.use(Vuex) //使用vuex // 設置post請求的請求頭 axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'; // 定義一個大倉庫,用來存放我項目組件中用到的數據 const store = new Vuex.Store({ state: { noteList: [] }, mutations: { // 修改倉庫中狀態的惟一方法就是經過提交mutation ADDNOTE: function (state, note) { state.noteList.push(note) // 將新筆記數據添加到noteList(同步操做) }, INITNOTELIST: function (state, noteList) { state.noteList = noteList } }, actions: { // 拉取最新的筆記數據 getNoteList: function (context, noteList) { axios.get('http://127.0.0.1:8000/api/notes/') .then((res)=> { console.log('我要去後端拉取筆記數據啦!'); console.log(res.data.data) // 將獲取到的筆記數據 放到大倉庫中 // _this.$store.state.noteList = res.data context.commit('INITNOTELIST', res.data.data) }) .catch(function (error) { console.log(error); }); }, // 全部異步操做都放在這個actions中 addNote(context, note) { // 先將新筆記數據post到後端 (異步操做) axios({ method: 'post', url: 'http://127.0.0.1:8000/api/add/', data: qs.stringify(note) // 將js對象轉換成字符串格式 }) .then(function (res) { console.log(res) // 提交mutation context.commit('ADDNOTE', note) }) .catch(function (error) { console.log(error) }); }, // 刪除筆記的異步操做 removeNote(context, id) { return new Promise(function (resolve, reject) { // 先將新筆記數據post到後端 (異步操做) axios({ method: 'get', url: 'http://127.0.0.1:8000/api/delete/' + id, }) .then(function (res) { console.log(res) // 提交mutation // 刪除成功以後要再去拉取最新的筆記數據 resolve() }) .catch(function (error) { console.log(error) reject(error) }); }) } } }) Vue.config.productionTip = false //Web代碼語法高亮庫 import hljs from 'highlight.js' import 'highlight.js/styles/monokai.css' //樣式文件 Vue.directive('highlight',function (el) { let blocks = el.querySelectorAll('pre code'); blocks.forEach((block)=>{ hljs.highlightBlock(block) }) }) /* eslint-disable no-new */ new Vue({ el: '#app', router, store:store, //將上面定義的大倉庫與vue實例創建聯繫 components: { App }, template: '<App/>', beforeMount: function () { //掛載以前操做 // 去後端拉取筆記數據 // 經過ajax拉取 var _this = this; axios.get('http://127.0.0.1:8000/api/notes/') .then(function (res) { console.log('我要去後端拉取筆記數據啦!'); console.log(res.data.data) // 將獲取到的筆記數據 放到大倉庫中 // _this.$store.state.noteList = res.data //獲取後端數據,調用commit,執行INITNOTELIST方法修改大倉庫 _this.$store.commit('INITNOTELIST', res.data.data) }) .catch(function (error) { console.log(error); }); } })
刷新網頁,點擊刪除一個,效果以下:
查看錶app01_note的數據,發現少了一條
前端+後端完整代碼,訪問github