欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

如何使用Vuex+Vue.js構建單頁應用

 更新時間:2016年10月27日 09:04:51   作者:懂懂懂懂懂懂懂濤大人  
這篇文章主要教大家如何使用Vuex+Vue.js構建單頁應用,具有一定的參考價值,感興趣的小伙伴們可以參考一下

前言:在最近學習 Vue.js 的時候,看到國外一篇講述了如何使用 Vue.js 和 Vuex 來構建一個簡單筆記的單頁應用的文章。感覺收獲挺多,自己在它的例子的基礎上進行了一些優(yōu)化和自定義功能,在這里和大家分享下學習心得。

在這篇教程中我們將通過構建一個筆記應用來學習如何在我們的 Vue 項目中使用 Vuex。我們將大概的過一遍什么是 Vuex.js,在項目中什么時候使用它,和如何構建我們的 Vue 應用。

這里放一張我們項目的預覽圖片:

項目源碼:vuex-notes-app;有需要的同學可以直接下載源碼查看。

主要知識點
Vuex 狀態(tài)管理機制的使用
Vue.js 的基礎 api
Vue-cli 腳手架的安裝及使用
vur-router 的使用
ES6 的語法,這里推薦看下阮一峰的入門教程

Vuex 概述
在我們迫不及待的開始項目之前,我們最好先花幾分鐘來了解下 Vuex 的核心概念。

Vuex 是一個專門為 Vue.js 應用所設計的集中式狀態(tài)管理架構。它借鑒了 Flux 和 Redux 的設計思想,但簡化了概念,并且采用了一種為能更好發(fā)揮 Vue.js 數(shù)據(jù)響應機制而專門設計的實現(xiàn)。

state 這樣概念初次接觸的時候可能會感覺到有點模糊,簡單來說就是將 state 看成我們項目中使用的數(shù)據(jù)的集合。然后,Vuex 使得 組件本地狀態(tài)(component local state)和 應用層級狀態(tài)(application state) 有了一定的差異。

component local state:該狀態(tài)表示僅僅在組件內(nèi)部使用的狀態(tài),有點類似通過配置選項傳入 Vue 組件內(nèi)部的意思。
application level state:應用層級狀態(tài),表示同時被多個組件共享的狀態(tài)層級。

假設有這樣一個場景:我們有一個父組件,同時包含兩個子組件。父組件可以很容易的通過使用 props 屬性來向子組件傳遞數(shù)據(jù)。

但是問題來了,當我們的兩個子組件如何和對方互相通信的? 或者子組件如何傳遞數(shù)據(jù)給他父組件的?在我們的項目很小的時候,這個兩個問題都不會太難,因為我們可以通過事件派發(fā)和監(jiān)聽來完成父組件和子組件的通信。

然而,隨著我們項目的增長:

1、保持對所有的事件追蹤將變得很困難。到底哪個事件是哪個組件派發(fā)的,哪個組件該監(jiān)聽哪個事件?
2、項目邏輯分散在各個組件當中,很容易導致邏輯的混亂,不利于我們項目的維護。
3、父組件將變得和子組件耦合越來越嚴重,因為它需要明確的派發(fā)和監(jiān)聽子組件的某些事件。

這就是 Vuex 用來解決的問題。 Vuex 的四個核心概念分別是:

The state tree:Vuex 使用單一狀態(tài)樹,用一個對象就包含了全部的應用層級狀態(tài)。至此它便作為一個『唯一數(shù)據(jù)源(SSOT)』而存在。這也意味著,每個應用將僅僅包含一個 store 實例。單狀態(tài)樹讓我們能夠直接地定位任一特定的狀態(tài)片段,在調(diào)試的過程中也能輕易地取得整個當前應用狀態(tài)的快照。
Getters:用來從 store 獲取 Vue 組件數(shù)據(jù)。
Mutators:事件處理器用來驅動狀態(tài)的變化。
Actions:可以給組件使用的函數(shù),以此用來驅動事件處理器 mutations
如何你暫時還不太理解這個四個概念,不用著急,我們將在后面的項目實戰(zhàn)中詳細的解釋。

