初學Vue(五) -- 路由

學習列表

初學Vue(一)-- Vue簡單入門

初學vue(二)-- 條件渲染、修飾符、循環

初學vue(三)-- 生命週期、過濾器、監聽屬性、計算屬性

初學vue(四)-- axios先後端交互、組件


單頁面應用程序

  • SPA : Single Page Application 單頁面應用程序
  • MPA : Multiple Page Application 多頁面應用程序
  • 單頁 web 應用

    就是隻有一個 web 頁面的應用,
    是加載單個 HTML 頁面,
    並在用戶與應用程序交互時, 動態更新該頁面的 web 應用程序css

  • 區別html

    • 對於傳統的多頁面應用程序來講, 每次請求服務器返回的都是一個完整的頁面
    • 對於單頁應用程序來講,

      只有第一次會加載頁面,
      之後的每次請求,
      僅僅是獲取必要的數據.而後,
      由頁面中 js 解析獲取的數據,
      展現在頁面中前端

  • 單頁面優點 :vue

    1. 減小了請求體積,加快頁面響應速度,下降了對服務器的壓力
    2. 更好的用戶體驗,讓用戶在 web app 感覺 native app 的流暢, (局部刷新)
  • 單頁面劣勢 :node

    1. 開發成本高 (須要學習路由)
    2. 不利於 SEO
  • 演示 : https://music.163.com/

