<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                [TOC] # vue-router ## \<router-link> 與 \<router-view> ```html <script src="https://unpkg.com/vue/dist/vue.js"></script> <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script> <div id="app"> <h1>Hello App!</h1> <p> <!-- 使用 router-link 組件來導航. --> <!-- 通過傳入 `to` 屬性指定鏈接. --> <!-- <router-link> 默認會被渲染成一個 `<a>` 標簽 --> <router-link to="/foo">Go to Foo</router-link> <router-link to="/bar">Go to Bar</router-link> </p> <!-- 路由出口 --> <!-- 路由匹配到的組件將渲染在這里 --> <router-view></router-view> </div> ``` ## 定義路由及路由匹配 項目中一般會單獨將路由抽離為一個 store.js 文件,如下: ```js import Vue from 'vue' import Router from 'vue-router' Vue.use(Router) export default new Router({ routes: [ { path: '/', redirect: '/store' }, { path: '/ebook', component: () => import('./views/ebook/index.vue'), // 路由懶加載,這里用的是ES6的語法 import()函數是動態加載 import 是靜態加載 children: [ { path: ':fileName', // 動態路由, 可以傳遞路徑參數 component: () => import('./components/ebook/EbookReader.vue') } ] }, { path: '/store', component: () => import('./views/store/index.vue'), redirect: '/store/shelf', // #/store -> #/store/home children: [ { path: 'home', // children 使用相對路徑 可以通過 store/home 來找到 component: () => import('./views/store/StoreHome.vue') }, { path: 'list', component: () => import('./views/store/StoreList.vue') }, { path: 'detail', // /store/detail 加斜杠則只能匹配/detail component: () => import('./views/store/StoreDetail.vue') }, ] } ] }) ``` 然后還需要再 main.js 中引入: ```js import router from './router' new Vue({ router, store, ... render: h => h(App) }).$mount('#app') ``` 上面有涉及 <span style="font-family:楷體;font-weight:700;">動態路徑參數</span> 的概念:你可以在一個路由中設置多段“路徑參數”,對應的值都會設置到`$route.params`中。例如 | 模式 | 匹配路徑 | $route.params | | --- | --- | --- | | /user/:username | /user/evan | `{ username: 'evan' }` | | /user/:username/post/:post\_id | /user/evan/post/123 | `{ username: 'evan', post_id: '123' }` | 同時也涉及到了 <span style="font-family:楷體;font-weight:700;">嵌套路由</span> : ```js const router = new VueRouter({ routes: [ { path: '/user/:id', component: User, children: [ { // 當 /user/:id/profile 匹配成功, // UserProfile 會被渲染在 User 的 <router-view> 中 path: 'profile', component: UserProfile }, { // 當 /user/:id/posts 匹配成功 // UserPosts 會被渲染在 User 的 <router-view> 中 path: 'posts', component: UserPosts } ] } ] }) ``` >[danger] 注意:以 / 開頭的嵌套路徑會被當作根路徑 ## 組件訪問路由對象 可以在任何組件內通過`this.$router`訪問路由器,也可以通過`this.$route`訪問當前路由。 `$route`是 <span style="font-family:楷體;font-weight:700;">路由信息對象</span>,包括 path,params,hash,query,fullPath,matched,name 等路由信息參數。而 `$router` 是 <span style="font-family:楷體;font-weight:700;">路由實例對象</span>,包括了路由的跳轉方法,鉤子函數等。 ## 路由跳轉及獲取參數 | 聲明式 | 編程式 | | --- | --- | | `<router-link :to="...">` | `router.push(...)` | ```js // 字符串 router.push('home') // 一般是在組件內部使用,即 this.$router.push() // 對象 router.push({ path: 'home' }) // 命名的路由 router.push({ name: 'user', params: { userId: '123' }}) // 帶查詢參數,變成 /register?plan=private router.push({ path: 'register', query: { plan: 'private' }}) ``` ```js // 在瀏覽器記錄中前進一步,等同于 history.forward() router.go(1) // 一般是在組件內部使用,即 this.$router.go() // 后退一步記錄,等同于 history.back() router.go(-1) // 前進 3 步記錄 router.go(3) ``` 前面有提到過:`route`是路由信息對象,包括 path,params,hash,query,fullPath,matched,name 等路由信息參數,那么顯然我們獲取當前路由的一些信息就需要通過`route`對象,下面主要看看`params、query`這兩個參數。 ```js // query 傳參,使用 name 跳轉 (name 是你為路由取的別名) this.$router.push({ name: 'detailPage', query: { queryId: '12345', queryName: 'query' } }) // query 傳參,使用 path 跳轉 this.$router.push({ path: '/detail', query: { queryId: '12345', queryName: 'query' } }) // 跳轉到的路由組件接收參數 const id = this.$route.query.queryId const name = this.$route.query.queryName ``` 用 query 傳參你的 URL 會類似這樣`localhost:8080/#/detail?queryId=12345&queryName=query` 而 params 實際上是與動態路徑參數相對應的,這個概念我們在上面也提到過 | 模式 | 匹配路徑 | $route.params | | --- | --- | --- | | /user/:username | /user/evan | `{ username: 'evan' }` | | /user/:username/post/:post\_id | /user/evan/post/123 | `{ username: 'evan', post_id: '123' }` | 來看看官方給出的例子:如果提供了`path`,`params`會被忽略,你需要提供路由的`name`或手寫完整的帶有參數的`path`: ```js const userId = '123' router.push({ name: 'user', params: { userId }}) // -> /user/123 router.push({ path: `/user/${userId}` }) // -> /user/123 // 這里的 params 不生效 router.push({ path: '/user', params: { userId }}) // -> /user ``` 看到這就很明顯了,如果你定義路由時沒有采用動態路徑參數的形式,那么一般都是采用 query 來傳遞信息,否則,可以使用 params 來傳遞信息。 ## hash 模式與 history 模式 <span style="font-size:20px; color: #42b983;">hash 模式</span> 在瀏覽器中符號 “#”,# 以及 # 后面的字符稱之為 hash,用 window.location.hash 讀取; 特點:hash 雖然在 URL 中,但不被包括在 HTTP 請求中;用來指導瀏覽器動作,對服務端安全無用,hash 不會重加載頁面。 hash 模式下,僅 hash 符號之前的內容會被包含在請求中,如 `http://www.xxx.com`,因此對于后端來說,即使沒有做到對路由的全覆蓋,也不會返回 404 錯誤。 ***** <span style="font-size:20px; color: #42b983;">history 模式</span> history 采用 HTML5 的新特性;且提供了兩個新方法:pushState(),replaceState()可以對瀏覽器歷史記錄棧進行修改,以及 popState 事件的監聽到狀態變更。 history 模式下,前端的 URL 必須和實際向后端發起請求的 URL 一致,如 `http://www.xxx.com/items/id`。后端如果缺少對 `/items/id` 的路由處理,將返回 404 錯誤。 使用該模式一般需要在服務端增加一個覆蓋所有情況的候選資源:如果 URL 匹配不到任何靜態資源,則應該返回同一個 index.html 頁面,這個頁面就是你 app 依賴的頁面。 hash 模式和 history 模式并沒有改變路由跳轉的語法,只是 history 模式的路由需要后臺的支持,關鍵是 URL:hash 模式僅 hash 符號('#’)之前的內容會被包含在請求中。 ***** `vue-router`默認 hash 模式 —— 使用 URL 的 hash 來模擬一個完整的 URL,于是當 URL 改變時,頁面不會重新加載。 如果想使用 history 模式,可以在 cli 構建時更換模式即可,或者: ```js const router = new VueRouter({ mode: 'history', routes: [...] }) ``` ## 導航守衛 還沒用過....[https://router.vuejs.org/zh/guide/advanced/navigation-guards.html#%E7%BB%84%E4%BB%B6%E5%86%85%E7%9A%84%E5%AE%88%E5%8D%AB](https://router.vuejs.org/zh/guide/advanced/navigation-guards.html#%E7%BB%84%E4%BB%B6%E5%86%85%E7%9A%84%E5%AE%88%E5%8D%AB) # vuex ## 基礎概念 每一個 Vuex 應用的核心就是 **store(倉庫)**。store 基本上就是一個容器,它包含著你的應用中大部分的 **狀態 (state)**。 Vuex 和單純的全局對象有以下兩點不同: - Vuex 的狀態存儲是響應式的。當 Vue 組件從 store 中讀取狀態的時候,若 store 中的狀態發生變化,那么相應的組件也會相應地得到更新。 - 你不能直接改變 store 中的狀態。改變 store 中的狀態的唯一途徑就是顯式地提交 (commit) ![](https://box.kancloud.cn/5145ed5562bb79d0e9b02155a5c1f2ac_787x569.png) 這個狀態自管理應用包含以下幾個部分: * **state**,驅動應用的數據源; * **view**,以聲明方式將 **state** 映射到視圖; * **actions**,響應在 **view** 上的用戶輸入導致的狀態變化。 一般將 store 放在一個單獨的 store.js 文件或 store 文件夾下,創建一個最簡單的 store: ```js // store.js import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({ state: { privilege: 0 }, /* 每個 mutation 都有一個字符串的事件類型 (type) 和 一個回調函數 (handler); 這個回調函數就是我們實際進行狀態更改的地方,并且它會接受 state 作為第一個參數 */ mutations: { 'SET_PRIVILEGE': (state, newPrivilege) => { state.privilege = newPrivilege } }, /* Action 提交的是 mutation,而不是直接變更狀態。 Action 可以包含任意異步操作。 Action 函數接受一個與 store 實例具有相同方法和屬性的 context 對象,因此你可以調用 context.commit 提交一個 mutation, 或者通過 context.state 和 context.getters 來獲取 state 和 getters。 當我們在之后介紹到 Modules 時,你就知道 context 對象為什么不是 store 實例本身了。 */ actions: { setPrivilege({ commit }, newPrivilege) { return commit('SET_PRIVILEGE', newPrivilege) } } }) ``` 然后我們還需要在 main.js 中引入: ```js import store from './store' new Vue({ router, store, render: h => h(App) }).$mount('#app') ``` > 為什么 vuex 不像 redux 需要引入中間件而可以直接處理異步操作呢? ## 組件中獲取 vuex 的 state 跟 redux 一樣,vuex 使用單一狀態樹,即每個應用僅應該包含一個 store 實例。 方法 1:子組件在 **計算屬性** 中返回某個狀態(基于 Vuex 的狀態存儲是響應式的) 如下面的代碼,每當`store.state.count`變化的時候, 都會重新求取計算屬性,并且觸發更新相關聯的 DOM。 ```js // 創建一個 Counter 組件 const Counter = { template: `<div>{{ count }}</div>`, computed: { count () { return store.state.count } } } ``` 方法 2:通過 store 選項將狀態從根組件"注入"到每個子組件(使用 vue-cli3 構建項目時自動使用該方式) 通過在根實例中注冊 store 選項,該 store 實例會注入到根組件下的所有子組件中,且子組件能通過 `this.$store `訪問到 ```js const app = new Vue({ el: '#app', // 把 store 對象提供給 "store" 選項,這可以把 store 的實例注入所有的子組件 store, components: { Counter }, template: ` <div class="app"> <counter></counter> </div> ` }) ``` ```js const Counter = { template: `<div>{{ count }}</div>`, computed: { count () { return this.$store.state.count } } } ``` 方法 3:使用 mapState 輔助函數(感覺可以被 mapGetter 替代?) 方法 4:使用 mapGetter(并不是單純的映射關系,可以做一些處理) Vuex 允許我們在 store 中定義“getter”(可以認為是 store 的計算屬性)。就像計算屬性一樣,getter 的返回值會根據它的依賴被緩存起來,且只有當它的依賴值發生了改變才會被重新計算。 Getter 接受 state 作為其第一個參數: ```js const store = new Vuex.Store({ state: { todos: [ { id: 1, text: '...', done: true }, { id: 2, text: '...', done: false } ] }, getters: { doneTodos: state => { return state.todos.filter(todo => todo.done) } } }) ``` `mapGetters`輔助函數僅僅是將 store 中的 getter 映射到局部計算屬性: ```js import { mapGetters } from 'vuex' export default { // ... computed: { // 使用對象展開運算符將 getter 混入 computed 對象中 ...mapGetters([ 'doneTodosCount', 'anotherGetter', // ... ]) } } ``` 如果你想將一個 getter 屬性另取一個名字,使用對象形式: ```js mapGetters({ // 把 `this.doneCount` 映射為 `this.$store.getters.doneTodosCount` doneCount: 'doneTodosCount' }) ``` ## Mutation 與 Action ### 在組件中分發 action 在組件中使用`this.$store.dispatch('xxx')`分發 action,或者使用`mapActions`輔助函數將組件的 methods 映射為`store.dispatch`調用(需要先在根節點注入`store`): ```js import { mapActions } from 'vuex' export default { // ... methods: { ...mapActions([ 'increment', // 將 `this.increment()` 映射為 `this.$store.dispatch('increment')` // `mapActions` 也支持載荷: 'incrementBy' // 將 `this.incrementBy(amount)` 映射為 `this.$store.dispatch('incrementBy', amount)` ]), ...mapActions({ add: 'increment' // 將 `this.add()` 映射為 `this.$store.dispatch('increment')` }) } } ``` ### 組合 action `store.dispatch`可以處理被觸發的 action 的處理函數返回的 Promise,并且`store.dispatch`仍舊返回 Promise ```js actions: { // ... actionB ({ dispatch, commit }) { return dispatch('actionA').then(() => { commit('someOtherMutation') }) } } ``` 使用 async / await: ```js // 假設 getData() 和 getOtherData() 返回的是 Promise actions: { async actionA ({ commit }) { commit('gotData', await getData()) }, async actionB ({ dispatch, commit }) { await dispatch('actionA') // 等待 actionA 完成 commit('gotOtherData', await getOtherData()) } } ``` ## 劃分 Module Vuex 允許我們將 store 分割成**模塊(module)**。每個模塊擁有自己的 state、mutation、action、getter、甚至是嵌套子模塊——從上至下進行同樣方式的分割 ```js const moduleA = { state: { ... }, mutations: { ... }, actions: { ... }, getters: { ... } } const moduleB = { state: { ... }, mutations: { ... }, actions: { ... } } const store = new Vuex.Store({ modules: { a: moduleA, b: moduleB } }) store.state.a // -> moduleA 的狀態 store.state.b // -> moduleB 的狀態 ``` 對于模塊內部的 mutation 和 getter,接收的第一個參數是**模塊的局部狀態對象**。 ```js const moduleA = { state: { count: 0 }, mutations: { increment (state) { // 這里的 `state` 對象是模塊的局部狀態 state.count++ } }, getters: { doubleCount (state) { return state.count * 2 } } } ``` 項目結構: ```shell ├── index.html ├── main.js ├── api │ └── ... # 抽取出API請求 ├── components │ ├── App.vue │ └── ... └── store ├── index.js # 我們組裝模塊并導出 store 的地方 ├── actions.js # 根級別的 action ├── mutations.js # 根級別的 mutation └── modules ├── cart.js # 購物車模塊 └── products.js # 產品模塊 ``` 完整的 vuex 項目結構示例 [點擊這里](https://github.com/ChenMingK/epub-Proj/tree/master/src/store)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看