下面這張圖詳細的解釋了 Vuex 應用中數(shù)據(jù)的流向(Vuex 官方圖)

簡單解釋下:

Vuex 規(guī)定,屬于應用層級的狀態(tài)只能通過 Mutation 中的方法來修改,而派發(fā) Mutation 中的事件只能通過 action。

從左到又,從組件出發(fā),組件中調(diào)用 action,在 action 這一層級我們可以和后臺數(shù)據(jù)交互,比如獲取初始化的數(shù)據(jù)源,或者中間數(shù)據(jù)的過濾等。然后在 action 中去派發(fā) Mutation。Mutation 去觸發(fā)狀態(tài)的改變,狀態(tài)的改變,將觸發(fā)視圖的更新。

注意事項

數(shù)據(jù)流都是單向的
組件能夠調(diào)用 action
action 用來派發(fā) Mutation
只有 mutation 可以改變狀態(tài)
store 是響應式的,無論 state 什么時候更新,組件都將同步更新

環(huán)境安裝
這個應用將使用 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 規(guī)范。

使用你最喜歡的編輯器打開我們剛剛新建的項目,項目的結構大概如下圖:

components/ 文件夾用來存放我們的 Vue 組件
vuex/ 文件夾存放的是和 Vuex store 相關的東西(state object,actions,mutators)
build/ 文件是 webpack 的打包編譯配置文件
config/ 文件夾存放的是一些配置項,比如我們服務器訪問的端口配置等
dist/ 該文件夾一開始是不存在,在我們的項目經(jīng)過 build 之后才會產(chǎn)出
App.vue 根組件,所有的子組件都將在這里被引用
index.html 整個項目的入口文件,將會引用我們的根組件 App.vue
main.js 入口文件的 js 邏輯,在 webpack 打包之后將被注入到 index.html 中

功能模塊
新增筆記,新增一篇筆記,編輯區(qū)顯示空的筆記內(nèi)容
刪除筆記,刪除一篇筆記之后,編輯區(qū)域顯示當前筆記類別的第一項
筆記列表切換,分為全部筆記和收藏筆記兩種,在切換之后,編輯區(qū)域顯示當前列表的第一條筆記
收藏筆記,給當前激活的筆記打上收藏的標簽

項目組件劃分
在這個項目中,我們將總共使用四個組件:根組件 App.vue,操作欄組件 Toolbar.vue,別表組件 NotesList.vue,筆記編輯組件 Editor.vue。

創(chuàng)建 Vuex Store
按照上面我們列出來的功能模塊,我們在 Vuex/ 下面建立一個 store.js 文件。

import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

// 需要維護的狀態(tài)
const state = {
 notes: [],
 activeNote: {},
 show: ''
};

const mutations = {
 // 初始化 state
 INIT_STORE(state, data) {
 state.notes = data.notes,
 state.show = data.show;
 state.activeNote = data.activeNote;
 },
 // 新增筆記
 NEW_NOTE(state) {
 var newNote = {
 id: +new Date(),
 title: '',
 content: '',
 favorite: false
 };
 state.notes.push(newNote);
 state.activeNote = newNote;
 },
 // 修改筆記
 EDIT_NOTE(state, note) {
 state.activeNote = note;
 // 修改原始數(shù)據(jù)
 for (var i = 0; i < state.notes.length; i++) {
 if(state.notes[i].id === note.id){
 state.notes[i] = note;
 break;
 }
 };
 },
 // 刪除筆記
 DELETE_NOTE(state) {
 state.notes.$remove(state.activeNote);
 state.activeNote = state.notes[0] || {};
 },
 // 切換筆記的收藏與取消收藏
 TOGGLE_FAVORITE(state) {
 state.activeNote.favorite = !state.activeNote.favorite;
 },
 // 切換顯示數(shù)據(jù)列表類型:全部 or 收藏
 SET_SHOW_ALL(state, show){
 state.show = show;
 // 切換數(shù)據(jù)展示,需要同步更新 activeNote
 if(show === 'favorite'){
 state.activeNote = state.notes.filter(note => note.favorite)[0] || {};
 }else{
 state.activeNote = state.notes[0] || {};
 }
 },
 // 設置當前激活的筆記
 SET_ACTIVE_NOTE(state, note) {
 state.activeNote = note;
 }
};

