Vue-day-05(路由概念與原理,Vue-router,路由嵌套,動態路由))

1 路由的基本概念與原理

1.1路由:
前端路由
后端路由

  • 介紹
  • 路由的本質就是一種對應關系,比如說我們在url地址中輸入我們要訪問的url地址之后,瀏覽器要去請求這個url地址對應的資源。
  • 那么url地址和真實的資源之間就有一種對應的關系,就是路由。
  • 路由分為前端路由和后端路由
    1). 后端路由是由服務器端進行實現,并完成資源的分發 (url與資源/數據的對應關系)
    2). 前端路由是依靠hash值(錨點鏈接)的變化進行實現 (錨點與組件之間的關系)
  • 后端路由性能相對前端路由來說較低,所以,我們接下來主要學習的是前端路由
  • 前端路由的基本概念:根據不同的事件來顯示不同的頁面內容,即事件與事件處理函數之間的對應關系
  • 前端路由主要做的事情就是監聽事件并分發執行事件處理函數

1.2后端路由

  • 介紹:


    image.png

1.3SPA

總結

image.png

  • 后端渲染界面,只要有一處修改,就需要刷新整個界面,存在性能問題
  • Ajax可以局部刷新,但是不支持前進后退
  • spa可以局部刷新,也支持前進后退

1.4 前端路由

image.png

1.5 路由總結

  • 路由:表示一種對應關系,某些事物的一 一對應的關系
  • 后端路由:url與后端資源的一 一對應的關系
  • 前端路由:用戶事件與事件處理函數一 一對應的關系

1.6 實現簡易前端路由

  • 介紹
    • 前端路由是基于hash值的變化進行實現的
      • 這里的hash值指的是url的hash值,也就是界面的錨點
    • 比如點擊頁面中的菜單或者按鈕改變URL的hash值,根據hash值的變化來控制組件的切換
    • 核心實現依靠一個事件,即監聽hash值變化的事件
window.onhashchange = function(){
    //location.hash可以獲取到最新的hash值
    location.hash
}

案例:
核心思路:

  • 在頁面中有一個vue實例對象,vue實例對象中有四個組件,分別是tab欄切換需要顯示的組件內容
  • 在頁面中有四個超鏈接,如下:
  • 當我們點擊這些超鏈接的時候,就會改變url地址中的hash值,當hash值被改變時,就會觸發onhashchange事件
  • 在觸發onhashchange事件的時候,我們根據hash值來讓不同的組件進行顯示:
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta http-equiv="X-UA-Compatible" content="ie=edge" />
        <title>Document</title>
        <!-- 導入 vue 文件 -->
        <script src="./lib/vue_2.5.22.js"></script>
    </head>
    <body>
        <!-- 被 vue 實例控制的 div 區域 -->
        <div id="app">
        <!-- 切換組件的超鏈接 -->
        <a href="#/zhuye">主頁</a> 
        <a href="#/keji">科技</a> 
        <a href="#/caijing">財經</a>
        <a href="#/yule">娛樂</a>

        <!-- 根據 :is 屬性指定的組件名稱,把對應的組件渲染到 component 標簽所在的位置 -->
        <!-- 可以把 component 標簽當做是【組件的占位符】 -->
        <component :is="comName"></component>
        </div>

        <script>
        // #region 定義需要被切換的 4 個組件
        // 主頁組件
        const zhuye = {
            template: '<h1>主頁信息</h1>'
        }

        // 科技組件
        const keji = {
            template: '<h1>科技信息</h1>'
        }

        // 財經組件
        const caijing = {
            template: '<h1>財經信息</h1>'
        }

        // 娛樂組件
        const yule = {
            template: '<h1>娛樂信息</h1>'
        }
        // #endregion

        // #region vue 實例對象
        const vm = new Vue({
            el: '#app',
            data: {
            comName: 'zhuye'
            },
            // 注冊私有組件
            components: {
            zhuye,
            keji,
            caijing,
            yule
            }
        })
        // #endregion

        // 監聽 window 的 onhashchange 事件,根據獲取到的最新的 hash 值,切換要顯示的組件的名稱
        window.onhashchange = function() {
            // 通過 location.hash 獲取到最新的 hash 值
            console.log(location.hash);
            switch(location.hash.slice(1)){
            case '/zhuye':
                vm.comName = 'zhuye'
            break
            case '/keji':
                vm.comName = 'keji'
            break
            case '/caijing':
                vm.comName = 'caijing'
            break
            case '/yule':
                vm.comName = 'yule'
            break
            }
        }
        </script>
    </body>
    </html>

