學習筆記: 狀態管理與Vuex
非父子組件(跨級組件和兄弟組件)通訊時,使用了bus
(中央事件總線)的一個方法,用來觸發和接收事件,進一步起到通訊的做用。css
一個組件能夠分爲數據(model
)和視圖(view
),數據更新時,視圖也會自動更新。在視圖中又能夠綁定一個事件,它們觸發methods
裏指定的方法,從而能夠改變數據、更新視圖,這是一個組件基本的運行模式。html
const store = new Vuex.Store({});
倉庫store
包含了應用的數據(狀態)和操做過程。Vuex裏的數據都是響應式的,任何組件使用同一store
的數據時,只要store
的數據變化,對應的組件也會當即更新。前端
數據保存在Vuex選項的state
字段內。vue
const store = new Vuex.Store({ state: { count: 0 } });
在任何組件內,能夠直接經過$store.state.count
讀取。webpack
<template> <div> <h1>首頁</h1> {{$store.state.count}} </div> </template>
直接卸載template
裏顯得有點亂,能夠用一個計算屬性來顯示:git
<div> <h1>首頁</h1> {{count}} </div> export default { computed: { count() { return $store.state.count; } } }
在組件內來自store
的數據只能讀取,不能手動修改,修改store
中數據的惟一途徑是顯式地提交mutations
。github
mutations
是Vuex的第二個選項,用來直接修改state
裏的數據。web
在組件內,經過this.$store.commit
方法來執行mutations
。vue-router
mutations
還能夠接受第二個參數,能夠是數字、字符串或對象等類型。數組
ES6語法
函數的參數能夠設定默認值,當沒有傳入該參數時,使用設置的值。
increment(state,n=1)等同於: increment(state,n){ n=n||1; }
提交mutations
的另外一種方式是直接使用包含type
屬性的對象。
mutations
裏儘可能不要異步操做數據,不然組件在commit
後數據不能當即改變,並且不知道何時會改變。
Vuex還有其餘3個選項可使用:getter
、actions
、modules
。
getter
能將computed
的方法提取出來,也能夠依賴其餘的getter
,把getter
做爲第二個參數。
action
與mutation
很像,不一樣的是action
裏面提交的是mutation
,而且能夠一步操做業務邏輯。
action
在組件內經過$store.dispatch
觸發。
modules
用來將store
分割到不一樣模塊,當項目足夠大時,store
裏的state
、getters
、mutations
、actions
會很是多,使用modules
能夠把它們寫到不一樣的文件中。
module
的mutation
和getter
接收的第一個參數state
是當前模塊的狀態。在actions
和getters
中還能夠接收一個參數rootState
,來訪問根節點的狀態。
vue-bus
中央事件總線bus
做爲一個簡單的組件傳遞事件,用於解決跨級和兄弟組件通訊的問題。
vue-bus
插件給Vue添加一個屬性$bus
,並代理$emit
、$on
、$off
三個方法。
ES6語法
emit(event,..args)
中的...
是函數參數的解構。由於不知道組件會傳遞多少個參數進來,使用...args
能夠把從當前參數到最後的參數都獲取到。
使用vue-bus
有兩點須要注意:
$bus.on
應該在created
鉤子內使用,若是在mounted
使用,它可能接收不到其餘組件來自created
鉤子內發出的事件;$bus.on
在beforeDestroy
鉤子裏應該再使用$bus.off
解除,由於組件銷燬後,就沒有必要把監聽的句柄存儲在vue-bus
中。註冊插件須要一個公開的方法install
,它的第一個參數時Vue構造器,第二個參數是一個可選的選項對象。
<p data-height="350" data-theme-id="0" data-slug-hash="RJVOXd" data-default-tab="js" data-user="whjin" data-embed-version="2" data-pen-title="Vue插件" class="codepen">See the Pen Vue插件 by whjin (@whjin) on CodePen.</p>
<script async src="https://static.codepen.io/ass...;></script>
vue-router
SPA的核心就是前端路由,對於一個網址,每次GET或POST等請求在服務端有一個專門的正則配置列表,而後匹配到具體的一條路徑後,分發到不一樣的Controller,進行各類操做,最終將html
或數據返回給前端,這樣就完成了一次IO。
前端路由,即由前端來維護一個路由規則。實現方式有兩種;
url
的hash
,就是常說的錨點(#
),JavaScript經過hashChange
事件來監聽url
的改變;history
模式,它使url
看起來像普通網站那樣,以/
分割,沒有#
,但也沒並無跳轉,不過使用這種模式須要服務端支持,服務端在接收到全部的請求後,都指向同一個html
文件,否則會出現404。所以,SPA只有一個html
,整個網站全部的內容都在這個html
裏,經過JavaScript來處理。
若是要獨立開發一個前端路由,須要考慮到頁面的可插拔、生命週期、內存管理等問題。
vue-router
vue-router
的實現原理與經過is
特性實現動態組件的方法相似,路由不一樣的頁面事實上就是動態加載不一樣的組件。
建立一個數組來指定路由匹配列表,每個路由映射一個組件:
const Routers = [ { path: '/index', component: (resolve) => require(['./views/index.vue'], resolve) }, { path: '/about', component: (resolve) => require(['./views/about.vue'], resolve) } ];
Routers裏每一項的path
屬性就是指定當前匹配的路徑,component
是映射的組件。
webpack
會把每個路由都打包爲一個js
文件,在請求道該頁面時,再去加載這個頁面的js
,也就是異步實現的懶加載(按需加載)。這樣作的好處是不須要在打開首頁的時候就把全部的頁面內容所有加載進來,只在訪問時才加載。
使用了異步路由後,變移除的每一個頁面的js
都叫作chunk
(塊),它們命名默認是0.main.js
、1.main.js
...
能夠在webpack
配置的出口output
裏經過設置chunkFilename
字段修改chunk
命名。
output: { publicPath: "/dist/", filename: "[name].js", chunkFilename: "[name].chunk.js" }
有了chunk
後,在每一個頁面(.vue
文件)裏寫的樣式也須要配置後纔會打包進main.css
,不然仍然會經過JavaScript動態建立<style>
標籤的形式寫入。
const RouterConfig = { //使用HTML5的History路由模式 mode: 'history', routes: Routers }; const router = new VueRouter(RouterConfig); new Vue({ el: "#app", router: router, render: h => { return h(App) } });
在RouterConfig裏設置mode
爲history
會開啓HTML5的History路由模式,經過/
設置路徑。若是不配置mode
,就會使用#
來設置路徑。
開啓History路由,在生產環境時必須進行配置,將全部路由都指向同一個html
,或設置404頁面,不然刷新時頁面就會出現404。
在路由列表裏,能夠在最後新加一項,當訪問的路徑不存在時,重定向到首頁:
{ path: '*', redirect: '/index' }
路由列表的path
能夠帶參數,好比/user/123
,其中用戶ID123
是動態的,但它們路由到同一個頁面,在這個頁面裏,指望獲取這個ID,然互毆請求相關數據。
vue-router
有兩種跳轉頁面的方法,第一種是使用內置的<router-link>
組件,它會被渲染爲一個<a>
標籤。
<template> <div> <h1>首頁</h1> <router-link to="/about">跳轉到about</router-link> </div> </template>
它的用法與通常的組件同樣,to
是一個prop
,指定須要跳轉的路徑,也能夠用v-bind
動態設置。
使用<router-link>
,在HTML5的History模式下會攔截點擊,避免瀏覽器從新加載頁面。
<router-view>還有其餘一些prop
,經常使用的有:
tag
能夠指定渲染成什麼標籤,好比<router-link to="/about" tag="li">
渲染的結果就是<li>
,而不是<a>
replace
使用replace
不會留下History記錄,因此導航後不能用後退鍵返回上一個頁面,如<router-link to="/about" replace>
active-class
當<router-link>
對應的路由匹配成功時,會自定給當前元素設置一個名爲router-link-active
的class
,設置prop:active-class
能夠修改默認的名稱。在作相似導航欄時,可使用該功能高亮顯示當前頁面對應的導航欄單項,可是通常不會修改active-class
,直接使用默認值router-link-active
。有時候,跳轉頁面可能須要在JavaScript中進行,相似於window.location.href
。這時可使用第二種跳轉方法,使用router
實例的方法。
<template> <div> <h1>介紹頁</h1> <button @click="handleRouter">跳轉到user</button> </div> </template> <script> export default { methods: { handleRouter() { this.$router.push('/user/123'); } } } </script>
$router
還有其餘一些方法:
replace
相似於<router-link>
的replace
功能,它不會向history
添加新紀錄,而是替換掉當前的history
記錄,如this.$router.replace('/user/123')
go
相似於window.history.go()
,在history
記錄中向前或後退多少步,參數是整數在SPA項目中,如何修改網頁的標題?
在頁面發生路由變化時,統一設置。
vue-router
提供了導航鉤子beforeEach
和afterEach
,它們會在路由即將改變前和改變後觸發,因此設置標題能夠在beforeEach
鉤子完成。
<p data-height="365" data-theme-id="0" data-slug-hash="gKRaLm" data-default-tab="js" data-user="whjin" data-embed-version="2" data-pen-title="vue-router導航鉤子" class="codepen">See the Pen vue-router導航鉤子 by whjin (@whjin) on CodePen.</p>
<script async src="https://static.codepen.io/ass...;></script>
導航鉤子有3個參數:
to
即將要進入的目標的路由對象from
當前導航即將要離開的路由對象next
調用該方法後,才能進入下一個鉤子路由列表的meta
字段能夠自定義一些信息,將每一個頁面的title
寫入meta
來統一維護,beforeEach
鉤子能夠從路由對象to
裏獲取meta
信息,從而改變標題。
某些頁面須要校驗是否登陸,若是登陸就能夠訪問,不然跳轉到登陸頁。經過localStorage
來簡單判斷是否登陸。
router.beforeEach((to, from, next) => { if (window.localStorage.getItem('token')) { next() } else { next('/login') } });
next()
的參數設置爲false
,能夠取消導航,設置爲具體的路徑能夠導航到指定的頁面。
webpack的主要適用場景時單頁面富應用(SPA)。SPA經過是由一個html
文件和一堆按需加載的js
文件組成。
export
和import
是用來導出和導入模塊的。一個模塊就是一個js
文件,它擁有獨立的做用域,裏面定義的變量外部是沒法獲取的。
在module
對象的rules
屬性中能夠指定一系列的loaders
,每個loader
都必須包含test
和use
兩個選項。
當webpack
編譯過程當中遇到require()
或import
語句導入一個後綴名爲.css
的文件時,先將它經過css-loader
轉換,再經過style-loader
轉換,而後繼續打包。use
選項的值能夠是數組或字符串,若是是數組,它的編譯順序就是從後往前。
webpack的主要核心部分包括 入口(Entry)、 出口(Output)、 加載器(Loaders)、 插件(Plugin)。
vue-loader
<style>
標籤使用scoped
屬性,表示當前的CSS只在這個組件有效,若是不加,namediv
的樣式會應用到整個項目。
使用.vue
文件須要先安裝vue-loader
、vue-style-loader
等加載器並作配置。若是要使用ES6語法,還須要安裝babel
和babel-loader
等加載器。
<p data-height="465" data-theme-id="0" data-slug-hash="NzjNgp" data-default-tab="js" data-user="whjin" data-embed-version="2" data-pen-title="Vue-webpack.config.js" class="codepen">See the Pen Vue-webpack.config.js by whjin (@whjin) on CodePen.</p>
<script async src="https://static.codepen.io/ass...;></script>
新建.babelrc
文件,並寫入babel
的配置,webpack會依賴此配置文件來使用babel
編譯ES6代碼。
{ "presets": ["es2015"], "plugins": ["transform-runtime"], "comments": false }
每一個.vue
文件表明一個組件,組件之間能夠相互依賴。
ES語法:
=>
是箭頭函數
render: h=>h(App)等同於 render: function(h) { return h(App) } 也等同於: render: h=>{ return h(App) }
箭頭函數裏的this
指向與普通函數不同,箭頭函數體內的this
對象就是定義時所在的對象,而不是使用時所在的對象。