export default new Vuex.Store({
 state,
 mutations
});

創(chuàng)建 Vuex Actions
在 Vuex/ 下面建立一個 action.js,用來給組件使用的函數(shù)。

function makeAction(type) {
 return ({ dispatch }, ...args) => dispatch(type, ...args);
};

const initNote = {
 id: +new Date(),
 title: '我的筆記',
 content: '第一篇筆記內(nèi)容',
 favorite: false
};

// 模擬初始化數(shù)據(jù)
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');
創(chuàng)建 Vuex Getters
在 vuex/ 下面建立一個 getter.js 文件,用來從 store 獲取數(shù)據(jù)。

// 獲取 noteList,這里將會根據(jù) state.show 的狀態(tài)做數(shù)據(jù)過濾
export const filteredNotes = (state) => {
 if(state.show === 'all'){
 return state.notes || {};
 }else if(state.show === 'favorite'){
 return state.notes.filter(note => note.favorite) || {};
 }
};


// 獲取列表展示狀態(tài) : all or favorite
export const show = (state) => {
 return state.show;
};

// 獲取當前激活 note
export const activeNote = (state) => {
 return state.activeNote;
};

以上就是我們 Vuex 的所有邏輯了,在定下了我們需要完成的功能之后,接下來就是只需要在組件中去調(diào)用 action 來實現(xiàn)對應的功能了。

路由配置
在這里我們將使用 vue-router 來做路由,引用 bootstrap 樣式。

index.html

<!DOCTYPE html>
<html>
 <head>
 <meta charset="utf-8">
 <title>vuex-notes-app</title>
 <link rel="stylesheet" >
 </head>
 <body>
 <div id="app"></div>
 <!-- built files will be auto injected -->
 </body>
</html>

所有的入口邏輯我們都將在 main.js 中編寫

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>
 <notes-list></notes-list>
 <editor></editor>
 </div>
</template>

<style>
 html, #app {
 height: 100%;
 }

 body {
 margin: 0;
 padding: 0;
 border: 0;
 height: 100%;
 max-height: 100%;
 position: relative;
 }
</style>

<script>
 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: {
 Toolbar,
 NotesList,
 Editor
 },
 store,
 vuex: {
 actions: {
 initStore
 }
 },
 ready() {
 this.initStore()
 }
 }
</script>

在根組件中引用了三個子組件:Toolbar.vue, NotesList.vue, Editor.vue。

注意:我們在配置里面加入了 vuex 這么一個選項,這里用來將我們 action 里面定義的方法給暴露出來,我們在根組件中只做了一件事情,那就是初始化模擬數(shù)據(jù),因此我們在組件生命周期的 ready 階段調(diào)用了 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>
 </div>
</template>

<script>
import { newNote, deleteNote, toggleFavorite } from '../vuex/actions';
import { activeNote } from '../vuex/getters';

export default {
 vuex: {
 getters: {
 activeNote
 },
 actions: {
 newNote,
 deleteNote,
 toggleFavorite
 }
 }
}
</script>

<style lang="scss" scoped>
 #toolbar{
 float: left;
 width: 80px;
 height: 100%;
 background-color: #30414D;
 color: #767676;
 padding: 35px 25px 25px 25px;

 .starred {
 color: #F7AE4F;
 }

 i{
 font-size: 30px;
 margin-bottom: 35px;
 cursor: pointer;
 opacity: 0.8;
 transition: opacity 0.5s ease;

 &:hover{
 opacity: 1;
 }
 }
 }
</style>

在這里,我們用到了 Vuex 的一個案例就是我們需要知道當前的激活的筆記是否是收藏類別的,如果是,我們需要高亮收藏按鈕,那么如何知道呢?那就是通過 vuex 里面的 getters 獲取當前激活的筆記對象,判斷它的 favorite 是否為 true。

