前端學(xué)習(xí)筆記二十七-Vue-Router

一.路由的概念與原理

路由的本質(zhì)就是一種對應(yīng)關(guān)系,比如我們在url地址中輸入我們要訪問的url地址之后,瀏覽器要去請求這個url地址對應(yīng)的資源。
那么url地址和真實的資源之間就有一種對應(yīng)的關(guān)系,就是路由。

路由分為前端路由后端路由

1.1 后端路由

后端路由是根據(jù)不同的用戶URL請求,返回不同的內(nèi)容,本質(zhì)就是URL請求地址與服務(wù)器資源之間的對應(yīng)關(guān)系。
由服務(wù)器端進行實現(xiàn),并完成資源的分發(fā)。


1.2 前端路由

前端路由依靠hash值(錨鏈接)的變化進行實現(xiàn)。

后端路由性能相對前端路由來說較低,所以,我們接下來主要學(xué)習(xí)的是前端路由。
基本概念:根據(jù)不同的事件來顯示不同的頁面內(nèi)容,即用戶事件事件處理函數(shù)之間的對應(yīng)關(guān)系。
前端路由主要做的事情就是監(jiān)聽事件并分發(fā)執(zhí)行事件處理函數(shù)。

1.3 SPA(Single Page Application)

  • 后端渲染(存在性能問題)
  • Ajax前端渲染(前端渲染提高性能,但是不支持瀏覽器的后退操作)
  • SPA單頁面應(yīng)用程序:整個網(wǎng)站只有一個頁面,內(nèi)容的變化通過Ajax局部更新實現(xiàn),同時支持瀏覽器地址欄的前進和后退操作
  • SPA的實現(xiàn)原理之一:基于URL地址的hash(hash的變化會導(dǎo)致瀏覽器訪問歷史記錄的變化,但hash的變化不會觸發(fā)新的URL請求)
  • 在實現(xiàn)SPA的過程中,最核心的技術(shù)點就是前端路由

二、前端路由的初體驗

前端路由是基于hash值的變化進行實現(xiàn)的(比如點擊頁面中的菜單或者按鈕改變URL的hash值,根據(jù)hash值的變化來控制組件的切換)
核心實現(xiàn)依靠一個事件,即監(jiān)聽hash值變化的事件

window.onhashchange = function(){
    //location.hash可以獲取到最新的hash值
    location.hash
}

前端路由實現(xiàn)tab欄切換:

<!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>
    <!-- 導(dǎo)入 vue 文件 -->
    <script src="./lib/vue_2.5.22.js"></script>
</head>
<body>
    <!-- 被 vue 實例控制的 div 區(qū)域 -->
    <div id="app">
        <!-- 切換組件的超鏈接 -->
        <a href="#/zhuye">主頁</a> 
        <a href="#/keji">科技</a> 
        <a href="#/caijing">財經(jīng)</a>
        <a href="#/yule">娛樂</a>

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

    <script>
        // #region 定義需要被切換的 4 個組件
        // 主頁組件
        const zhuye = {
            template: '<h1>主頁信息</h1>'
        }
        // 科技組件
        const keji = {
            template: '<h1>科技信息</h1>'
        }
        // 財經(jīng)組件
        const caijing = {
            template: '<h1>財經(jīng)信息</h1>'
        }
        // 娛樂組件
        const yule = {
            template: '<h1>娛樂信息</h1>'
        }
        // #endregion

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

        // 監(jiān)聽 window 的 onhashchange 事件,根據(jù)獲取到的最新的 hash 值,切換要顯示的組件的名稱
        window.onhashchange = function() {
            // 通過 location.hash 獲取到最新的 hash 值
            console.log(location.hash); // #/zhuye
            vm.comName = location.hash.slice(2)
        }
    </script>
</body>
</html>

案例效果圖:

點擊每個超鏈接之后,會進行相應(yīng)的內(nèi)容切換,如下:

核心思路:
在頁面中有一個vue實例對象,vue實例對象中有四個組件,分別是tab欄切換需要顯示的組件內(nèi)容
在頁面中有四個超鏈接,如下:

