背景:小型應用里的每個組件維護着自有的狀態,即當前應用的狀態的一部分,所以整個應用的狀態被分散在了各個角落,但是我們經常遇到要把
狀態的一部分
共享給多個組件的情況。
狀態其實可以形象地想成我們的 data 里面的各個屬性。
Vuex 使用了單狀態樹(single state tree),一個 store 對象就存儲了整個應用層的狀態。它讓我們可以更方便地定位某一具體的狀態,並且在調試時能簡單地獲取到當前整個應用的快照。
先埋個伏筆。Vuex 使用的這種 single state tree 與 modularity 模塊化是不沖突的,問題是,如何將 state 與 mutation 分到子模塊中?
要使用 store ,首先必須
Vue.use(Vuex)
,然后將 store
const store = new Vuex.store()
inject 定義到 Vue 實例 app 中
new Vue({store})
,實現從根組件注入到所有子組件中,接着就可以在子組件中使用
this.$store
當一個組件需要使用多個某 store 的狀態屬性或 getters ,可以使用 shared helper ---- 共享幫手
,它會返回一個對象 。
it('helper: mapState (object)', () =& {
conststore =newVuex.Store({
getters: {
constvm =newVue({
computed: mapState({
// 在 mapState 里面我們既可以調用 store 的 state ,也可以調用 store 的 getters
a: (state, getters) =&{
returnstate.a + getters.b
expect(vm.a).toBe(3)
store.state.a++
expect(vm.a).toBe(4)
那么如何將它與本地的計算屬性結合使用呢?一般我們會使用一個工具,將多個對象合而為一,再把這個最終的對象傳遞給 computed。但是這里我們可以直接使用 es6 的 stage 3 的 object spread operator ---- 對象擴展操作符,來超簡潔地實現這一功能。
computed: {
localComputed () {}
// 將其中的屬性與本地的計算屬性合並在一起
...mapState({
message:state=&state.obj.message
有時候我們需要從 store 的狀態派生出其他狀態,然后對這個狀態(的方法)在多個組件中加以利用。通常我們的做法是復制這個方法,或者將它封裝為一個公用的方法,然后在需要的時候導入,但是兩者其實都不甚理想。Vuex 提供了 getters 屬性,用途類似 stores 中的計算屬性。
getters 中的方法接受兩個參數,分別為 state 以及 getters(其他 getters),用法如下。
getters: {
doneTodosCount: (state, getters) =&{
returngetters.doneTodos.length
那么我們在其他組件內部使用 getters 也變得十分簡單
computed: {
doneTodosCount () {
returnthis.$store.getters.doneTodosCount
mapGetters
可以將 store 的 getters 映射到本地的計算屬性中來,除了可以使用數組之外,還可以使用對象起別名。
...mapGetters([
'doneTodosCount',
'anotherGetter',
能改變 Vuex store 中的 state 狀態的唯一方法是提交 mutation 變更。mutation 和事件很像:都有字符串類型的 type 以及 handler 句柄。我們在 handler 中實際修改 state,state 為每個 mutation 的第一個參數。
conststore =newVuex.Store({
mutations: {
increment (state) {
// mutate state
state.count++
// call, 只有在使用 type increment 調用 mutation 時才能稱為 mit('increment')
commit 的第二個可選參數為 payload 有效載荷,可以為普通類型或對象類型等等。
commit 方法還可以通過對象形式調用,這種情況下,這個對象都會被當成 payload 。
type:'increment',
little tips
建議使用大寫命名 Mutation
將所有大寫變量存放在一個文件中,需要的時候引入。使用 es6 的計算屬性名新特性來使用常量作為方法名。
// mutation-types.js
exportconstSOME_MUTATION ='SOME_MUTATION'
// store.js
importVuexfrom'vuex'
import{ SOME_MUTATION }from'./mutation-types'
conststore =newVuex.Store({
state: { ... },
mutations: {
// we can use the ES2015 computed property name feature
// to use a constant as the function name
[SOME_MUTATION] (state) {
// mutate state
es6 計算屬性名
// e.g: 使用含有空格的變量作為屬性名會報錯,此時可以將它存為字符串或者存在中括號包裹的變量中
varlastName ="last name";
varperson = {
"first name":"Nicholas",
// 中括號包裹的變量
[lastName]: "Zakas"
console.log(person["last name"]);// Zakas
mutations 必須都是同步的,它的改變必須在調用之后立即執行
因為它是唯一可以修改 state 的,如果它使用了異步方法,將會使我們的 state 變得無法追蹤,定位問題也變得是否困難
在組件中 commit mutation 時
可以使用 this.$mit() 或者使用 mapMutations 方法,后者可以將組件中的方法映射到 mit 調用(需要在根組件注入 store)。
import{ mapMutations }from'vuex'
exportdefault{
methods: {
// 傳入數組
...mapMutations([
'increment'// map this.increment() to this.$mit('increment')
// 傳入對象,可以使用 alias
...mapMutations({
add:'increment'// map this.add() to this.$mit('increment')
actions 是提交 mutations 的,它可以有任意的異步操作。
actions 的第一個參數是 context,它向外暴露一組與 store 實例相同的方法/屬性,所以可以直接調用 mit 或者訪問 context.state 或者 context.getters 。我們通常使用 es6 的參數解構來簡化我們的代碼,直接寫成
{ commit }
actions: {
increment ({ commit }) {
commit('increment')
如何觸發 Actions?
actions 通過
store.dispatch('actionName')
觸發,其方法體中再觸發 mutation,但是 mutations 是可以直接通過 mit 觸發的,那么為什么不直接使用 mit(‘mutationName’) 呢?因為,actions 是可以異步執行的,而 mutations 只可以同步。所以這種 dispatch 調用可以在 action 內執行異步操作,也就是說可以執行異步 mutation。
可以使用 payload 格式或者對象形式觸發。二者等價
// dispatch with a payload
store.dispatch('incrementAsync', {
// dispatch with an object
store.dispatch({
type:'incrementAsync',
shopping cart 中的實際應用,既調用了異步 API,又提交了多個 mutation。
actions: {
checkout ({ commit, state }, payload) {
// save the items currently in the cart
constsavedCartItems = [...state.cart.added]
// send out checkout request, and optimistically
// clear the cart
commit(types.CHECKOUT_REQUEST)
// the 異步 shop API accepts a success callback and a failure callback
shop.buyProducts(
// handle success
() =& commit(types.CHECKOUT_SUCCESS),
// handle failure
() =& commit(types.CHECKOUT_FAILURE, savedCartItems)
在組件中分發 Actions
this.$store.dispatch()
mapActions
映射組件方法到
store.dispatch
中調用(需要注入 root)。同
mapMutations
Actions 組合,怎么控制 actions 執行呢?
由於 actions 是異步的,因此我們就很難知道一個 action 什么時候完成,以及該怎么把多個 action 組合起來,處理復雜的異步工作流?
store.dispatch()
方法返回了我們定義的 action handler 的返回值,所以我們可以直接返回一個 Promise 呀~
actions: {
actionA ({ commit }) {
returnnewPromise((resolve, reject) =&{
setTimeout(()=&{
commit('someMutation')
可以這么用
store.dispatch('actionA').then(()=&{
然后在另一個 action 中
actions: {
actionB ({ dispatch, commit }) {
returndispatch('actionA').then(()=&{
commit('someOtherMutation')
由於 Vuex 使用了單狀態樹,所以隨着我們應用的規模逐漸增大, store 也越來越膨脹。為了應對這個問題,Vuex 允許我們將 store 分成多個 modules。每個 module 有着自己的 state, mutations, actions, getters, 甚至可以有嵌套( nested )的 modules。比如說:
constmoduleA = {
state: { ... },
mutations: { ... },
actions: { ... },
getters: { ... }
constmoduleB = {
state: { ... },
mutations: { ... },
actions: { ... }
conststore =newVuex.Store({
modules: {
a: moduleA,
b: moduleB
// 注意,調用的時候,多個模塊都在 state 對象中,而非 modules 中
store.state.a // -& moduleA's state
store.state.b // -& moduleB's state
modules 中的各種 state , local or root?
mutations 和 getters 中,接受的第一個參數是 modules 的本地 state
constmoduleA = {
state: {count:0},
mutations: {
increment: (state) {
// state is the local module state
state.count++
getters: {
doubleCount (state) {
returnstate.count *2
相似地,在 actions 中,
context.state
為本地 state,而
context.rootState
為根 state
constmoduleA = {
actions: {
incrementIfOdd ({ state, commit }) {
if(state.count %2===1) {
commit('increment')
getters 的第三個參數才是 root state
constmoduleA = {
getters: {
sumWithRootCount (state, getters, rootState) {
returnstate.count + rootState.count
Strict Mode & Form Handling
嚴格模式下,如果在 mutation handler 之外修改了 Vuex 的 state,應用就會拋錯。比如我們將 Vuex 中的某個數據,用 Vue 的 v-model 綁定到 input 時,一旦感應到 input 改動,就會嘗試去直接修改這個數據,嚴格模式下就會報錯。所以建議是綁定 value 值,然后在 input 時調用 action 。
&input:value="message"@input="updateMessage"&
computed: {
...mapState({
message:state=&state.obj.message
methods: {
updateMessage (e) {
this.$mit('updateMessage', e.target.value)
mutation 可以這么處理
mutations: {
updateMessage (state, message) {
state.obj.message = message
誠然,這樣做是很仔細明了的,但是我們也不能用 v-model 這么好用的方法了,另外一個方法就是繼續使用 v-model ,並配套使用 雙向計算屬性和 setter 。
computed: {
message: {
returnthis.$store.state.obj.message
set (value) {
// 直接 commit 到 mutation,type 為 updateMessage
this.$mit('updateMessage', value)
建議部署到開發環境的時候一定一定要關掉嚴格模式。
已發表評論數()
請填寫推刊名
描述不能大於100個字符!
權限設置: 公開
僅自己可見
正文不准確
標題不准確
排版有問題
主題不准確
沒有分頁內容
圖片無法顯示
視頻無法顯示
與原文不一致如何使用Vuex+Vue.js構建單頁應用
作者:懂懂懂懂懂懂懂濤大人
字體:[ ] 類型:轉載 時間:
這篇文章主要教大家如何使用Vuex+Vue.js構建單頁應用,具有一定的參考價值,感興趣的小伙伴們可以參考一下
前言:在最近學習 Vue.js 的時候,看到國外一篇講述了如何使用 Vue.js 和 Vuex 來構建一個簡單筆記的單頁應用的文章。感覺收獲挺多,自己在它的例子的基礎上進行了一些優化和自定義功能,在這里和大家分享下學習心得。
在這篇教程中我們將通過構建一個筆記應用來學習如何在我們的 Vue 項目中使用 Vuex。我們將大概的過一遍什么是 Vuex.js,在項目中什么時候使用它,和如何構建我們的 Vue 應用。
這里放一張我們項目的預覽圖片:
項目源碼:;有需要的同學可以直接下載源碼查看。
主要知識點
狀態管理機制的使用
的基礎 api
腳手架的安裝及使用
的語法,這里推薦看下阮一峰的入門教程
在我們迫不及待的開始項目之前,我們最好先花幾分鍾來了解下 Vuex 的核心概念。
Vuex 是一個專門為 Vue.js 應用所設計的集中式狀態管理架構。它借鑒了 Flux 和 Redux 的設計思想,但簡化了概念,並且采用了一種為能更好發揮 Vue.js 數據響應機制而專門設計的實現。
state 這樣概念初次接觸的時候可能會感覺到有點模糊,簡單來說就是將 state 看成我們項目中使用的數據的集合。然后,Vuex 使得 組件本地狀態(component local state)和 應用層級狀態(application state) 有了一定的差異。
component local state:該狀態表示僅僅在組件內部使用的狀態,有點類似通過配置選項傳入 Vue 組件內部的意思。
application level state:應用層級狀態,表示同時被多個組件共享的狀態層級。
假設有這樣一個場景:我們有一個父組件,同時包含兩個子組件。父組件可以很容易的通過使用 props 屬性來向子組件傳遞數據。
但是問題來了,當我們的兩個子組件如何和對方互相通信的? 或者子組件如何傳遞數據給他父組件的?在我們的項目很小的時候,這個兩個問題都不會太難,因為我們可以通過事件派發和監聽來完成父組件和子組件的通信。
然而,隨着我們項目的增長:
1、保持對所有的事件追蹤將變得很困難。到底哪個事件是哪個組件派發的,哪個組件該監聽哪個事件?
2、項目邏輯分散在各個組件當中,很容易導致邏輯的混亂,不利於我們項目的維護。
3、父組件將變得和子組件耦合越來越嚴重,因為它需要明確的派發和監聽子組件的某些事件。
這就是 Vuex 用來解決的問題。 Vuex 的四個核心概念分別是:
The state tree:Vuex 使用單一狀態樹,用一個對象就包含了全部的應用層級狀態。至此它便作為一個『唯一數據源(SSOT)』而存在。這也意味着,每個應用將僅僅包含一個 store 實例。單狀態樹讓我們能夠直接地定位任一特定的狀態片段,在調試的過程中也能輕易地取得整個當前應用狀態的快照。
Getters:用來從 store 獲取 Vue 組件數據。
Mutators:事件處理器用來驅動狀態的變化。
Actions:可以給組件使用的函數,以此用來驅動事件處理器 mutations
如何你暫時還不太理解這個四個概念,不用着急,我們將在后面的項目實戰中詳細的解釋。
下面這張圖詳細的解釋了 Vuex 應用中數據的流向(Vuex 官方圖)
簡單解釋下:
Vuex 規定,屬於應用層級的狀態只能通過 Mutation 中的方法來修改,而派發 Mutation 中的事件只能通過 action。
從左到又,從組件出發,組件中調用 action,在 action 這一層級我們可以和后台數據交互,比如獲取初始化的數據源,或者中間數據的過濾等。然后在 action 中去派發 Mutation。Mutation 去觸發狀態的改變,狀態的改變,將觸發視圖的更新。
數據流都是單向的
組件能夠調用 action
action 用來派發 Mutation
只有 mutation 可以改變狀態
store 是響應式的,無論 state 什么時候更新,組件都將同步更新
這個應用將使用 webpack 來做模塊打包,處理和熱重啟。使用 Vue 官方提供的腳手架 vue-cli。
安裝 vue-cli
npm install -g vue-cli
注:Node.js &= 4.x, 5.x 最好
初始化應用
vue init webpack vue-notes-app
cd vue-notes-app
npm install // 安裝依賴包
npm run dev // 啟動服務
初始化一個項目名為vue-notes-app的應用,並選擇使用 webpack 打包方式。在命令行中按照提示選擇初始化配置項。其中在選擇 JSLint 校驗的時候,推薦選擇 AirBNB 規范。
使用你最喜歡的編輯器打開我們剛剛新建的項目,項目的結構大概如下圖:
components/ 文件夾用來存放我們的 Vue 組件
vuex/ 文件夾存放的是和 Vuex store 相關的東西(state object,actions,mutators)
build/ 文件是 webpack 的打包編譯配置文件
config/ 文件夾存放的是一些配置項,比如我們服務器訪問的端口配置等
dist/ 該文件夾一開始是不存在,在我們的項目經過 build 之后才會產出
App.vue 根組件,所有的子組件都將在這里被引用
index.html 整個項目的入口文件,將會引用我們的根組件 App.vue
main.js 入口文件的 js 邏輯,在 webpack 打包之后將被注入到 index.html 中
新增筆記,新增一篇筆記,編輯區顯示空的筆記內容
刪除筆記,刪除一篇筆記之后,編輯區域顯示當前筆記類別的第一項
筆記列表切換,分為全部筆記和收藏筆記兩種,在切換之后,編輯區域顯示當前列表的第一條筆記
收藏筆記,給當前激活的筆記打上收藏的標簽
項目組件划分
在這個項目中,我們將總共使用四個組件:根組件 App.vue,操作欄組件 Toolbar.vue,別表組件 NotesList.vue,筆記編輯組件 Editor.vue。
創建 Vuex Store
按照上面我們列出來的功能模塊,我們在 Vuex/ 下面建立一個 store.js 文件。
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
// 需要維護的狀態
const state = {
notes: [],
activeNote: {},
const mutations = {
// 初始化 state
INIT_STORE(state, data) {
state.notes = data.notes,
state.show = data.
state.activeNote = data.activeN
// 新增筆記
NEW_NOTE(state) {
var newNote = {
id: +new Date(),
title: '',
content: '',
favorite: false
state.notes.push(newNote);
state.activeNote = newN
// 修改筆記
EDIT_NOTE(state, note) {
state.activeNote =
// 修改原始數據
for (var i = 0; i & state.notes. i++) {
if(state.notes[i].id === note.id){
state.notes[i] =
// 刪除筆記
DELETE_NOTE(state) {
state.notes.$remove(state.activeNote);
state.activeNote = state.notes[0] || {};
// 切換筆記的收藏與取消收藏
TOGGLE_FAVORITE(state) {
state.activeNote.favorite = !state.activeNote.
// 切換顯示數據列表類型:全部 or 收藏
SET_SHOW_ALL(state, show){
state.show =
// 切換數據展示,需要同步更新 activeNote
if(show === 'favorite'){
state.activeNote = state.notes.filter(note =& note.favorite)[0] || {};
state.activeNote = state.notes[0] || {};
// 設置當前激活的筆記
SET_ACTIVE_NOTE(state, note) {
state.activeNote =
export default new Vuex.Store({
創建 Vuex Actions
在 Vuex/ 下面建立一個 action.js,用來給組件使用的函數。
function makeAction(type) {
return ({ dispatch }, ...args) =& dispatch(type, ...args);
const initNote = {
id: +new Date(),
title: '我的筆記',
content: '第一篇筆記內容',
favorite: false
// 模擬初始化數據
const initData = {
show: 'all',
notes: [initNote],
activeNote: initNote
export const initStore = ({ dispatch }) =& {
dispatch('INIT_STORE', initData);
// 更新當前activeNote對象
export const updateActiveNote = makeAction('SET_ACTIVE_NOTE');
// 添加一個note對象
export const newNote = makeAction('NEW_NOTE');
// 刪除一個note對象
export const deleteNote = makeAction('DELETE_NOTE');
export const toggleFavorite = makeAction('TOGGLE_FAVORITE');
export const editNote = makeAction('EDIT_NOTE');
// 更新列表展示
export const updateShow = makeAction('SET_SHOW_ALL');
創建 Vuex Getters
在 vuex/ 下面建立一個 getter.js 文件,用來從 store 獲取數據。
// 獲取 noteList,這里將會根據 state.show 的狀態做數據過濾
export const filteredNotes = (state) =& {
if(state.show === 'all'){
return state.notes || {};
}else if(state.show === 'favorite'){
return state.notes.filter(note =& note.favorite) || {};
// 獲取列表展示狀態 : all or favorite
export const show = (state) =& {
return state.
// 獲取當前激活 note
export const activeNote = (state) =& {
return state.activeN
以上就是我們 Vuex 的所有邏輯了,在定下了我們需要完成的功能之后,接下來就是只需要在組件中去調用 action 來實現對應的功能了。
在這里我們將使用 vue-router 來做路由,引用 bootstrap 樣式。
index.html
&!DOCTYPE html&
&meta charset="utf-8"&
&title&vuex-notes-app&/title&
&link rel="stylesheet" href="/bootstrap/3.3.6/css/bootstrap.min.css"&
&div id="app"&&/div&
&!-- built files will be auto injected --&
所有的入口邏輯我們都將在 main.js 中編寫
import Vue from 'vue';
import App from './App';
import VueRouter from 'vue-router';
import VueResource from 'vue-resource';
// 路由模塊和HTTP模塊
Vue.use(VueResource);
Vue.use(VueRouter);
const router = new VueRouter();
router.map({
'/index': {
component: App
router.redirect({
'*': '/index'
router.start(App, '#app');
根組件 App.vue
&template&
&div id="app" class="app"&
&toolbar&&/toolbar&
¬es-list&&/notes-list&
&editor&&/editor&
&/template&
html, #app {
height: 100%;
margin: 0;
padding: 0;
border: 0;
height: 100%;
max-height: 100%;
import Toolbar from './components/Toolbar';
import NotesList from './components/NotesList';
import Editor from './components/Editor';
import store from './vuex/store';
import { initStore } from './vuex/actions';
export default {
components: {
NotesList,
actions: {
this.initStore()
在根組件中引用了三個子組件:Toolbar.vue, NotesList.vue, Editor.vue。
注意:我們在配置里面加入了 vuex 這么一個選項,這里用來將我們 action 里面定義的方法給暴露出來,我們在根組件中只做了一件事情,那就是初始化模擬數據,因此我們在組件生命周期的 ready 階段調用了 actions 里面的 initStore 來初始化我們的 store 里面的 state
Toolbar.vue
&template&
&div id="toolbar"&
&i class="glyphicon logo"&&img src="../assets/logo.png" width="30" height="30"&&/i&
&i @click="newNote" class="glyphicon glyphicon-plus"&&/i&
&i @click="toggleFavorite" class="glyphicon glyphicon-star" :class="{starred: activeNote.favorite}"&&/i&
&i @click="deleteNote" class="glyphicon glyphicon-remove"&&/i&
&/template&
import { newNote, deleteNote, toggleFavorite } from '../vuex/actions';
import { activeNote } from '../vuex/getters';
export default {
getters: {
activeNote
actions: {
deleteNote,
toggleFavorite
&style lang="scss" scoped&
height: 100%;
color: #767676;
padding: 35px 25px 25px 25
.starred {
color: #F7AE4F;
font-size: 30
margin-bottom: 35
opacity: 0.8;
transition: opacity 0.5
opacity: 1;
在這里,我們用到了 Vuex 的一個案例就是我們需要知道當前的激活的筆記是否是收藏類別的,如果是,我們需要高亮收藏按鈕,那么如何知道呢?那就是通過 vuex 里面的 getters 獲取當前激活的筆記對象,判斷它的 favorite 是否為 true。
始終牢記一個概念,vuex 中數據是單向的,只能從 store 獲取,而我們這個例子中的 activeNote 也是始終都在 store.js 中維護的,這樣子就可以給其他組件公用了
// 需要維護的狀態
const state = {
notes: [],
activeNote: {},
NotesList.vue
&template&
&div id="notes-list"&
&div id="list-header"&
&h2&Notes | &/h2&
&div class="btn-group btn-group-justified" role="group"&
&!-- all --&
&div class="btn-group" role="group"&
&button type="button" class="btn btn-default"
@click="toggleShow('all')"
:class="{active: show === 'all'}"&All Notes&/button&
&!-- favorites --&
&div class="btn-group" role="group"&
&button type="button" class="btn btn-default"
@click="toggleShow('favorite')"
:class="{active: show === 'favorite'}"&Favorites&/button&
&!-- 渲染筆記列表 --&
&div class="container"&
&div class="list-group"&
&a v-for="note in filteredNotes"
class="list-group-item" href="#"
:class="{active: activeNote === note}"
@click="updateActiveNote(note)"&
&h4 class="list-group-item-heading"&
{{note.title.trim().substring(0,30)}}
&/template&
import { updateActiveNote, updateShow } from '../vuex/actions';
import { show, filteredNotes, activeNote } from '../vuex/getters';
export default {
getters: {
filteredNotes,
activeNote
actions: {
updateActiveNote,
updateShow
methods: {
toggleShow(show) {
this.updateShow(show);
筆記列表組件,主要有三個操作
切換渲染筆記
點擊列表 title,切換 activeNote
我們通過 getters 中的 filteredNotes 方法獲取筆記列表
// 獲取 noteList,這里將會根據 state.show 的狀態做數據過濾
export const filteredNotes = (state) =& {
if(state.show === 'all'){
return state.notes || {};
}else if(state.show === 'favorite'){
return state.notes.filter(note =& note.favorite) || {};
可以看到,我們獲取的列表是依賴於 state.show 這個狀態的。而我們的切換列表操作恰好就是調用 actions 里面的方法來更新 state.show,這樣一來,實現了數據列表的動態刷新,而且我們對樹的操作都是通過調用 actions 的方法來實現的。
我們再看,在切換列表的時候,我們還需要動態的更新 activeNote。看看我們在 store.js 中是如何做的:
// 切換顯示數據列表類型:全部 or 收藏
SET_SHOW_ALL(state, show){
state.show =
// 切換數據展示,需要同步更新 activeNote
if(show === 'favorite'){
state.activeNote = state.notes.filter(note =& note.favorite)[0] || {};
state.activeNote = state.notes[0] || {};
觸發這些操作的是我們給兩個按鈕分別綁定了我們自定義的函數,通過給函數傳入不同的參數,然后調用 actions 里面的方法,來實現對數據的過濾,更新。
Editor.vue
&template&
&div id="note-editor"&
&div class="form-group"&
&input type="text" name="title"
class="title form-control"
placeholder="請輸入標題"
@input="updateNote"
v-model="currentNote.title"&
v-model="currentNote.content" name="content"
class="form-control" row="3" placeholder="請輸入正文"
@input="updateNote"&&/textarea&
&/template&
import { editNote } from '../vuex/actions';
import { activeNote } from '../vuex/getters';
export default {
getters: {
activeNote
actions: {
computed: {
// 通過計算屬性得到的一個對象,這樣子我們就能愉快的使用 v-model 了
currentNote: activeNote
methods: {
// 為什么這么做? 因為在嚴格模式中不允許直接在模板層面去修改 state 中的值
updateNote() {
this.editNote(this.currentNote);
在 Editor.vue 組件中,我們需要能夠實時的更新當前的 activeNote 組件和列表中對應的我們正在修改的筆記對象的內容。
由於我們前面提到過,在組件中是不允許直接修改 store.js在里面的狀態值的,所以在這里的時候,我們通過一個計算屬性,將 store 里面的狀態值賦值給一個對象,然后在自定義的 updateNotes() 方法中,去調用 action,同時傳入 currentNote 對象。
在 store.js 中,我們是這么做的,找到對應的 id 的對象,重新賦值,因為前面提到過,我們的數據是響應式的,在這里進行了改變,對應的視圖也將刷新改變,這樣一來就實現了實時編輯,實時渲染的功能了。
// 修改筆記
EDIT_NOTE(state, note) {
state.activeNote =
// 修改原始數據
for (var i = 0; i & state.notes. i++) {
if(state.notes[i].id === note.id){
state.notes[i] =
在這個項目中,我們並沒有引入 vue-resource 插件,只是自己模擬了部分的數據,有興趣的同學可以自己去試試。