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