<a href="#/zhuye">主頁</a> 
<a href="#/keji">科技</a> 
<a href="#/caijing">財經(jīng)</a>
<a href="#/yule">娛樂</a>

當我們點擊這些超鏈接的時候,就會改變url地址中的hash值,當hash值被改變時,就會觸發(fā)onhashchange事件,然后得到當前hash值,根據(jù)這個hash值來讓不同的組件進行顯示。

三、Vue Router簡介

它是一個Vue.js官方提供的路由管理器。是一個功能更加強大的前端路由器,推薦使用。
Vue Router和Vue.js的核心深度集成,因此非常契合,可以一起方便的實現(xiàn)SPA單頁應(yīng)用程序的開發(fā)。
Vue Router依賴于Vue,所以需要先引入Vue,再引入Vue Router

Vue Router的特性:

  • 支持H5歷史模式或者hash模式
  • 支持嵌套路由
  • 支持路由參數(shù)
  • 支持編程式路由
  • 支持命名路由
  • 支持路由導(dǎo)航守衛(wèi)
  • 支持路由過渡動畫特效
  • 支持路由懶加載
  • 支持路由滾動行為

四、Vue Router的使用步驟(★★★)

A. 導(dǎo)入js文件
<script src="lib/vue_2.5.22.js"></script>
為全局window對象掛載VueRouter構(gòu)造函數(shù)
<script src="lib/vue-router_3.0.2.js"></script>
B. 添加路由鏈接
<router-link>是vue中提供的標簽,默認會被渲染為a標簽,
to屬性默認被渲染為href屬性,
to屬性的值會被渲染為#開頭的hash地址
<router-link to="/user">User</router-link>
<router-link to="/login">Login</router-link>
C. 添加路由填充位(路由占位符)
<router-view></router-view>
最后路由展示的組件就會在占位符的位置顯示
D. 定義路由組件
var User = { template:"<div>This is User</div>" }
var Login = { template:"<div>This is Login</div>" }
E. 配置路由規(guī)則并創(chuàng)建路由實例

var myRouter = new VueRouter({
    //routes是路由規(guī)則數(shù)組
    routes:[
        //每一個路由規(guī)則都是一個對象,對象中至少包含path和component兩個屬性
        //path表示  路由匹配的hash地址,component表示路由規(guī)則對應(yīng)要展示的組件對象
        {path:"/user",component:User},
        {path:"/login",component:Login}
    ]
})

F. 將路由掛載到Vue實例中

new Vue({
    el:"#app",
    //通過router屬性掛載路由對象
    router:myRouter
})

補充
路由重定向:可以通過路由重定向為頁面設(shè)置默認展示的組件
在路由規(guī)則中添加一條路由規(guī)則即可,如下:

var myRouter = new VueRouter({
    //routes是路由規(guī)則數(shù)組
    routes: [
        //path設(shè)置為/表示頁面最初始的地址 / ,redirect表示要被重定向的新地址,設(shè)置為一個路由即可
        { path:"/", redirect:"/user"},
        { path: "/user", component: User },
        { path: "/login", component: Login }
    ]
})

五、嵌套路由,動態(tài)路由的實現(xiàn)方式

A. 嵌套路由的概念(★★★)

當我們進行路由的時候顯示的組件中還有新的子級路由鏈接以及內(nèi)容。

嵌套路由最關(guān)鍵的代碼在于理解子級路由的概念:
比如我們有一個/login的路由
那么/login下面還可以添加子級路由,如:
/login/account
/login/phone

參考代碼如下:

    var User = { template: "<div>This is User</div>" }
    //Login組件中的模板代碼里面包含了子級路由鏈接以及子級路由的占位符
    var Login = { template: `<div>
        <h1>This is Login</h1>
        <hr>
        <router-link to="/login/account">賬號密碼登錄</router-link>
        <router-link to="/login/phone">掃碼登錄</router-link>
        <!-- 子路由組件將會在router-view中顯示 -->
        <router-view></router-view>
        </div>` }

    //定義兩個子級路由組件
    var account = { template:"<div>賬號:<input><br>密碼:<input></div>"};
    var phone = { template:"<h1>掃我二維碼</h1>"};
    var myRouter = new VueRouter({
        //routes是路由規(guī)則數(shù)組
        routes: [
            { path:"/",redirect:"/user"},
            { path: "/user", component: User },
            { 
                path: "/login", 
                component: Login,
                //通過children屬性為/login添加子路由規(guī)則
                children:[
                    { path: "/login/account", component: account },
                    { path: "/login/phone", component: phone },
                ]
            }
        ]
    })

    var vm = new Vue({
        el: '#app',
        data: {},
        methods: {},
        router:myRouter
    });