介紹路由

  • 路由 : 是瀏覽器 URL 中的哈希值( # hash) 與 展現視圖內容 之間的對應規則ios

    • 簡單來講,路由就是一套映射規則(一對一的對應規則), 由開發人員制定規則.-
    • 當 URL 中的哈希值( # hash) 發生改變後,路由會根據制定好的規則, 展現對應的視圖內容
  • 爲何要學習路由?web

    • 在 web App 中, 常常會出現經過一個頁面來展現和管理整個應用的功能.
    • SPA 每每是功能複雜的應用,爲了有效管理全部視圖內容,前端路由 應運而生.
  • vue 中的路由 : 是 hashcomponent 的對應關係, 一個哈希值對應一個組件

一 : 路由的基本使用

準備工做 (3個)

  • 安裝 : npm i vue-router
  • 引入 :
<script src="./vue.js"></script>
// 千萬注意 :引入路由必定要在引入vue以後,由於vue-router是基於vue工做的
<script src="./node_modules/vue-router/dist/vue-router.js"></script>
  • 實例路由對象 + 掛載到vue上vue-router

    • 實例路由對象 : const router = new VueRouter()
    • 掛載到vue上 : new Vue({ router,data,methods })
    • 驗證路由是否掛載成功, 就看打開頁面,最後面有沒有個 #/

具體步驟 (4個)

  • 1.入口
  • 2.路由規則
  • 3.組件
  • 4.出口
# 1. 入口
     // 方式1 : url地址爲入口   調試開發用
     輸入url地址 改變哈希值 `01-路由的基本使用.html#/one`    
     // 方式2 : 聲明式導航 : router-link+to (見下面介紹)
# 2. 路由規則
// path : 路由路徑
// component : 未來要展現的路由組件
routes: [
    { path: '/one', component: One }, 
    { path: '/two', component: Two }
]
# 3. 組件
// 使用返回值的這個組件名稱
const One = Vue.component('one', {
  template: ` <div> 子組件 one </div> `
})
# 4. 出口
<!--  出口 組件要展現的地方-->
<router-view></router-view>

# 總結
拿到入口哈希路徑, 根據路由匹配規則,找到對應的組件,顯示到對應的出口位置

二 : 由使用注意事項

  • 入口npm

    • 最經常使用的入口 是 聲明式導航 router-link
<!-- 
router-link 組件最終渲染爲 a標籤, to屬性轉化爲 a標籤的href屬性
to 屬性的值 , 實際上就是哈希值,未來要參與路由規則中進行與組件匹配
  -->
<router-link to="/one">首頁</router-link>
  • 組件
const One = {
  template: `<div> 子組件 one </div> `
}
  • 演示 : 多個組件匹配
<div id="app">
  <!-- 1 路由入口:連接導航 -->
  <router-link to="/one">One</router-link>
  <router-link to="/two">Two</router-link>

  <!-- 4 路由出口:用來展現匹配路由視圖內容 -->
  <router-view></router-view>
</div>

<!--  導入 vue.js -->
<script src="./vue.js"></script>
<!--  導入 路由文件 -->
<script src="./node_modules/vue-router/dist/vue-router.js"></script>
<script>
  // 3 建立兩個組件
  const One ={
    template: '<h1>這是 one 組件</h1>'
  }
  const Two =  {
    template: '<h1>這是 two 組件</h1>'
  }

  // 0 建立路由對象
  const router = new VueRouter({
    // 2. 路由規則
    routes: [
      { path: '/one', component: One },
      { path: '/two', component: Two }
    ]
  })

  const vm = new Vue({
    el: '#app',
    //0. 不要忘記,將路由與vue實例關聯到一塊兒!
    router
  })
</script>

三 : 入口導航菜單高亮處理

  • 點擊導航 => 元素裏添加了兩個類
<a href="#/one" class="router-link-exact-active router-link-active">One</a>
<a href="#/two" class="">Two</a>
  • 修改方式1 : 直接修改類的樣式
.router-link-exact-active,
.router-link-active {
  color: red;
  font-size: 50px;
}
  • 修改方式2 : 使用存在過的類樣式 => 修改默認高亮類名
const router = new VueRouter({
  routes: [],
  // 修改默認高亮的a標籤的類名
  // red 是已經存在過的
  linkActiveClass: 'red'
})

四: 路由配置

4.1 動態路由 => 詳情列表

導入 : 列表三個手機都要點擊進去詳情頁, 只須要一個組件,顯示不一樣的數據便可
# 入口
<router-link to="/detail/1">手機1</router-link>
<router-link to="/detail/2">手機2</router-link>
<router-link to="/detail/3">手機3</router-link>

<router-link to="/detail">手機4</router-link>  沒有參數如何????

# 規則
routes: [
  // 2 . 路由規則
  { path: '/detail/:id?', component: Detail }
]

# 獲取參數的三種方式
const Detail =  {
    template: `
        // 方式1 : 組件中直接讀取
        <div> 顯示詳情頁內容....{{ $route.params.id  }} </div>
    `,
    created() {
        // 方式2 : js直接讀取
        // 打印只會打印一次,由於組件是複用的,每次進來鉤子函數只會執行一次
        console.log(this.$route.params.id)
    },
    // 方式3 : 監聽路由的參數,爲何不須要深度監聽,由於一個路徑變化,就會對應一個對新的路由對象(地址變)
    watch: {
        $route(to, from) {
            console.log(to.params.id)
        }
    }
}

4.2 路由對象 - $route

  • 一個路由對象 (route object) 表示當前激活的路由的狀態信息,包含了當前 URL 解析獲得的信息
  • 一個哈希值路徑 ==> 一個路由對象
  • $route.path編程

    • 類型: string
    • 字符串,對應當前路由的路徑,老是解析爲絕對路徑,如 "/foo/bar"
    • # 後面?前面的內容
  • $route.params

    • 類型: Object
    • 一個 key/value 對象,包含了動態片斷和全匹配片斷,若是沒有路由參數,就是一個空對象。
    • 一個 key/value 對象,包含了動態片斷和全匹配片斷,若是沒有路由參數,就是一個空對象。
  • $route.query

    • 類型: Object
    • 參數對象
    • 一個 key/value 對象,表示 URL 查詢參數。例如,對於路徑 /foo?user=1,則有 $route.query.user == 1,若是沒有查詢參數,則是個空對象。
  • $route.hash

    • 類型: string

      當前路由的 hash 值 (帶 #) ,若是沒有 hash 值,則爲空字符串。

  • $route.fullPath

    • 類型: string
    • 全路徑
    • 完成解析後的 URL,包含查詢參數和 hash 的完整路徑。
# 演示 : 
<router-link to="/detail/4?age=21#one">detail</router-link>
{ path: '/detail/:id?', component: detail } 
在組件內 created打印 this.$route
> fullPath: "/detail/4?id=001#one"
> hash : "#one"
> params : {id:'4'}
> query : {age : 21}
> path : '/detail/4'

4.3 嵌套路由 => children

導入 : url測試 parent 和child, 想讓child 在 parent 中顯示
  • parent 的內部 添加 : <router-view> </router-view>
  • 規則裏添加 children
  • /child 和 child 的區別

    • 若是是/child => 那麼訪問就能夠直接訪問#/child就能夠訪問 子組件
    • 若是是child => 那麼訪問就應該訪問#/parent/child才能夠訪問子組件
const parent = {
    template: `<p>parent  <router-view> </router-view> </p>`
}
const child = {
    template: `<p>child</p>`
}

const router = new VueRouter({
    routes: [
        {
            path: '/parent',
            component: parent,
            children: [
                { path: '/child', component: child }
            ]
        }
    ]
})

4.4 命名路由

  • 有時候,經過一個名稱來標識一個路由顯得更方便一些,
  • 特別是在連接一個路由,或者是執行一些跳轉的時候。 ===> 場景
  • 你能夠在建立 Router 實例的時候,在 routes 配置中給某個路由設置名稱。 ==> 如何命名
# 命名
routes: [
    {
        path: '/parent',
        name: 'parent',
        component: parent
    }
]

# 入口連接 + 跳轉  (使用 path 和 name 的轉換)
<!-- 方式1 : url手動寫 -->

<!-- 方式2 : 入口連接 聲明式導航 -->
<router-link to="/parent">點擊</router-link>
<router-link :to="{ name : 'parent' }">點擊</router-link>  # 忘了 帶 : 原始對象類型

<!-- 方式3 : 編程式導航 -->
 fn() {
     // this.$router.push('/parent')
     this.$router.push({
         name: 'parent'
     })
 }

4.5 命名視圖

導入 : 有時候想同時 (同級) 展現多個視圖,

需求 : 訪問 / 根目錄 同時展現如下三個組件

  • 三個組件
const header = {
    template: `<p>header  </p>`
}
const main = {
    template: `<p>main  </p>`
}
const footer = {
    template: `<p>footer  </p>`
}
  • 規則
# 之前的那個方式只能顯示三個 header
# 演示以前的效果 

routes: [
    {
        path: '/',
        components: {
            default: header,
            m: main,
            f: footer
        }
    }
]
  • 出口
<router-view> </router-view>
<router-view name="m"> </router-view>
<router-view name="f"> </router-view>

4.6 重定向

redirect: '/header'
redirect: { name: 'header' }
redirect: to => {
      // console.log(to)
    return {
        name: 'about'
    }
}

4.7 組件傳參

  • 原始方式使用 $route獲取
# 入口
    <router-link to="/header/3">123</router-link>
# 規則
routes: [
    {
        path: '/header/:id',
        component: header,
    }
]
# 獲取參數
const header = {
    template: `<p>header  {{ $route.params.id }}  </p>`
}
  • 布爾模式
# 入口
    <router-link to="/header/3">123</router-link>

# 規則
routes: [
    {
        path: '/header/:id',
        component: header,
        // 若是 props 被設置爲 true,route.params 將會被設置爲組件屬性
        props: true
    }
]

# 獲取參數
const header = {
    // 參數 id 當成參數
    props: ['id'],
    template: `<p>header   {{ id }} </p>`
}
  • 對象模式
# 入口
 <router-link to="/header">123</router-link>

# 規則
 routes: [
     {
         path: '/header',
         component: header,
         props: { foo: '0000' }
     }
 ]
# 組件
 const header = {
        props: ['foo'],
        template: `<p>header   {{ foo }} </p>`
 }
  • 函數模式
# 同對象模式同樣
# 區別是props值不同
 props: to => {
     return { foo: '0000' }
 }
  • 注意 : 對象模式和函數模式參數 在props裏,因此聲明式導航那裏就不要傳參了

4.8嵌套路由

實際生活中的應用界面,一般由多層嵌套的組件組合而成。一樣地,URL 中各段動態路徑也按某種結構對應嵌套的各層組件。

藉助 vue-router,使用嵌套路由配置,就能夠很簡單地表達這種關係。

  • 單層路由
<div id="app">
  <router-view></router-view>
</div>
const User = {
  template: '<div>User {{ $route.params.id }}</div>'
}

const router = new VueRouter({
  routes: [
    { path: '/user/:id', component: User }
  ]
})

這裏的 <router-view> 是最頂層的出口,渲染最高級路由匹配到的組件。一樣地,一個被渲染組件一樣能夠包含本身的嵌套 <router-view>。例如,在 User 組件的模板添加一個 <router-view>

  • 嵌套路由

    • 模板配置
    const User = {
      template: `
        <div class="user">
          <h2>User {{ $route.params.id }}</h2>
          <router-view></router-view>
        </div>
      `
    }
  • 路由配置:要在嵌套的出口中渲染組件,須要在 VueRouter 的參數中使用 children 配置
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
        }
      ]
    }
  ]
})