始終牢記一個概念,vuex 中數(shù)據(jù)是單向的,只能從 store 獲取,而我們這個例子中的 activeNote 也是始終都在 store.js 中維護的,這樣子就可以給其他組件公用了

// 需要維護的狀態(tài)
const state = {
 notes: [],
 activeNote: {},
 show: ''
};
NotesList.vue
<template>
 <div id="notes-list">
 <div id="list-header">
 <h2>Notes | heavenru.com</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>
 </div>

 <!-- favorites -->
 <div class="btn-group" role="group">
 <button type="button" class="btn btn-default"
 @click="toggleShow('favorite')"
 :class="{active: show === 'favorite'}">Favorites</button>
 </div>
 </div>
 </div>

 <!-- 渲染筆記列表 -->
 <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)}}
 </h4>
 </a>
 </div>
 </div>
 </div>
</template>

<script>
 import { updateActiveNote, updateShow } from '../vuex/actions';
 import { show, filteredNotes, activeNote } from '../vuex/getters';

 export default {
 vuex: {
 getters: {
 show,
 filteredNotes,
 activeNote
 },
 actions: {
 updateActiveNote,
 updateShow
 }
 },
 methods: {
 toggleShow(show) {
 this.updateShow(show);
 }
 }
 }
</script>

筆記列表組件,主要有三個操作

渲染筆記
切換渲染筆記
點擊列表 title,切換 activeNote

我們通過 getters 中的 filteredNotes 方法獲取筆記列表

// 獲取 noteList,這里將會根據(jù) state.show 的狀態(tài)做數(shù)據(jù)過濾
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 這個狀態(tài)的。而我們的切換列表操作恰好就是調(diào)用 actions 里面的方法來更新 state.show,這樣一來,實現(xiàn)了數(shù)據(jù)列表的動態(tài)刷新,而且我們對樹的操作都是通過調(diào)用 actions 的方法來實現(xiàn)的。

我們再看,在切換列表的時候,我們還需要動態(tài)的更新 activeNote??纯次覀冊?store.js 中是如何做的:

// 切換顯示數(shù)據(jù)列表類型:全部 or 收藏
SET_SHOW_ALL(state, show){
 state.show = show;
 // 切換數(shù)據(jù)展示,需要同步更新 activeNote
 if(show === 'favorite'){
 state.activeNote = state.notes.filter(note => note.favorite)[0] || {};
 }else{
 state.activeNote = state.notes[0] || {};
 }
}

觸發(fā)這些操作的是我們給兩個按鈕分別綁定了我們自定義的函數(shù),通過給函數(shù)傳入不同的參數(shù),然后調(diào)用 actions 里面的方法,來實現(xiàn)對數(shù)據(jù)的過濾,更新。

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">
 <textarea
 v-model="currentNote.content" name="content"
 class="form-control" row="3" placeholder="請輸入正文"
 @input="updateNote"></textarea>
 </div>
 </div>
</template>

<script>
 import { editNote } from '../vuex/actions';
 import { activeNote } from '../vuex/getters';

 export default {
 vuex: {
 getters: {
 activeNote
 },
 actions: {
 editNote
 }
 },
 computed: {
 // 通過計算屬性得到的一個對象,這樣子我們就能愉快的使用 v-model 了
 currentNote: activeNote
 },
 methods: {
 // 為什么這么做? 因為在嚴格模式中不允許直接在模板層面去修改 state 中的值
 updateNote() {
 this.editNote(this.currentNote);
 }
 }
 }
</script>

在 Editor.vue 組件中,我們需要能夠實時的更新當前的 activeNote 組件和列表中對應的我們正在修改的筆記對象的內(nèi)容。

由于我們前面提到過,在組件中是不允許直接修改 store.js在里面的狀態(tài)值的,所以在這里的時候,我們通過一個計算屬性,將 store 里面的狀態(tài)值賦值給一個對象,然后在自定義的 updateNotes() 方法中,去調(diào)用 action,同時傳入 currentNote 對象。