頁面效果大致如下:

B. 動態(tài)路由匹配(★★★)

var User = { template:"<div>用戶:{{$route.params.id}}</div>"}

var myRouter = new VueRouter({
    //routes是路由規(guī)則數(shù)組
    routes: [
        //通過 /:參數(shù)名  的形式傳遞參數(shù) 
        { path: "/user/:id", component: User },     
    ]
})

可以在路由對應(yīng)的組件中使用$route.params.id來獲取路徑傳參的id參數(shù)值,但是這種方式不夠靈活。今后可以盡量使用props將組件和路由解耦。

  1. 通過props來接收參數(shù)
var User = { 
    props:["id"], //使用props接收id參數(shù)
    template:"<div>用戶:{{id}}</div>"
}

var myRouter = new VueRouter({
    //routes是路由規(guī)則數(shù)組
    routes: [
        //通過/:參數(shù)名  的形式傳遞參數(shù) 
        //如果props設(shè)置為true,route.params將會被設(shè)置為組件屬性
        { path: "/user/:id", component: User, props:true },
        
    ]
})
  1. 還有一種情況,我們可以將props設(shè)置為對象,直接將靜態(tài)數(shù)據(jù)傳遞給組件進行使用。
    但是這樣id的值就訪問不到了。
var User = { 
    props:["username","pwd"],
    template:"<div>用戶:{{username}}---{{pwd}}</div>"
    }

var myRouter = new VueRouter({
    //routes是路由規(guī)則數(shù)組
    routes: [
        //通過 /:參數(shù)名  的形式傳遞參數(shù) 
        //如果props設(shè)置為對象,則傳遞的是對象中的數(shù)據(jù)給組件
        { path: "/user/:id", component: User, props:{username:"jack",pwd:123} },
        
    ]
})
  1. 如果既想要獲取路由傳遞的參數(shù)值,又想獲取傳遞的對象數(shù)據(jù),那么props應(yīng)該設(shè)置為函數(shù)形式。
var User = { 
    props:["username","pwd","id"],
    template:"<div>用戶:{{id}} -> {{username}}---{{pwd}}</div>"
    }

var myRouter = new VueRouter({
    //routes是路由規(guī)則數(shù)組
    routes: [
        //通過 /:參數(shù)名  的形式傳遞參數(shù) 
        //如果props設(shè)置為函數(shù),則通過函數(shù)的第一個參數(shù)獲取路由對象
        //并可以通過路由對象的params屬性獲取傳遞的參數(shù)
        //
        { path: "/user/:id", component: User,props:(route)=>{
            return {username:"jack",pwd:123,id:route.params.id}
            } 
        },
        
    ]
})

六、命名路由以及編程式導(dǎo)航

A. 命名路由:用name屬性值給路由取別名

案例:

var myRouter = new VueRouter({
    //routes是路由規(guī)則數(shù)組
    routes: [
        //通過name屬性為路由添加一個別名
        { path: "/user/:id", component: User, name:"user"},        
    ]
})

添加了別名之后,可以使用別名進行跳轉(zhuǎn)(給to屬性綁定對象的形式)
<router-link to="/user/123">User</router-link>
等價于
<router-link :to="{ name:'user' , params: {id:123} }">User</router-link>

還可以編程式導(dǎo)航
myRouter.push( { name:'user' , params: {id:123} } )

B. 編程式導(dǎo)航(★★★)

頁面導(dǎo)航的兩種方式:
A. 聲明式導(dǎo)航:通過點擊鏈接的方式實現(xiàn)的導(dǎo)航
B. 編程式導(dǎo)航:調(diào)用js的api方法實現(xiàn)導(dǎo)航,比如調(diào)用location.href就是

