python 全棧開發,Day93(vue內容補充,VueX)

昨日內容回顧

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(內容)
View Code

1、Vue內容補充

npm安裝的語法

1. npm install xx -D         --> 安裝當前項目用到的開發環境(好比webpack等)
2. npm install xx -S(--save) --> 安裝當前項目用到的依賴包(線上運行必需要有的包)
3. npm install xx -g         --> 全局安裝,安裝完以後在cmd能夠直接當命令行工具使用的

Vue中配置全局jQuery

安裝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'
  }
}
View Code

須要在哪一個頁面用,直接python

import jQuery from 'jquery'

若是須要全局使用,在mian.js中導入jquery

 

highlight.js

昨天的文章,已經介紹了使用第一種方式,來引入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
})
View Code

修改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>
View Code

訪問網頁,測試一段代碼

和昨天個人寫的博客

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>
View Code

刷新網頁,效果以下:

如今須要將輸入的標題,添加到左側的列表組中

查看NoteList.vue,發現左側的列表組變量都是在NoteList數組中,增長到這個數組就能夠了。

這就須要用到組件間的傳值。以前咱們學到,組件之間傳值,使用bus。可是如今不用bus了,用vuex

vuex就是一個倉庫

 

2、Vuex

vuex是什麼?

先引用vuex官網的話:

Vuex 是一個專爲 Vue.js 應用程序開發的狀態管理模式。它採用集中式存儲管理應用的全部組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。

狀態管理模式集中式存儲管理 一聽就很高大上,蠻嚇人的。在我看來 vuex 就是把須要共享的變量所有存儲在一個對象裏面,而後將這個對象放在頂層組件中供其餘組件使用。這麼說吧,將vue想做是一個js文件、組件是函數,那麼vuex就是一個全局變量,只是這個「全局變量」包含了一些特定的規則而已。

在vue的組件化開發中,常常會遇到須要將當前組件的狀態傳遞給其餘組件。父子組件通訊時,咱們一般會採用 props + emit 這種方式。但當通訊雙方不是父子組件甚至壓根不存在相關聯繫,或者一個狀態須要共享給多個組件時,就會很是麻煩,數據也會至關難維護,這對咱們開發來說就很不友好。vuex 這個時候就很實用,不過在使用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
    }
}
View Code

這個就是最基本也是完整的vuex代碼;vuex 包含有五個基本的對象:

  • state:存儲狀態。也就是變量;
  • getters:派生狀態。也就是set、get中的get,有兩個可選參數:state、getters分別能夠獲取state中的變量和其餘的getters。外部調用方式:store.getters.personInfo()。就和vue的computed差很少;
  • mutations:提交狀態修改。也就是set、get中的set,這是vuex中惟一修改state的方式,但不支持異步操做。第一個參數默認是state。外部調用方式:store.commit('SET_AGE', 18)。和vue中的methods相似。
  • actions:和mutations相似。不過actions支持異步操做。第一個參數默認是和store具備相同參數屬性的對象。外部調用方式:store.dispatch('nameAsyn')
  • modules:store的子模塊,內容就至關因而store的一個實例。調用方式和前面介紹的類似,只是要加上當前子模塊名,如:store.a.getters.xxx()

 

安裝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

 

使用vuex

修改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/>'
})
View Code

修改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>
View Code

刷新網頁,效果和以前是同樣的。

 

State

單一狀態

Vuex 使用單一狀態樹——是的,用一個對象就包含了所有的應用層級狀態。至此它便做爲一個「惟一數據源 (SSOT)」而存在。這也意味着,每一個應用將僅僅包含一個 store 實例。單一狀態樹讓咱們可以直接地定位任一特定的狀態片斷,在調試的過程當中也能輕易地取得整個當前應用狀態的快照。

單狀態樹和模塊化並不衝突——在後面的章節裏咱們會討論如何將狀態和狀態變動事件分佈到各個子模塊中。

在 Vue 組件中得到 Vuex 狀態

那麼咱們如何在 Vue 組件中展現狀態呢?因爲 Vuex 的狀態存儲是響應式的,從 store 實例中讀取狀態最簡單的方法就是在計算屬性中返回某個狀態:

// 建立一個 Counter 組件
const Counter = {
  template: `<div>{{ count }}</div>`,
  computed: {
    count () {
      return store.state.count
    }
  }
}
View Code

