Vue全家桶 + webpack 構建單頁應用初體驗

文章指南

主題

  承接這上一篇Vue + Webpack 構建模塊化開發框架詳解,咱們知道了如何使用webpack對vue進行打包,從而開始咱們的前端模塊化開發之路,這一篇在上一篇的基礎上講解 Vue全家桶(vue+vuex+vue-router+axios) + webpack 構建一個單頁應用Demojavascript

前提

  閱讀本篇內容以前,除了須要掌握上一篇內容中的前提部分的知識,還須要瞭解如下內容👇php

  • Vue全家桶系列,掌握vuex,vue-router以及axios ,不瞭解請移步官方教程axios-npmvuexvue-router
vue全家桶簡單介紹
vuex : vuex是一種集中式狀態管理模式,什麼意思呢?咱們在模塊化開發過程當中,咱們以組件來做爲模塊單位,模塊之間存在於不一樣的命名空間,做用域互不干預,這樣保證了咱們模塊之間變量函數名稱等不會衝突,可是有時候咱們咱們須要組件之間共享一些數據或者狀態,咱們一般的作法是傳參,可是傳參的作法至少有兩個弊端,一是麻煩(尤爲是當須要傳遞的參數不少時),二是很差管理且冗餘(給多個組件傳參就須要多份參數列表,並且容易出錯)。vuex提供的集中式管理就解決了這個問題,經過把要共享的數據或狀態集中起來管理,別的組件須要時就去訪問變動,大大提升了可維護性和開發效率

vue-router : vue-router是一個前端路由管理器,這個和後端常據說的路由有些不一樣(我的以爲),這裏的路由管理器更像是一個組件註冊器,vue-router爲分散的組件註冊一個路由或者叫地址也何嘗不可,以方便咱們控制組件的層級嵌套關係以及隱藏仍是顯示,這樣咱們能夠很方便高效的構建單頁應用html

axios : axios 和 jquery.ajax/vue-resource同樣 , 都是HTTP異步請求的工具,axios和vue-resource的API很像,可是我的以爲,axios的API更豐富一些前端

正文



 本文的小Demo大概功能就是一個登錄的功能,咱們這裏app.vue封裝了一個登錄組件,success.vue封裝了一個提示面板,經過vuex來集中管理登錄狀態,用vue-router來路由提示面板,用axios來異步提交到一個跨域的服務器(這裏後臺服務是nginx+php提供,因此在dev-server中要設置一個反向代理,也就是nginx來代理咱們的dev-server的請求從而解決axios跨域問題)

先來看看咱們的項目結構 [自定義的]

clipboard.png

這裏的目錄設置,並非一成不變的金科玉律,也不必定是最好的,讀者能夠根據本身的想法設定文件結構,瞭解如何配置單入口單出口的webpack.config.js,能夠看個人上一篇文章(開頭提到了),或者移步webpack官方網站。本篇內容,再也不講解過多webpack配置,和上一篇是基本相同的,下面主要講解 Vue全家桶相關內容vue

index.js

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

stores/index-store.js

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.phpnginx

routers/index-router.js

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和後期維護

components/App.vue 和 components/success.vue

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>

templates/index.html

<!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改動,當即向vuexStore實例提交了狀態變動,當用戶點擊show,App組件中methods.login事件被觸發,它向Store實例發起一個分發,並導航到/appStoreaction收到分發調用axios去異步請求位於localhost:80下的php後臺服務,獲得的登錄狀態當即提交,與此同時,Router去渲染/app路由對應的組件到模板中去,因而咱們就能夠看到一個動態響應式的狀態提示了

相關文章
相關標籤/搜索