2 vue-router的基本使用

2.1 基本使用

介紹
它是一個Vue.js官方提供的路由管理器。是一個功能更加強大的前端路由器,推薦使用
Vue Router和Vue.js非常契合,可以一起方便的實現SPA(single page web application,單頁應用程序)應用程序的開發
Vue Router依賴于Vue,所以需要先引入Vue,再引入Vue Router
官網:https://router.vuejs.org/zh/

Vue Router的特性:

  • 支持H5歷史模式或者hash模式
  • 支持嵌套路由
  • 支持路由參數
  • 支持編程式路由
  • 支持命名路由
  • ....

基本使用步驟:
1.導入js文件
2.添加路由鏈接
3.添加路由占位符(最后路由展示的組件就會在占位符的位置顯示)
4.定義路由組件
5.配置路由規則并創建路由實例
6.將路由掛載到Vue實例中

1.導入js文件

image.png

2.添加路由鏈接
image.png

3.添加路由占位符(最后路由展示的組件就會在占位符的位置顯示)
image.png

router-view:路由-視圖,顯示用戶點擊的路由鏈接對應的組件

  • 視圖:組件可以顯示出具體內容,可以理解為視圖
  • 例如:用戶點擊User路由鏈接,就會將User組件顯示到這里

4.定義路由組件

image.png

5.創建路由實例,并配置路由規則
image.png

6.將路由掛載到Vue實例中
image.png

  • router是:router:router的簡寫
  • 如果VueRouter的實例名是xxx,那掛載時,就需要寫:router:xxx
  • Vue實例化時,參數el,data,methods,router都是固定的

代碼:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <!--1. 導入 vue 文件 -->
    <script src="./lib/vue_2.5.22.js"></script>
    <script src="./lib/vue-router_3.0.2.js"></script>
  </head>
  <body>
    <!--2. 添加路由鏈接:to渲染成href。to的值渲染成#hash值(錨點)-->
    <!-- 被 vm 實例所控制的區域 -->
    <div id="app">
      <router-link to="/user">User</router-link><!--<a href="#/user"> User</a>-->
      <router-link to="/register">Register</router-link>

      <!-- 3.路由占位符 -->
      <router-view></router-view>
    </div>

    <script>
     //4.定義路由組件
      const User = {
        template: '<h1>User 組件</h1>'
      }

      const Register = {
        template: '<h1>Register 組件</h1>'
      }
    //5. 配置路由規則,并創建路由實例
      // 創建路由實例對象
      const router = new VueRouter({
        // 所有的路由規則
        routes: [
          { path: '/user', component: User },
          { path: '/register', component: Register }
        ]
      })

      // 創建 vm 實例對象
      const vm = new Vue({
        // 指定控制的區域
        el: '#app',
        data: {},
        //6.掛載路由實例對象
        // router: router
        router
      })
    </script>
  </body>
</html>

2.2 路由重定向

介紹:


image.png
  • rediret:重定向
  • 普通的路由是定義path和component,訪問url顯示對應組件
  • 重定向路由是定義path和redirect,訪問url跳轉到另一個url

代碼:

//將上一個案例的路由規則增加一個重定向:
// 創建路由實例對象
const router = new VueRouter({
    // 所有的路由規則
    routes: [
        { path: '/', redirect: '/user'},//增加這一行代碼,如果訪問跟路徑/,則重定向到/user
        { path: '/user', component: User },
        { path: '/register', component: Register }
    ]
})

效果:

  • 再訪問:03.路由重定向.html
  • 會跳轉:03.路由重定向.html#/user

3 vue-router嵌套路由

  • 通過路由嵌套,可以處理復雜的界面
  • 嵌套路由功能分析:如下圖:點擊Register之后發現Register組件中嵌套了另一塊內容

步驟:
1. 父路由組件模板

image.png

2 子級路由模板

image.png

  • 因為子級模板是哎register組件內顯示的,所以應該定義在register組件的template中
  • 在template添加路由連接,子url是/register開頭
  • 在template添加router-view,給子組件占位

3 路由嵌套配置

image.png

  • 作為register的子組件,那么就需要在register的children屬性中定義路由規則
    代碼:
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <!-- 導入 vue 文件 -->
    <script src="./lib/vue_2.5.22.js"></script>
    <script src="./lib/vue-router_3.0.2.js"></script>
  </head>
  <body>
    <!-- 被 vm 實例所控制的區域 -->
    <div id="app">
      <router-link to="/user">User</router-link>
      <router-link to="/register">Register</router-link>

      <!-- 路由占位符 -->
      <router-view></router-view>
    </div>

    <script>
      const User = {
        template: '<h1>User 組件</h1>'
      }

      const Register = {
        template: `<div>
          <h1>Register 組件</h1>
          <hr/>

          <!-- 子路由鏈接 -->
          <router-link to="/register/tab1">tab1</router-link>
          <router-link to="/register/tab2">tab2</router-link>

          <!-- 子路由的占位符 -->
          <router-view />
        <div>`
      }

      const Tab1 = {
        template: '<h3>tab1 子組件</h3>'
      }

      const Tab2 = {
        template: '<h3>tab2 子組件</h3>'
      }

      // 創建路由實例對象
      const router = new VueRouter({
        // 所有的路由規則
        routes: [
          { path: '/', redirect: '/user'},
          { path: '/user', component: User },
          // children 數組表示子路由規則
          { path: '/register', component: Register, children: [
            { path: '/register/tab1', component: Tab1 },
            { path: '/register/tab2', component: Tab2 }
          ] }
        ]
      })

      // 創建 vm 實例對象
      const vm = new Vue({
        // 指定控制的區域
        el: '#app',
        data: {},
        // 掛載路由實例對象
        // router: router
        router
      })
    </script>
  </body>

總結:

  • 關于router-view和router-link的書寫位置:
  • 路由規則在哪定義的,router-view和router-link就寫在誰的模板中
  • Register和User定義在vm中,那么他們的router-view和router-link就定義在app中
  • app這個div就可以理解為vm的模板
  • Register和User可以理解為vm的子組件
  • Tab1和Tab2定義在Register中,那么他們的router-view和router-link就定義Register中的模板中
  • 路由規則在哪定義的,決定了自己的父組件是誰,那么子組件的router-view和router-link就定義在父組件的模板中

分析圖:


image.png

4 vue-router動態路由匹配

4.1 動態路由匹配

  • 需求:點擊不同的用戶連接,顯示對應的用戶信息
  • 定義如下路由鏈接和路由規則,是否可行?

image.png

動態路由匹配介紹:

image.png
  • 匹配規則定義時,動態路由語法為:參數名,以冒號開頭,就代表是動態匹配
  • 路由組件定義時,獲取路由參數為:{{$route.params.參數名}}
  • $route.params.是固定寫法
  • Vue實例的屬性,都是開頭,比如el
// 創建 vm 實例對象
const vm = new Vue({
    // 指定控制的區域
    el: '#app',
    data: {},
    // 掛載路由實例對象
    // router: router
    router
})
  • 創建Vue實例時,傳遞的參數有:el,data,router
  • 那么vm有了el,data,$router屬性
  • 但是獲取動態參數,是{{$route.params.參數名}}