Vue-Router中常見的導(dǎo)航方式:
this.$router.push("hash地址");
this.$router.push("/login");
this.$router.push({ name:'user' , params: {id:123} });
this.$router.push({ path:"/login" });
this.$router.push({ path:"/login",query:{username:"jack"} });

this.$router.go(n); n為數(shù)字,參考history.go
this.$router.go(-1);

七、實現(xiàn)后臺管理案例(★★★)

案例效果:

點擊左側(cè)的"用戶管理","權(quán)限管理","商品管理","訂單管理","系統(tǒng)設(shè)置"都會出現(xiàn)對應(yīng)的組件并展示內(nèi)容

其中"用戶管理"組件展示的效果如上圖所示,在用戶管理區(qū)域中的詳情鏈接也是可以點擊的,點擊之后將會顯示用戶詳情信息。

案例思路:
1).先將素材文件夾中的11.基于vue-router的案例.html復(fù)制到我們自己的文件夾中。
看一下這個文件中的代碼編寫了一些什么內(nèi)容,
這個頁面已經(jīng)把后臺管理頁面的基本布局實現(xiàn)了
2).在頁面中引入vue,vue-router
3).創(chuàng)建Vue實例對象,準備開始編寫代碼實現(xiàn)功能
4).希望是通過組件的形式展示頁面的主體內(nèi)容,而不是寫死頁面結(jié)構(gòu),所以我們可以定義一個根組件:

//只需要把原本頁面中的html代碼設(shè)置為組件中的模板內(nèi)容即可
const app = {
    template:`<div>
        <!-- 頭部區(qū)域 -->
        <header class="header">傳智后臺管理系統(tǒng)</header>
        <!-- 中間主體區(qū)域 -->
        <div class="main">
          <!-- 左側(cè)菜單欄 -->
          <div class="content left">
            <ul>
              <li>用戶管理</li>
              <li>權(quán)限管理</li>
              <li>商品管理</li>
              <li>訂單管理</li>
              <li>系統(tǒng)設(shè)置</li>
            </ul>
          </div>
          <!-- 右側(cè)內(nèi)容區(qū)域 -->
          <div class="content right">
            <div class="main-content">添加用戶表單</div>
          </div>
        </div>
        <!-- 尾部區(qū)域 -->
        <footer class="footer">版權(quán)信息</footer>
      </div>`
  }

5).當我們訪問頁面的時候,默認需要展示剛剛創(chuàng)建的app根組件,我們可以
創(chuàng)建一個路由對象來完成這個事情,然后將路由掛載到Vue實例對象中即可

const myRouter = new VueRouter({
    routes:[
        {path:"/",component:app}
    ]
})

const vm = new Vue({
    el:"#app",
    data:{},
    methods:{},
    router:myRouter
})

補充:到此為止,基本的js代碼都處理完畢了,我們還需要設(shè)置一個路由占位符

<body>
  <div id="app">
    <router-view></router-view>
  </div>
</body>

6).此時我們打開頁面應(yīng)該就可以得到一個VueRouter路由出來的根組件了
我們需要在這個根組件中繼續(xù)路由實現(xiàn)其他的功能子組件
先讓我們更改根組件中的模板:更改左側(cè)li為子級路由鏈接,并在右側(cè)內(nèi)容區(qū)域添加子級組件占位符

const app = {
    template:`<div>
        ........
        <div class="main">
          <!-- 左側(cè)菜單欄 -->
          <div class="content left">
            <ul>
              <!-- 注意:我們把所有l(wèi)i都修改為了路由鏈接 -->
              <li><router-link to="/users">用戶管理</router-link></li>
              <li><router-link to="/accesses">權(quán)限管理</router-link></li>
              <li><router-link to="/goods">商品管理</router-link></li>
              <li><router-link to="/orders">訂單管理</router-link></li>
              <li><router-link to="/systems">系統(tǒng)設(shè)置</router-link></li>
            </ul>
          </div>
          <!-- 右側(cè)內(nèi)容區(qū)域 -->
          <div class="content right">
            <div class="main-content">
                <!-- 在 -->
                <router-view></router-view> 
            </div>
          </div>
        </div>
        .......
      </div>`
  }