每當 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>
  `
})
View Code

經過在根實例中註冊 store 選項,該 store 實例會注入到根組件下的全部子組件中,且子組件能經過 this.$store 訪問到。讓咱們更新下 Counter 的實現:

const Counter = {
  template: `<div>{{ count }}</div>`,
  computed: {
    count () {
      return this.$store.state.count
    }
  }
}
View Code

 

添加標題到store

修改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>
View Code

刷新網頁效果以下:

如今有一個問題,組件能直接修改大倉庫的值。若是組件繁多,倉庫的值出現了異常,不知道是哪一個組件更新的。因此vuex爲了解決這個問題,規定修改倉庫的值,必須在倉庫裏面執行才能夠!它提供一個方法Mutation

 

Mutation

更改 Vuex 的 store 中的狀態的惟一方法是提交 mutation。Vuex 中的 mutation 很是相似於事件:每一個 mutation 都有一個字符串的 事件類型 (type) 和 一個 回調函數 (handler)。這個回調函數就是咱們實際進行狀態更改的地方,而且它會接受 state 做爲第一個參數:

const store = new Vuex.Store({
  state: {
    count: 1
  },
  mutations: {
    increment (state) {
      // 變動狀態
      state.count++
    }
  }
})
View Code

你不能直接調用一個 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/>'
})
View Code

修改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>
View Code

刷新網頁,再次驗證添加功能是否正常!

 

如今添加的數組,是在內存中,不是在數據庫中。那麼須要用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數據

 

使用ajax獲取後端數據

修改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
      }
    })
  }
})
View Code

刷新網頁,查看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)
      }
    })
  }
})
View Code

因爲後端的數據是一個數組,數組每個元素都是對象。修改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>
View Code

刷新頁面,效果以下:

打開app01_note表,增長一條記錄

刷新頁面,會發現多了一條數據

 

axios

Axios 是一個基於 promise 的 HTTP 庫,能夠用在瀏覽器和 node.js 中。

中文文檔連接以下:

 https://www.kancloud.cn/yunye/axios/234845

vue中發送ajax請求推薦使用 axios 

 

安裝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

使用axios

import axios from 'axios'

 

使用GET請求

語法:

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)
    //   }
    // })
  }
})
View Code

刷新頁面,效果以下:

 

添加標題到左側

因爲如今左側的列表組裏面存放的值,都是對象。因此頁面點擊添加按鈕,是沒有效果的!

修改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>
View Code

刷新網頁,效果以下:

注意:此時添加的數據,只是在內存中,刷新網頁,就沒有了!

 

添加筆記到數據庫

注意:必須指定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);
      });
  }
})
View Code

從新添加一條數據,效果以下:

刷新頁面,記錄沒有丟失

查看app01_note表記錄,發現多了一條!

這裏有一個問題,如今異步的從操做都寫在了mutations裏面,好比POST請求操做

可是Vuex裏面規定,全部的異步操做,要放到actions裏面!不能放到mutations裏面

 

Action

Action 相似於 mutation,不一樣在於:

  • Action 提交的是 mutation,而不是直接變動狀態。
  • Action 能夠包含任意異步操做。

讓咱們來註冊一個簡單的 action:

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  },
  actions: {
    increment (context) {
      context.commit('increment')
    }
  }
})
View Code

Action 函數接受一個與 store 實例具備相同方法和屬性的 context 對象,所以你能夠調用 context.commit 提交一個 mutation,或者經過 context.state和 context.getters 來獲取 state 和 getters。當咱們在以後介紹到 Modules時,你就知道 context 對象爲何不是 store 實例自己了。

實踐中,咱們會常常用到 ES2015 的 參數解構 來簡化代碼(特別是咱們須要調用 commit 不少次的時候):

actions: {
  increment ({ commit }) {
    commit('increment')
  }
}
View Code

 

分發 Action

Action 經過 store.dispatch 方法觸發:

store.dispatch('increment')

乍一眼看上去感受畫蛇添足,咱們直接分發 mutation 豈不更方便?實際上並不是如此,還記得 mutation 必須同步執行這個限制麼?Action 就不受約束!咱們能夠在 action 內部執行異步操做:

actions: {
  incrementAsync ({ commit }) {
    setTimeout(() => {
      commit('increment')
    }, 1000)
  }
}
View Code

Actions 支持一樣的載荷方式和對象方式進行分發:

// 以載荷形式分發
store.dispatch('incrementAsync', {
  amount: 10
})

// 以對象形式分發
store.dispatch({
  type: 'incrementAsync',
  amount: 10
})
View Code

 

修改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);
      });
  }
})
View Code

這樣的話,將異步限制在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>
View Code

刷新網頁,添加一條數據

 再次刷新,網頁效果以下:

 單向數據流

官方解釋:

prop 是單向綁定的:當父組件的屬性變化時,將傳導給子組件,可是不會反過來。這是爲了防止子組件無心修改了父組件的狀態——這會讓應用的數據流難以理解。

另外,每次父組件更新時,子組件的全部 prop 都會更新爲最新值。這意味着你不該該在子組件內部改變 prop。若是你這麼作了,Vue 會在控制檯給出警告。

 

看下圖

state,驅動應用的數據源;
view,以聲明方式將 state 映射到視圖;
actions,響應在 view 上的用戶輸入致使的狀態變化。

 

單向數據流指只能從一個方向修改數據,姑且咱們能夠這樣理解,以下圖所示。一個父組件下有兩個子組件1和子組件2,父組件能夠向子組件傳遞數據。假如子組件都獲取到了父組件的name,在子組件1中對name從新修改以後,子組件2和父組件中的值並不會發生改變,這正是由於Vue中的機制是單向數據流,子組件不能直接改變父組件的狀態。但反過來,若是是父組件中的name修改了,固然兩個子組件中的name也就改變了。 

可是,當咱們的應用遇到多個組件共享狀態時,單向數據流的簡潔性很容易被破壞:

  • 多個視圖依賴於同一狀態。
  • 來自不一樣視圖的行爲須要變動同一狀態。

 

使用傳統方式將會很是繁瑣,一般會致使沒法維護的代碼

Vuex狀態管理

組件的共享狀態抽取出來,以一個全局單例模式管理,在這種模式下,咱們的組件樹構成了一個巨大的「視圖」,無論在樹的哪一個位置,任何組件都能獲取狀態或者觸發行爲!

另外,經過定義和隔離狀態管理中的各類概念並強制遵照必定的規則,咱們的代碼將會變得更結構化且易維護。

某些大神說,一看就明白了,不須要解釋。那我只能呵呵!

再來看下面一張圖

 

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 多是繁瑣冗餘的。確實是如此——若是您的應用夠簡單,您最好不要使用 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>
View Code

在來修改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>
View Code

刷新頁面,效果以下:

若是左側的筆記列表是空的,查看django後端是否啓動了。

瀏覽器打開控制檯,查看Console是否有錯誤!

觸發動做

要先發動ajax請求先去刪除筆記,後端返回成功後,再發送ajax請求去拉取最新的筆記數據

好比這樣:

removeNote:function(id){
        // 刪除當前筆記 // 去數據庫刪除該id的筆記 this.$store.dispatch('removeNote', id) this.$store.dispatch('getNoteList') }

可是沒法知道removeNote執行,到底有沒有成功,由於它是異步操做!

這個時候,就須要用到組合action

 

組合 Action

Action 一般是異步的,那麼如何知道 action 何時結束呢?更重要的是,咱們如何才能組合多個 action,以處理更加複雜的異步流程?

首先,你須要明白 store.dispatch 能夠處理被觸發的 action 的處理函數返回的 Promise,而且 store.dispatch 仍舊返回 Promise

actions: {
  actionA ({ commit }) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        commit('someMutation')
        resolve()
      }, 1000)
    })
  }
}
View Code

如今你能夠:

store.dispatch('actionA').then(() => {
  // ...
})
View Code

在另一個 action 中也能夠:

actions: {
  // ...
  actionB ({ dispatch, commit }) {
    return dispatch('actionA').then(() => {
      commit('someOtherMutation')
    })
  }
}
View Code

最後,若是咱們利用 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())
  }
}
View Code

一個 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>
View Code

修改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);
      });
  }
})
View Code

刷新網頁,點擊刪除一個,效果以下:

查看錶app01_note的數據,發現少了一條

 

前端+後端完整代碼,訪問github

https://github.com/987334176/MyNotes

相關文章
相關標籤/搜索