代碼:

<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
    <!-- 導入 vue 文件 -->
    <script src="./lib/vue_2.5.22.js"></script>
    <script src="./lib/vue-router_3.0.2.js"></script>
  </head>
  <body>
    <!-- 被 vm 實例所控制的區域 -->
    <div id="app">
      <router-link to="/user/1">User1</router-link>
      <router-link to="/user/2">User2</router-link>
      <router-link to="/user/3">User3</router-link>
      <router-link to="/register">Register</router-link>

      <!-- 路由占位符 -->
      <router-view></router-view>
    </div>

    <script>
      const User = {
        template: '<h1>User 組件 -- 用戶id為: {{$route.params.id}}</h1>'
      }

      const Register = {
        template: '<h1>Register 組件</h1>'
      }

      // 創建路由實例對象
      const router = new VueRouter({
        // 所有的路由規則
        routes: [
          { path: '/', redirect: '/user'},
          { path: '/user/:id', component: User },
          { path: '/register', component: Register }
        ]
      })

      // 創建 vm 實例對象
      const vm = new Vue({
        // 指定控制的區域
        el: '#app',
        data: {},
        // 掛載路由實例對象
        // router: router
        router
      })
    </script>
  </body>

4.2 路由組件傳遞參數

介紹:

image.png
  • 就是在組件中想要獲取路由參數,需要通過{{$route.params.id}}來獲取,比較麻煩

4.2.1 props的值為布爾類型

image.png
  • 路由定義規則中:props:true,代表給動態參數id,開啟props傳參(其實就是通過props方式傳遞參數)
  • 路由組件定義中:通過props接收參數
  • 這樣就不用通過{{$route.params.id}}獲取
  • 其實這個跟之前的組件通過屬性傳遞數據是類似的:
<User id='1'></User>
這個1就會傳遞給User組件的props屬性id

代碼:

<body>
    <!-- 被 vm 實例所控制的區域 -->
    <div id="app">
      <router-link to="/user/1">User1</router-link>
      <router-link to="/user/2">User2</router-link>
      <router-link to="/user/3">User3</router-link>
      <router-link to="/register">Register</router-link>

      <!-- 路由占位符 -->
      <router-view></router-view>
      <User id='1'></User>
    </div>

    <script>
      const User = {
        props: ['id'],
        template: '<h1>User 組件 -- 用戶id為: {{id}}</h1>'
      }

      const Register = {
        template: '<h1>Register 組件</h1>'
      }

      // 創建路由實例對象
      const router = new VueRouter({
        // 所有的路由規則
        routes: [
          { path: '/', redirect: '/user'},
          { path: '/user/:id', component: User, props: true },
          { path: '/register', component: Register }
        ]
      })

      // 創建 vm 實例對象
      const vm = new Vue({
        // 指定控制的區域
        el: '#app',
        data: {},
        // 掛載路由實例對象
        // router: router
        router
      })
    </script>
  </body>

內部原理:


image.png

4.2.2 props的值為對象類型

  • 介紹:
image.png
  • uname的lisi傳遞給User組件中props的uname,age的12傳遞給User組件中props的age
  • 這時的id就無法獲取了,所以id在這種方式中就廢了
  • 只有props為true時,才會將:id作為參數傳遞給User

代碼:

