Vue規模化——vue-router、vuex

一、路由vue-router

後端路由:對於普通的網站,所有的超鏈接都是URL地址,URL地址對應服務器上的資源;
前端路由:對於單頁面應用程序,主要通過URL中的hash(#)來實現頁面跳轉,HTTP請求中不會包含hash相關的內容。

插件下載:https://github.com/vuejs/vue-routerhttps://unpkg.com/vue-router/dist/vue-router.js

在Vue後面加載vue-router,它會自動安裝。

<script src="lib/vue.js"></script>
<script src="lib/vue-router.js"></script>

1、路由的基本使用

<div id="app">
  <!-- 點擊a鏈接,修改url地址,Vue實例上的router監聽到url地址的改變,展示對應組件 -->
  <!-- <a href="#/foo">Go To Foo</a> -->
  <!-- <a href="#/bar">Go To Bar</a> -->
  
  <!-- <router-link>默認會被渲染成一個<a>標籤,通過傳入to屬性指定鏈接地址 -->
  <router-link to="/foo">Go To Foo</router-link>
  <router-link to="/bar">Go To Bar</router-link>
  
  <!-- 路由出口,路由匹配到的組件將渲染在這裏 -->
  <router-view></router-view>
</div>

<script>
  // 1.定義(路由)組件
  const Foo={template:'<div>foo</div>'};
  const Bar={template:'<div>bar</div>'};

  // 2.定義路由
  // path:監聽的路由鏈接地址。component:要展示的組件,是一個模板對象,不能是組件名
  const routes=[
    {path:'/foo',component:Foo},
    {path:'/bar',component:Bar}
  ];

  // 3.創建router實例,配置路由
  const router=new VueRouter({
    routes // 相當於routes:routes
  });

  // 4.創建Vue實例,註冊路由
  const vm=new Vue({
    el:'#app',
    router // 註冊路由,監聽url地址的變化,展示對應組件
  });
</script>

2、重定向和別名

重定向:當用戶訪問/a時,url將會被替換成/b,然後匹配路由爲/b,如用於使根路徑重定向爲顯示某個組件。重定向通過routes配置來完成。

const routes=[
  {path:'/',redirect:'/foo'}, // 重定向
  {path:'/foo',component:Foo}
];

別名:/a的別名是/b意味着,當用戶訪問/b時,url保持爲/b,但路由匹配爲/a,和訪問/a一樣。 

const routes=[
  {path:'/a',component:A,alias:'/b'}
];

3、<router-link>

tag:使用tag屬性指定router-link渲染的標籤類型,默認值'a'。還是會監聽點擊,觸發導航。

linkActiveClass:這是路由構造函數中的選項,設置鏈接激活時使用的CSS類名,默認值"router-link-active"。通過該類名可設置路由高亮的樣式。

4、編程式導航

除了使用<router-link>創建a標籤來定義導航鏈接,還可以藉助router的實例方法,通過編寫代碼來實現。

想要導航到不同的URL,使用router.push方法(在Vue實例內部使用this.$router.push),點擊<router-link>時,該方法會在內部調用。

router.push('home') // 字符串

router.push({path:'home'}) // 對象

router.push({name:'user',params:{userId:123}}) // 命名的路由

router.push({path:'register',query:{plan:'private'}}) // 帶查詢參數,變成 /register?plan=private

router.push方法會向history棧添加一個新的記錄,當用戶點擊瀏覽器後退按鈕時,則回到之前的URL。 

router.go(n)方法的參數是一個整數,表示在history記錄中向前或者後退多少步,類似window.history.go(n)。

5、路由組件傳參

(1)? & $route.query

使用查詢字符串給路由傳遞參數,不需要修改路由規則的path屬性。

<router-link to="/foo?id=10&name=cong">Go To Foo</router-link>
const foo={
  template:'<div>Foo--{{$route.query.id}}--{{$route.query.name}}</div>',
  created(){
    console.log(this.$route.query.id);
  }
}

(2)/ : $route.params

<router-link to="/foo/10/cong">Go To Foo</router-link>
const foo={
  template:'<div>Foo--{{$route.params.id}}--{{$route.params.name}}</div>',
  created(){
    console.log(this.$route.params.id);
  }
}
const routes=[
  {path:'/foo/:id/:name',component:foo}
];

 (3)props

6、嵌套路由

<div id="app">
  <router-link to="/user">User</router-link>
  <router-view></router-view>
</div>

<template id="user">
  <div>
    <h3>最高級路由</h3>
    <router-link to="/user/profile">Profile</router-link> <!-- 嵌套<router-link> -->
    <router-view></router-view>                           <!-- 嵌套<router-view> -->
  </div>
</template>
<script>
  const User={
    template:'#user'
  };

  const Profile={ // 嵌套路由的組件
    template:'<div>被嵌套的路由</div>'
  };

  const router=new VueRouter({
    routes:[
      {
        path:'/user',
        component:User,
        children:[ // 用children定義嵌套路由
          {path:'profile',component:Profile} // 沒有/,以/開頭的嵌套路徑會被當作根路徑
        ]
      }
    ]
  });

  const vm=new Vue({
    el:'#app',
    router
  });
</script>

7、命名視圖

有時想同級展示多個視圖,而不是嵌套展示。可以在界面中擁有多個單獨命名的視圖,而不是隻有一個單獨的出口。如果router-view沒有設置名字,默認爲default。

一個視圖使用一個組件渲染,因此對於同個路由,多個視圖就需要多個組件。使用components配置(帶上s)。

<div id="app">
  <router-view></router-view>
  <router-view name="left"></router-view>
  <router-view name="main"></router-view>
</div>
<script>
  const router=new VueRouter({
    routes:[
      {path:'/',components:{
        default:header,
        left:leftBox,
        main:mainBox
        }
      }
    ]
  });
</script>

二、狀態管理vuex

中文官網:https://vuex.vuejs.org/zh/   GitHub:https://github.com/vuejs/vuex

1、狀態管理模式

Vuex是一個專爲Vue.js應用程序開發的狀態管理模式(公共數據管理工具)。它採用集中式存儲管理應用的所有組件的狀態(共享的數據),並以相應的規則保證狀態以一種可預測的方式發生變化(整個程序中的任何組件直接獲取或修改公共數據)。

// 組件
new Vue({
  // state
  data(){
    return {
      count:0
    }
  },
  // view
  template:`<div>{{count}}</div>`,
  // actions
  methods:{
    increment(){
      this.count++
    }
  }
})

狀態自管理應用(組件)包含:state,驅動應用的數據源;view,以聲明方式將state映射到視圖;actions,響應在view上的用戶輸入導致的狀態變化。但是,當應用遇到多個組件共享狀態時,單向數據流的簡潔性很容易被破壞,如多個視圖依賴於同一狀態(傳參繁瑣)、來自不同視圖的行爲需要變更同一狀態。

把組件的共享狀態抽取出來,以一個全局單例模式管理,任何組件都能獲取狀態或者觸發行爲。

雖然Vuex可以幫助管理共享狀態,但也附帶了更多的概念和框架。如果不打算開發大型單頁應用,使用Vuex可能是繁瑣冗餘的,一個簡單的store模式就足夠了。但如果需要構建一箇中大型單頁應用,更好地在組件外部管理狀態則需要Vuex 。

2、安裝與創建store

在Vue之後引入vuex會進行自動安裝。

Vuex依賴Promise,如果瀏覽器並沒有實現Promise(如IE),可以使用一個polyfill的庫(es6-promise),可以通過CDN將其引入,之後window.Promise會自動可用。

<script src="/path/to/vue.js"></script>
<script src="/path/to/vuex.js"></script>

<script src="https://cdn.jsdelivr.net/npm/es6-promise@4/dist/es6-promise.auto.js"></script>

每一個Vuex應用的核心是store(倉庫),基本上是一個容器,包含着應用中大部分的狀態 (state)。Vuex使用單一狀態樹,用一個對象就包含了全部的應用層級狀態,作爲一個“唯一數據源 (SSOT)”而存在。每個應用僅包含一個store實例。

Vuex和單純的全局對象不同,vuex的狀態存儲是響應式的,若store中的狀態發生變化,相應的組件也會得到高效更新;改變store中的狀態的唯一途徑是顯式地提交(commit)mutation,爲了更明確地追蹤到狀態的變化。

創建一個store,僅提供一個初始state對象和一些mutation、getters。

在根實例中註冊store選項,可將狀態從根組件注入到每一個子組件中(需調用Vue.use(Vuex)),子組件通過this.$store訪問。

const store=new Vuex.Store({
  state:{
    count:0
  },
  mutations:{
    increment(state){
      state.count++
    }
  },
  getters:{
    optCount:state=>{
      return 'count值是:'+state.count
    }
  }
})

const vm=new Vue({
  el:"#app",
  store // 將store掛載到vm實例,任何組件都可以使用store存儲訪問數據
})

console.log(store.state.count);
store.commit('increment')
console.log(store.getters.optCount);

3、核心概念

(1)state

store.state獲取狀態對象。由於store中的狀態是響應式的,在組件中調用store中的狀態僅需要在計算屬性中返回即可,當然也可以用在函數中,等。

mapState輔助函數:用於一個組件獲取多個狀態,可省略store。單獨構建的版本中輔助函數爲Vuex.mapState。

import {mapState} from 'vuex'

export default{
  computed:mapState({
    count:state=>state.count,
    // 簡寫爲count:'count'
    // 簡寫爲'count' 計算屬性名稱與state的子節點名稱相同時,給mapState傳一個字符串即可
    // 傳字符串參數 'count' 等同於 `state => state.count`

    // 爲了使用this獲取局部狀態,必須使用常規函數,不能簡寫
    countPlusLocalState(state){
      return state.count+this.localCount
    }
  })
}

對象展開運算符:mapState函數返回的是一個對象,如果需要與局部計算屬性混合使用,可使用對象展開運算符。

computed:{
  localComputed(){},
  ...mapState({ // 使用對象展開運算符將此對象混入到外部對象中
    // ...
  })
}

(2)mutation

mutation非常類似於事件,每個mutation都有一個字符串的事件類型和一個回調函數。回調函數進行狀態更改,接受state作爲第一個參數。第二個參數可選,是mutation的載荷,應該是一個對象,可以包含多個字段且更易讀。

store.commit('事件類型')方法觸發狀態變更。

store.commit('increment',{ // 方式1
  amount:10
})
store.commit({ // 方式2
  type:'increment',
  amount:10
})

(3)getter

在store中定義getter,可以認爲是store的計算屬性,getter的返回值會根據它的依賴被緩存起來,且只有當它的依賴值發生了改變纔會被重新計算。

Getter接受state作爲其第一個參數,可以接受其它getter作爲第二個參數。

通過store.getters對象,可以以屬性的形式訪問這些值,作爲Vue的響應式系統的一部分緩存其中。在對store裏的數組進行查詢時,也可以通過讓getter返回一個函數實現給getter傳參,通過方法訪問時,每次都會去進行調用,而不會緩存結果。

getters:{
  // ...
  getTodoById:(state)=>(id)=>{
    return state.todos.find(todo=>todo.id===id)
  }
}
store.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }

(4)action

(5)module 

三、服務端渲染

待更新。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章