注意,以 / 開頭的嵌套路徑會被看成根路徑。 這讓你充分的使用嵌套組件而無須設置嵌套的路徑。

五 : 路由進階

5.1 元信息

  • 規則聲明
routes: [
     {
         path: '/header',
         component: header,
         meta: {
            title: 'XXXX'
         }
     }
 ]
  • 獲取
created() {
    document.title = this.$route.meta.title
 }
  • 做用 :
  • 在路由導航的時候,能夠用做判斷

5.2 編程式導航

const one = {
    template: ` 
<div> <button @click="handleClick('back')">返回 上一頁</button>
<button @click="handleClick('push')">跳轉 two頁</button>
<button @click="handleClick('replace')">替換 two頁</button> 
</div>`,
    methods: {
        handleClick(type) {
            if (type == 'back') {
                // 返回
                this.$router.back()
            } else if (type == 'push') {
                // 跳轉 有歷史記錄
                this.$router.push('/two')
            } else {
                // 替換 沒有歷史記錄
                this.$router.replace('/two')
            }
        }
    }
}
const two = {
    template: `<p>two </p>`
}

5.3 導航守衛

router.beforeEach((to, from, next) => {
    // 訪問 login

    if (to.name == 'login') {
        // 下一步
        next()
    } else {
        // 中止跳轉
        next(false)
        // 跳轉到下一步
        next({ name: 'login' }) 或者 使用路徑  next('/login')
    }
})
相關文章
相關標籤/搜索