<body>
    <!-- 被 vm 實例所控制的區域 -->
    <div id="app">
      <router-link to="/user/1">User1</router-link>
      <router-link to="/user/2">User2</router-link>
      <router-link to="/user/3">User3</router-link>
      <router-link to="/register">Register</router-link>
      <!-- 路由占位符 -->
      <router-view></router-view>
    </div>

    <script>
      const User = {
        props: ['id', 'uname', 'age'],
        //這個id其實是拿不到值的
        template: '<h1>User 組件 -- 用戶id為: {{id}} -- 姓名為:{{uname}} -- 年齡為:{{age}}</h1>'
      }

      const Register = {
        template: '<h1>Register 組件</h1>'
      }

      // 創建路由實例對象
      const router = new VueRouter({
        // 所有的路由規則
        routes: [
          { path: '/', redirect: '/user'},
          { path: '/user/:id', component: User, props: { uname: 'lisi', age: 20 } },
          { path: '/register', component: Register }
        ]
      })

      // 創建 vm 實例對象
      const vm = new Vue({
        // 指定控制的區域
        el: '#app',
        data: {},
        // 掛載路由實例對象
        // router: router
        router
      })
    </script>
  </body>

4.2.3 props的值為函數類型

  • 介紹:
image.png
  • props指定了一個箭頭函數:相當于如下代碼
 ``` props:function (route){
      return {uname:'zs',age:20,id:route.params.id}
  }```
  • 箭頭函數返回了一個對象,對象中的數據,就是要傳遞的數據
  • uname和age是定死的值
  • router是箭頭函數的形參,系統在調用時會將$route傳遞進去
  • id是通過route.params.id動態獲取到id參數的值
    代碼:
<body>
    <!-- 被 vm 實例所控制的區域 -->
    <div id="app">
      <router-link to="/user/1">User1</router-link>
      <router-link to="/user/2">User2</router-link>
      <router-link to="/user/3">User3</router-link>
      <router-link to="/register">Register</router-link>

      <!-- 路由占位符 -->
      <router-view></router-view>
    </div>

    <script>
      const User = {
        props: ['id', 'uname', 'age'],
        template: '<h1>User 組件 -- 用戶id為: {{id}} -- 姓名為:{{uname}} -- 年齡為:{{age}}</h1>'
      }

      const Register = {
        template: '<h1>Register 組件</h1>'
      }

      // 創建路由實例對象
      const router = new VueRouter({
        // 所有的路由規則
        routes: [
          { path: '/', redirect: '/user' },
          {
            path: '/user/:id',
            component: User,
            props: route => ({ uname: 'zs', age: 20, id: route.params.id })
          },
          { path: '/register', component: Register }
        ]
      })

      // 創建 vm 實例對象
      const vm = new Vue({
        // 指定控制的區域
        el: '#app',
        data: {},
        // 掛載路由實例對象
        // router: router
        router
      })
    </script>
  </body>

5. vue-router命名路由

介紹:


image.png
  • 這樣就不用在定義路由鏈接得時候,在to中寫具體的path了
  • 有時候path比較復雜,用名字代替會更好一點
  • 如果path中有參數,那么在to中就通過params來確定參數的值
  • 相當于:
    <router-link to="/user/123">User2</router-link>
    代碼:
<body>
    <!-- 被 vm 實例所控制的區域 -->
    <div id="app">
      <router-link to="/user/1">User1</router-link>
      <router-link to="/user/2">User2</router-link>
      <router-link :to="{ name: 'user', params: {id: 3} }">User3</router-link>
      <!--原來寫法,可能你會更喜歡原來的寫法,但是如果path比較復雜時,用命名路由會更好-->
      <router-link to="/user/3">User2</router-link>
      <router-link to="/register">Register</router-link>

      <!-- 路由占位符 -->
      <router-view></router-view>
    </div>

    <script>
      const User = {
        props: ['id', 'uname', 'age'],
        template: '<h1>User 組件 -- 用戶id為: {{id}} -- 姓名為:{{uname}} -- 年齡為:{{age}}</h1>'
      }

      const Register = {
        template: '<h1>Register 組件</h1>'
      }

      // 創建路由實例對象
      const router = new VueRouter({
        // 所有的路由規則
        routes: [
          { path: '/', redirect: '/user' },
          {
            // 命名路由
            name: 'user',
            path: '/user/:id',
            component: User,
            props: route => ({ uname: 'zs', age: 20, id: route.params.id })
          },
          { path: '/register', component: Register }
        ]
      })

      // 創建 vm 實例對象
      const vm = new Vue({
        // 指定控制的區域
        el: '#app',
        data: {},
        // 掛載路由實例對象
        // router: router
        router
      })
    </script>
  </body>