然后,我們要為子級路由創(chuàng)建并設(shè)置需要顯示的子級組件

//建議創(chuàng)建的組件首字母大寫,和其他內(nèi)容區(qū)分
const Users = {template:`<div>
    <h3>用戶管理</h3>
</div>`}
const Access = {template:`<div>
    <h3>權(quán)限管理</h3>
</div>`}
const Goods = {template:`<div>
    <h3>商品管理</h3>
</div>`}
const Orders = {template:`<div>
    <h3>訂單管理</h3>
</div>`}
const Systems = {template:`<div>
    <h3>系統(tǒng)管理</h3>
</div>`}

//添加子組件的路由規(guī)則
const myRouter = new VueRouter({
    routes:[
        {path:"/",component:app , children:[
            { path:"/users",component:Users },
            { path:"/accesses",component:Access },
            { path:"/goods",component:Goods },
            { path:"/orders",component:Orders },
            { path:"/systems",component:Systems },
        ]}
    ]
})

const vm = new Vue({
    el:"#app",
    data:{},
    methods:{},
    router:myRouter
})

7).展示用戶信息列表:
A.為Users組件添加私有數(shù)據(jù),并在模板中循環(huán)展示私有數(shù)據(jù)

const Users = {
    data(){
        return {
            userList:[
                {id:1,name:"zs",age:18},
                {id:2,name:"ls",age:19},
                {id:3,name:"wang",age:20},
                {id:4,name:"jack",age:21},
            ]
        }
    },
    template:`<div>
        <h3>用戶管理</h3>
        <table>
            <thead>
                <tr>
                    <th>編號</th>
                    <th>姓名</th>
                    <th>年齡</th>
                    <th>操作</th>
                </tr>
            </thead>
            <tbody>
                <tr :key="item.id" v-for="item in userList">
                    <td>{{item.id}}</td>
                    <td>{{item.name}}</td>
                    <td>{{item.age}}</td>
                    <td><a href="javascript:;">詳情</a></td>
                </tr>
            </tbody>
        </table>
    </div>`
}

8).當用戶列表展示完畢之后,我們可以點擊列表中的詳情來顯示用戶詳情信息,首先我們需要創(chuàng)建一個組件,用來展示詳情信息

const UserInfo = {
    props:["id"],
    template:`<div>
      <h5>用戶詳情</h5>
      <p>查看 {{id}} 號用戶信息</p>
      <button @click="goBack">返回用戶詳情頁</button>
    </div> `,
    methods:{
      goBack(){
        //當用戶點擊按鈕,后退一頁
        this.$router.go(-1);
      }
    }
  }

然后我們需要設(shè)置這個組件的路由規(guī)則

const myRouter = new VueRouter({
    routes:[
        {path:"/",component:app , children:[
            { path:"/users",component:Users },
            //添加一個/userinfo的路由規(guī)則
            { path:"/userinfo/:id",component:UserInfo,props:true},
            { path:"/accesses",component:Access },
            { path:"/goods",component:Goods },
            { path:"/orders",component:Orders },
            { path:"/systems",component:Systems },
        ]}
    ]
})

const vm = new Vue({
    el:"#app",
    data:{},
    methods:{},
    router:myRouter
})

再接著給用戶列表中的詳情a連接添加事件

const Users = {
    data(){
        return {
            userList:[
                {id:1,name:"zs",age:18},
                {id:2,name:"ls",age:19},
                {id:3,name:"wang",age:20},
                {id:4,name:"jack",age:21},
            ]
        }
    },
    template:`<div>
        <h3>用戶管理</h3>
        <table>
            <thead>
                <tr>
                    <th>編號</th>
                    <th>姓名</th>
                    <th>年齡</th>
                    <th>操作</th>
                </tr>
            </thead>
            <tbody>
                <tr :key="item.id" v-for="item in userList">
                    <td>{{item.id}}</td>
                    <td>{{item.name}}</td>
                    <td>{{item.age}}</td>
                    <td><a href="javascript:;" @click="goDetail(item.id)">詳情</a></td>
                </tr>
            </tbody>
        </table>
    </div>`,
    methods:{
        goDetail(id){
            this.$router.push("/userinfo/"+id);
        }
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容