摘要:如果不熟悉,在這個教程里面,我們會通過構建一個筆記應用來學習怎么用。這個是我們要構建的筆記應用的截圖你可以從下載源碼,這里是的地址。每當用戶點擊筆記列表中的某一條時,組件會調用來分發這個會把當前選中的筆記設為。
原文:Learn Vuex by Building a Notes App,有刪改。
本文假設讀者熟悉 Vuex 文檔 的內容。如果不熟悉,you definitely should!
在這個教程里面,我們會通過構建一個筆記應用來學習怎么用 Vuex。我會簡單地介紹一下 Vuex 的基礎內容, 什么時候該用它以及用 Vuex 的時候該怎么組織代碼,然后我會一步一步地把這些概念應用到這個筆記應用里面。
這個是我們要構建的筆記應用的截圖:
你可以從 Github Repo 下載源碼,這里是 demo 的地址。
Vuex 概述Vuex 是一個主要應用在中大型單頁應用的類似于 Flux 的數據管理架構。它主要幫我們更好地組織代碼,以及把應用內的的狀態保持在可維護、可理解的狀態。
如果你不太理解 Vue.js 應用里的狀態是什么意思的話,你可以想象一下你此前寫的 Vue 組件里面的 data 字段。Vuex 把狀態分成組件內部狀態和應用級別狀態:
組件內部狀態:僅在一個組件內使用的狀態(data 字段)
應用級別狀態:多個組件共用的狀態
舉個例子:比如說有一個父組件,它有兩個子組件。這個父組件可以用 props 向子組件傳遞數據,這條數據通道很好理解。
那如果這兩個子組件相互之間需要共享數據呢?或者子組件需要向父組件傳遞數據呢?這兩個問題在應用體量較小的時候都好解決,只要用自定義事件即可。
但是隨著應用規模的擴大:
追蹤這些事件越來越難了。這個事件是哪個組件觸發的?誰在監聽它?
業務邏輯遍布各個組件,導致各種意想不到的問題。
由于要顯式地分發和監聽事件,父組件和子組件強耦合。
Vuex 要解決的就是這些問題,Vuex 背后有四個核心的概念:
狀態樹: 包含所有應用級別狀態的對象
Getters: 在組件內部獲取 store 中狀態的函數
Mutations: 修改狀態的事件回調函數
Actions: 組件內部用來分發 mutations 事件的函數
下面這張圖完美地解釋了一個 Vuex 應用內部的數據流動:
這張圖的重點:
數據流動是單向的
組件可以調用 actions
Actions 是用來分發 mutations 的
只有 mutations 可以修改狀態
store 是反應式的,即,狀態的變化會在組件內部得到反映
搭建項目項目結構是這樣的:
components/包含所有的組件
vuex/包含 Vuex 相關的文件 (store, actions)
build.js是 webpack 將要輸出的文件
index.html是要渲染的頁面
main.js是應用的入口點,包含了根實例
style.css
webpack.config.js
新建項目:
mkdir vuex-notes-app && cd vuex-note-app npm init -y
安裝依賴:
npm install webpack webpack-dev-server vue-loader vue-html-loader css-loader vue-style-loader vue-hot-reload-api babel-loader babel-core babel-plugin-transform-runtime babel-preset-es2015 babel-runtime@5 --save-dev npm install vue vuex --save
然后配置 Webpack:
// webpack.config.js module.exports = { entry: "./main.js", output: { path: __dirname, filename: "build.js" }, module: { loaders: [ { test: /.vue$/, loader: "vue" }, { test: /.js$/, loader: "babel", exclude: /node_modules/ } ] }, babel: { presets: ["es2015"], plugins: ["transform-runtime"] } }
然后在 package.json 里面配置一下 npm script:
"scripts": { "dev": "webpack-dev-server --inline --hot", "build": "webpack -p" }
后面測試和生產的時候直接運行npm run dev和npm run build就行了。
創建 Vuex Store在 vuex/文件夾下創建一個 store.js:
import Vue from "vue" import Vuex from "vuex" Vue.use(Vuex) const state = { notes: [], activeNote: {} } const mutations = { ... } export default new Vuex.Store({ state, mutations })
現在我用下面這張圖把應用分解成多個組件,并把組件內部需要的數據對應到 store.js 里的 state。
App, 根組件,就是最外面那個紅色的盒子
Toolbar 是左邊的綠色豎條,包括三個按鈕
NotesList 是包含了筆記標題列表的紫色框。用戶可以點擊所有筆記(All Notes)或者收藏筆記(Favorites)
Editor 是右邊這個可以編輯筆記內容的黃色框
store.js 里面的狀態對象會包含所有應用級別的狀態,也就是各個組件需要共享的狀態。
筆記列表(notes: [])包含了 NodesList 組件要渲染的 notes 對象。當前筆記(activeNote: {})則包含當前選中的筆記對象,多個組件都需要這個對象:
Toolbar 組件的收藏和刪除按鈕都對應這個對象
NotesList 組件通過 CSS 高亮顯示這個對象
Editor 組件展示及編輯這個筆記對象的內容。
聊完了狀態(state),我們來看看 mutations, 我們要實現的 mutation 方法包括:
添加筆記到數組里 (state.notes)
把選中的筆記設置為「當前筆記」(state.activeNote)
刪掉當前筆記
編輯當前筆記
收藏/取消收藏當前筆記
首先,要添加一條新筆記,我們需要做的是:
新建一個對象
初始化屬性
push 到state.notes里去
把新建的這條筆記設為當前筆記(activeNote)
ADD_NOTE (state) { const new Note = { text: "New note", favorite: fals } state.notes.push(newNote) state.activeNote= newNote }
然后,編輯筆記需要用筆記內容 text 作參數:
EDIT_NOTE (state, text) { state.activeNote.text = text }
剩下的這些 mutations 很簡單就不一一贅述了。整個 vuex/store.js 是這個樣子的:
import Vue from "vue" import Vuex from "vuex" Vue.use(Vuex) const state = { note: [], activeNote: {} } const mutations = { ADD_NOTE (state) { const newNote = { text: "New Note", favorite: false } state.notes.push(newNote) state.activeNote = newNote }, EDIT_NOTE (state, text) { state.activeNote.text = text }, DELETE_NOTE (state) { state.notes.$remove(state.activeNote) state.activeNote = state.notes[0] }, TOGGLE_FAVORITE (state) { state.activeNote.favorite = !state.activeNote.favorite }, SET_ACTIVE_NOTE (state, note) { state.activeNote = note } } export default new Vuex.Store({ state, mutations })
接下來聊 actions, actions 是組件內用來分發 mutations 的函數。它們接收 store 作為第一個參數。比方說,當用戶點擊 Toolbar 組件的添加按鈕時,我們想要調用一個能分發ADD_NOTE mutation 的 action。現在我們在 vuex/文件夾下創建一個 actions.js 并在里面寫上 addNote函數:
// actions.js export const addNote = ({ dispatch }) => { dispatch("ADD_NOTE") }
剩下的這些 actions 都跟這個差不多:
export const addNote = ({ dispatch }) => { dispatch("ADD_NOTE") } export const editNote = ({ dispatch }, e) => { dispatch("EDIT_NOTE", e.target.value) } export const deleteNote = ({ dispatch }) => { dispatch("DELETE_NOTE") } export const updateActiveNote = ({ dispatch }, note) => { dispatch("SET_ACTIVE_NOTE", note) } export const toggleFavorite = ({ dispatch }) => { dispatch("TOGGLE_FAVORITE") }
這樣,在 vuex 文件夾里面要寫的代碼就都寫完了。這里面包括了 store.js 里的 state 和 mutations,以及 actions.js 里面用來分發 mutations 的 actions。
構建 Vue 組件最后這個小結,我們來實現四個組件 (App, Toolbar, NoteList 和 Editor) 并學習怎么在這些組件里面獲取 Vuex store 里的數據以及調用 actions。
創建根實例 - main.jsmain.js是應用的入口文件,里面有根實例,我們要把 Vuex store 加到到這個根實例里面,進而注入到它所有的子組件里面:
import Vue from "vue" import store from "./vuex/store" import App from "./components/App.vue" new Vue({ store, // 注入到所有子組件 el: "body", components: { App } })App - 根組件
根組件 App 會 import 其余三個組件:Toolbar, NotesList 和 Editor:
把 App 組件放到 index.html 里面,用 BootStrap 提供基本樣式,在 style.css 里寫組件相關的樣式:
ToolbarNotes | coligo.io
Toolbar 組件提供給用戶三個按鈕:創建新筆記,收藏當前選中的筆記和刪除當前選中的筆記。
這對于 Vuex 來說是個絕佳的用例,因為 Toolbar 組件需要知道「當前選中的筆記」是哪一條,這樣我們才能刪除、收藏/取消收藏它。前面說了「當前選中的筆記」是各個組件都需要的,不應該多帶帶存在于任何一個組件里面,這時候我們就能發現共享數據的必要性了。
每當用戶點擊筆記列表中的某一條時,NodeList 組件會調用updateActiveNote() action 來分發 SET_ACTIVE_NOTE mutation, 這個 mutation 會把當前選中的筆記設為 activeNote。
也就是說,Toolbar 組件需要從 state 獲取 activeNote 屬性:
vuex: { getters: { activeNote: state => state.activeNote } }
我們也需要把這三個按鈕所對應的 actions 引進來,因此 Toolbar.vue 就是這樣的:
注意到當 activeNote.favorite === true的時候,收藏按鈕還有一個 starred 的類名,這個類的作用是對收藏按鈕提供高亮顯示。
NotesListNotesList 組件主要有三個功能:
把筆記列表渲染出來
允許用戶選擇"所有筆記"或者只顯示"收藏的筆記"
當用戶點擊某一條時,調用updateActiveNoteaction 來更新 store 里的 activeNote
顯然,在 NoteLists 里需要 store 里的notes array和activeNote:
vuex: { getters: { notes: state => state.notes, activeNote: state => state.activeNote } }
當用戶點擊某一條筆記時,把它設為當前筆記:
import { updateActiveNote } from "../vuex/actions" export default { vuex: { getters: { // as shown above }, actions: { updateActiveNote } } }
接下來,根據用戶點擊的是"所有筆記"還是"收藏筆記"來展示過濾后的列表:
import { updateActiveNote } from "../vuex/actions" export default { data () { return { show: "all" } }, vuex: { // as shown above }, computed: { filteredNotes () { if (this.show === "all"){ return this.notes } else if (this.show === "favorites") { return this.notes.filter(note => note.favorite) } } } }
在這里組件內的 show 屬性是作為組件內部狀態出現的,很明顯,它只在 NoteList 組件內出現。
以下是完整的 NotesList.vue:
Notes | coligo
這個組件的幾個要點:
用前30個字符當作該筆記的標題
當用戶點擊一條筆記,該筆記變成當前選中筆記
在"all"和"favorite"之間選擇實際上就是設置 show 屬性
通過:class=""設置樣式
EditorEditor 組件是最簡單的,它只做兩件事:
從 store 獲取當前筆記activeNote,把它的內容展示在 textarea
在用戶更新筆記的時候,調用 editNote() action
以下是完整的 Editor.vue:
這里的 textarea 不用 v-model 的原因在 vuex 文檔里面有詳細的說明。
至此,這個應用的代碼就寫完了,不明白的地方可以看源代碼, 然后動手操練一遍。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/79311.html
摘要:鑒于該篇文章閱讀量大,回復的同學也挺多的,特地抽空寫了一篇下的使用方法,傳送門使用構建單頁應用新篇華麗的分割線原文地址前言在最近學習的時候,看到國外一篇講述了如何使用和來構建一個簡單筆記的單頁應用的文章。 鑒于該篇文章閱讀量大,回復的同學也挺多的,特地抽空寫了一篇 vue2.0 下的 vuex 使用方法,傳送門:使用 Vuex + Vue.js 構建單頁應用【新篇】 ---------...
摘要:鑒于該篇文章閱讀量大,回復的同學也挺多的,特地抽空寫了一篇下的使用方法,傳送門使用構建單頁應用新篇華麗的分割線原文地址前言在最近學習的時候,看到國外一篇講述了如何使用和來構建一個簡單筆記的單頁應用的文章。 鑒于該篇文章閱讀量大,回復的同學也挺多的,特地抽空寫了一篇 vue2.0 下的 vuex 使用方法,傳送門:使用 Vuex + Vue.js 構建單頁應用【新篇】 ---------...
摘要:鑒于該篇文章閱讀量大,回復的同學也挺多的,特地抽空寫了一篇下的使用方法,傳送門使用構建單頁應用新篇華麗的分割線原文地址前言在最近學習的時候,看到國外一篇講述了如何使用和來構建一個簡單筆記的單頁應用的文章。 鑒于該篇文章閱讀量大,回復的同學也挺多的,特地抽空寫了一篇 vue2.0 下的 vuex 使用方法,傳送門:使用 Vuex + Vue.js 構建單頁應用【新篇】 ---------...
摘要:鑒于該篇文章閱讀量大,回復的同學也挺多的,特地抽空寫了一篇下的使用方法,傳送門使用構建單頁應用新篇華麗的分割線原文地址前言在最近學習的時候,看到國外一篇講述了如何使用和來構建一個簡單筆記的單頁應用的文章。 鑒于該篇文章閱讀量大,回復的同學也挺多的,特地抽空寫了一篇 vue2.0 下的 vuex 使用方法,傳送門:使用 Vuex + Vue.js 構建單頁應用【新篇】 ---------...
摘要:鑒于該篇文章閱讀量大,回復的同學也挺多的,特地抽空寫了一篇下的使用方法,傳送門使用構建單頁應用新篇華麗的分割線原文地址前言在最近學習的時候,看到國外一篇講述了如何使用和來構建一個簡單筆記的單頁應用的文章。 鑒于該篇文章閱讀量大,回復的同學也挺多的,特地抽空寫了一篇 vue2.0 下的 vuex 使用方法,傳送門:使用 Vuex + Vue.js 構建單頁應用【新篇】 ---------...
閱讀 2242·2021-09-23 11:52
閱讀 1910·2021-09-02 15:41
閱讀 3028·2019-08-30 10:47
閱讀 1993·2019-08-29 17:14
閱讀 2348·2019-08-29 16:16
閱讀 3198·2019-08-28 18:29
閱讀 3429·2019-08-26 13:30
閱讀 2617·2019-08-26 10:49