6. vue-router編程式導航

6.1 頁面導航的兩種方式

image.png
  • 聲明式導航,其實就是html實現導航
  • 編程時導航,其實就是js代碼實現導航(location.href就是js代碼)
  • 頁面導航,其實就是頁面跳轉

6.2 編程導航

  • 基本用法


    image.png
  • push跳轉錨點
  • go前進后退,參數n一個數字,代表前進后退幾個界面
  • n,代表前進n個界面
  • -n,代表后退n個界面

代碼:

<body>
    <!-- 被 vm 實例所控制的區域 -->
    <div id="app">
      <router-link to="/user/1">User1</router-link>
      <router-link to="/user/2">User2</router-link>
      <router-link :to="{ name: 'user', params: {id: 3} }">User3</router-link>
      <router-link to="/register">Register</router-link>

      <!-- 路由占位符 -->
      <router-view></router-view>
    </div>

    <script>
      const User = {
        props: ['id', 'uname', 'age'],
        template: `<div>
          <h1>User 組件 -- 用戶id為: {{id}} -- 姓名為:{{uname}} -- 年齡為:{{age}}</h1>
          <button @click="goRegister">跳轉到注冊頁面</button>
        </div>`,
        methods: {
          goRegister() {
            this.$router.push('/register')//跳轉到注冊頁面(錨點),可以看下效果
          }
        },
      }

      const Register = {
        template: `<div>
          <h1>Register 組件</h1>
          <button @click="goBack">后退</button>
        </div>`,
        methods: {
          goBack() {
            this.$router.go(-1)//-1:后退1個界面
          }
        }
      }

      // 創建路由實例對象
      const router = new VueRouter({
        // 所有的路由規則
        routes: [
          { path: '/', redirect: '/user' },
          {
            // 命名路由
            name: 'user',
            path: '/user/:id',
            component: User,
            props: route => ({ uname: 'zs', age: 20, id: route.params.id })
          },
          { path: '/register', component: Register }
        ]
      })

      // 創建 vm 實例對象
      const vm = new Vue({
        // 指定控制的區域
        el: '#app',
        data: {},
        // 掛載路由實例對象
        // router: router
        router
      })
    </script>
  </body>

6.3 push參數 (了解)

  • 介紹


    image.png
  • 跟route-link是一樣的作用,都是實現頁面跳轉
  • 所以push中可以直接寫path路徑(路由),也可以寫命名路由
  • 相當于:
<!--前兩個對應這個  -->
<router-link to="/home">User1</router-link>
<!--#push中的name應該也不帶斜杠才對-->
<router-link :to="{ name: 'user', params: {userId: 123} }">User123</router-link>
<router-link to="/register?uname=lisi">Register</router-link>
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 1.背景介紹 vue router是vue.js官方的路由管理器,它和vue.js的核心深度集成,讓構建單頁面應用...
    expecto_5357閱讀 429評論 0 1
  • Vue全家桶-前端路由 一、路由的基本概念與原理 1.路由:是一個比較廣義和抽象的概念,路由的本質就是對應關系。 ...
    coder_shen閱讀 378評論 0 0
  • ### 什么是Vue.js + Vue.js 是目前最火的一個前端框架,React是最流行的一個前端框架(Reac...
    JLong閱讀 1,103評論 0 0
  • ## 框架和庫的區別?> 框架(framework):一套完整的軟件設計架構和**解決方案**。> > 庫(lib...
    Rui_bdad閱讀 2,961評論 1 4
  • # 傳智播客vue 學習## 1. 什么是 Vue.js* Vue 開發手機 APP 需要借助于 Weex* Vu...
    再見天才閱讀 3,599評論 0 6