承接這上一篇Vue + Webpack 構建模塊化開發框架詳解,咱們知道了如何使用webpack對vue進行打包,從而開始咱們的前端模塊化開發之路,這一篇在上一篇的基礎上講解 Vue全家桶(vue+vuex+vue-router+axios)
+ webpack
構建一個單頁應用Demojavascript
閱讀本篇內容以前,除了須要掌握上一篇內容中的前提部分的知識,還須要瞭解如下內容👇php
vue全家桶簡單介紹
vuex
: vuex是一種集中式狀態管理模式,什麼意思呢?咱們在模塊化開發過程當中,咱們以組件來做爲模塊單位,模塊之間存在於不一樣的命名空間,做用域互不干預,這樣保證了咱們模塊之間變量函數名稱等不會衝突,可是有時候咱們咱們須要組件之間共享一些數據或者狀態,咱們一般的作法是傳參,可是傳參的作法至少有兩個弊端,一是麻煩(尤爲是當須要傳遞的參數不少時),二是很差管理且冗餘(給多個組件傳參就須要多份參數列表,並且容易出錯)。vuex提供的集中式管理就解決了這個問題,經過把要共享的數據或狀態集中起來管理,別的組件須要時就去訪問變動,大大提升了可維護性和開發效率
vue-router
: vue-router是一個前端路由管理器,這個和後端常據說的路由有些不一樣(我的以爲),這裏的路由管理器更像是一個組件註冊器,vue-router爲分散的組件註冊一個路由或者叫地址也何嘗不可,以方便咱們控制組件的層級嵌套關係以及隱藏仍是顯示,這樣咱們能夠很方便高效的構建單頁應用html
axios
: axios 和 jquery.ajax/vue-resource同樣 , 都是HTTP異步請求的工具,axios和vue-resource的API很像,可是我的以爲,axios的API更豐富一些前端
這裏的目錄設置,並非一成不變的金科玉律,也不必定是最好的,讀者能夠根據本身的想法設定文件結構,瞭解如何配置單入口單出口的webpack.config.js,能夠看個人上一篇文章(開頭提到了),或者移步webpack官方網站。本篇內容,再也不講解過多webpack配置,和上一篇是基本相同的,下面主要講解 Vue全家桶相關內容vue
import Vue from 'vue'; import Router from './routers/index-router'; import Store from './stores/index-store'; import App from './components/App.vue'; var app = new Vue({ //建立一個Vue實例 router : Router, //加入路由配置 store : Store, //加入狀態管理 components : {App} //加入App組件 }).$mount('#app'); //掛載節點
須要注意的是,路由和狀態都須要加入一個vue實例中去纔有意義。這裏有一點頗有意思,就是在路由router中註冊的組件(success.vue)依然能夠訪問到狀態store實例,而官方教程上並無特別強調這一點,在下面咱們能夠看到這個有趣的事情java
import Vuex from 'vuex'; import Vue from 'vue'; import axios from 'axios'; Vue.use(Vuex); //在vue中加入Vuex插件 const Store = new Vuex.Store({ //實例化一個Store state : { //這裏是咱們須要集中管理的登錄狀態 account : "ads", password : "123456", islogin : null }, mutations : { // 這是惟一能夠變動state的途徑,須要經過一個提交 updateAccount(state,payload){ //具備載荷的mutation state.account = payload.account }, updatePassword(state,payload){ state.password = payload.password }, islogin(state,payload){ if(payload == 1){ state.islogin = true }else if(payload == 0){ state.islogin = false } } }, actions : { //這是能夠支持異步執行提交的actions login (context,payload){ //這裏是去訪問咱們的反向代理服務器上的一個php文件 axios.get('/index.php',{ params : { account : payload.account, password : payload.password } }).then(function(response){ if(response.data.code == 'success'){ //變動store狀態 context.commit('islogin',1) //這裏作了在異步邏輯中的狀態提交 }else{ context.commit('islogin',0) } }).catch(function(error){ console.log(error) alert('fail') }) } } }) export default Store
咱們這裏的Store有三個屬性,state
是咱們須要集中管理的狀態或者數據, mutations
是維護變動咱們狀態的一個方式, actions
是爲了在異步邏輯中提交狀態的一箇中轉站,須要注意的是:jquery
在實例化Store以前,必須先 Vue.use(Vuex) ,先在vue中加入Vuex插件
這裏須要說一下的是,如何開啓dev-server的proxy,讓nginx來代理axios的請求,也就是跨域訪問了(由於dev-server跑的是8080端口,nginx跑的是80端口,不設置代理的話瀏覽器將拒絕跨域訪問),感受很深奧,其實很簡單,咱們須要修改一下webpack.config.js中devServer的配置 : webpack
webpack.config.jsios
devServer : { contentBase : './dist', watchContentBase : true, compress : true, port : 8080, hot : true, inline : true, //開啓頁面自動刷新 open : true, proxy : { '/index.php' : { target : 'http://localhost:80/phpinfo.php', secure : false } } }
而後,咱們的axios在配置url時使用 /index.php
,就能夠至關於訪問http://localhost:80/phpinfo.php
nginx
import VueRouter from 'vue-router'; import Vue from 'vue'; import success from '../components/success.vue'; // 組件註冊路由,這裏success組件註冊路由是'/app' var routes = [ { path : '/app',component : success } ] Vue.use(VueRouter); //在vue中加入VueRouter插件 var Router = new VueRouter({ //實例化一個router routes //這裏的寫法至關於 routes:routes }) export default Router;
這裏的路由只註冊了一個組件,vue-router的能力遠不止如此,還能夠嵌套定義組件的層級關係,更多到官方文檔瞭解 ,路由器和狀態管理器同樣都是vue官方核心插件,使用前都須要先 Vue.use(VueRouter)
,咱們其實能夠看到,這裏把路由和狀態分別從vue實例中抽離出來,單獨管理,經過暴露實例Store
Router
,加入到vue實例中去,這樣能夠方便debug和後期維護
App.vue
<template> <div> <input type="text" v-model="account"> <input type="password" v-model="password"> <button type="button" @click="login">show</button> </div> </template> <script> export default { data : function(){ return { account : "", password : "" } }, created : function(){ this.account = this.$store.state.account this.password = this.$store.state.password }, watch : { //偵聽屬性 account : function(){ //當accout改變就當即提交狀態 this.$store.commit('updateAccount',{ account : this.account }) }, // 當password改變就當即提交狀態 password : function(){ this.$store.commit('updatePassword',{ password : this.password }) } }, methods : { login : function(){ //經過分發到action,來異步請求登陸服務,並變動狀態 this.$store.dispatch('login',{ account : this.account, password : this.password }) this.$router.push('/app');//同時顯示登錄狀態 } } } </script> <style scoped> input { height: 40px; width: 300px; border: 1px solid blue; box-shadow: none; } </style>
success.vue
<template> <div> <p>{{islogin}}</p> </div> </template> <script> export default { computed : { //計算屬性 //動態響應狀態的變動 islogin : function(){ var islogin = this.$store.state.islogin if(islogin == null){ return 'No option' }else if(islogin == true){ return 'Login Success' }else if(islogin == false){ return 'Login Fail' } } } } </script> <style scoped> p { height: 40px; text-align: center; } </style>
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>index</title> </head> <body> <div id="app"> <!-- App組件渲染出口 --> <App></App> <!-- 註冊路由的組件渲染出口 --> <router-view></router-view> </div> </body> </html>
好了,到此爲止,代碼基本完成,咱們來理一理,vue+vuex+vue-router以及組件之間是如何配合工做的?
用戶在App.vue
組件中輸入,v-model
雙向綁定了App
組件中的data
,App組件中的偵聽屬性發現data改動,當即向vuex
的Store
實例提交了狀態變動,當用戶點擊show
,App組件中methods.login
事件被觸發,它向Store實例發起一個分發,並導航到/app
,Store
的action
收到分發調用axios
去異步請求位於localhost:80
下的php
後臺服務,獲得的登錄狀態當即提交,與此同時,Router
去渲染/app
路由對應的組件到模板中去,因而咱們就能夠看到一個動態響應式的狀態提示了