在 store.js 中,我們是這么做的,找到對應的 id 的對象,重新賦值,因為前面提到過,我們的數(shù)據(jù)是響應式的,在這里進行了改變,對應的視圖也將刷新改變,這樣一來就實現(xiàn)了實時編輯,實時渲染的功能了。

// 修改筆記
EDIT_NOTE(state, note) {
 state.activeNote = note;
 // 修改原始數(shù)據(jù)
 for (var i = 0; i < state.notes.length; i++) {
 if(state.notes[i].id === note.id){
 state.notes[i] = note;
 break;
 }
 };
},

Q&A

在這個項目中,我們并沒有引入 vue-resource 插件,只是自己模擬了部分的數(shù)據(jù),有興趣的同學可以自己去試試。

由于我們的例子相對簡單,沒有涉及到很深入的東西,更深層次的研究需要大家花更多的時間去實踐了。

最后,再說一句,在 action 里面,我們其實可以做的還有更多,比如根據(jù) id 動態(tài)的異步獲取筆記內(nèi)容等等,這些有興趣的同學可以自己去嘗試,一點點的豐富這個例子。

原文地址:https://coligo.io/learn-vuex-by-building-notes-app/

本文已被整理到了《Vue.js前端組件學習教程》,歡迎大家學習閱讀。

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

  • VUE子組件的watch不被觸發(fā)問題及解決

    VUE子組件的watch不被觸發(fā)問題及解決

    這篇文章主要介紹了VUE子組件的watch不被觸發(fā)問題及解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • vue3基礎知識剖析

    vue3基礎知識剖析

    筆者這篇文章會從vue3基礎的知識點開始剖析,特別是在將composition?API的時候,在代碼示例中不會一上來就使用setup語法糖,而是用早期的setup函數(shù),這樣方便于初學的小伙伴們理解跟學習
    2022-08-08
  • Vue.js devtool插件安裝后無法使用的解決辦法

    Vue.js devtool插件安裝后無法使用的解決辦法

    Vue.js devtool插件最近在開發(fā)人員中很火,這篇文章主要為大家詳細介紹了Vue.js devtool插件安裝后無法使用,出現(xiàn)提示“vue.js not detected”的解決辦法
    2017-11-11
  • 在vue中使用express-mock搭建mock服務的方法

    在vue中使用express-mock搭建mock服務的方法

    這篇文章主要介紹了在vue中使用express-mock搭建mock服務的方法,文中給大家提到了在vue-test-utils 中 mock 全局對象的相關知識 ,需要的朋友可以參考下
    2018-11-11
  • vue3使用reactive包裹數(shù)組正確賦值問題

    vue3使用reactive包裹數(shù)組正確賦值問題

    這篇文章主要介紹了vue3使用reactive包裹數(shù)組正確賦值問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • vue項目啟動出現(xiàn)cannot GET /服務錯誤的解決方法

    vue項目啟動出現(xiàn)cannot GET /服務錯誤的解決方法

    這篇文章主要介紹了vue項目啟動出現(xiàn)cannot GET /服務錯誤的解決方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-04-04
  • vue-cli3腳手架安裝方法

    vue-cli3腳手架安裝方法

    這篇文章主要介紹了vue-cli3腳手架安裝方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-04-04
  • 在項目中封裝axios的實戰(zhàn)過程

    在項目中封裝axios的實戰(zhàn)過程

    這篇文章主要給大家介紹了關于如何在項目中封裝axios的相關資料,axios 請求的封裝,無非是為了方便代碼管理,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下
    2021-09-09
  • Vue中的change事件無效問題及解決

    Vue中的change事件無效問題及解決

    這篇文章主要介紹了Vue中的change事件無效問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • vue如何修改el-form-item中的label樣式修改問題

    vue如何修改el-form-item中的label樣式修改問題

    這篇文章主要介紹了vue如何修改el-form-item中的label樣式修改問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-10-10

最新評論