vue基礎八(路由組件)


vue-router

    是什么
        是vue官方的一個插件
        專門用來實現一個SPA應用
        基於vue的項目基本都會用到此庫

        vuex  vue-router  這兩個插件應用很廣泛
單頁Web應用(single page web application,SPA)
        整個應用只有一個完整的頁面(這個完整的頁面,由多個組件組成)

        點擊頁面中的鏈接不會刷新頁面, 本身也不會向服務器發請求

        當點擊路由鏈接時, 只會做頁面的局部更新(組件切換)

        數據都需要通過ajax請求獲取, 並在前端異步展現
路由
        是一個key:value的映射關系

        前台路由   路徑 和 要顯示的組件
        {

            path:'/home',
            component:Home

        }
        當點擊鏈接的時候,路徑會發生變化,但是不會向服務器發請求,而是去顯示對應的組件
后台路由   路徑 和 匹配的函數

        app.get('/users/info',function(){})

        當點擊鏈接的時候,路徑會發生變化,而且會向服務器發請求,然后匹配到后端的一個函數處理這個路由的請求,返回需要的
        數據
簡單理解前台路由:路由可以讓我們實現組件的切換和跳轉:
            點擊鏈接,匹配路由,顯示對應的組件
路由組件和非路由組件
            
            //宏觀上去看 如果一個組件是點擊鏈接之后才會出現的,那么就一定和路由相關,就被路由組件

            //一個組件是在路由器中的路由中注冊的,就是路由組件
            //一個組件不是在路由中注冊的就叫非路由組件

 

 

案例實現

1.安裝router, npm install vue-router

2.新建文件夾router,文件,新建index.js, 引入vue, router, 

import Vue from "vue";
import Vuerouter from "vue-router";
//使用插件
Vue.use(Vuerouter);

暴露路由

// 暴露路由
export default Vuerouter({});

3.在入口文件main.js中,引入路由,注冊路由

import router from '@/router'

Vue.config.productionTip = false

new Vue({
  el:'#root',
  render: h => h(App),
  router
  //注冊路由器,注冊之后 
  //每個路由組件內部都可以通過this.$router拿到路由器對象
  //每個路由組件內部都可以通過this.$route拿到當前的路由對象
})

 

4,在router中引入路由組件,並且配置路由對象

// 引入路由組件
import About from '@/pages/About'
import Home from '@/pages/Home'
// 暴露路由
export default new Vuerouter({

 routes:[
    {
      path:'/home',
      component:Home
    },

    {
      path:'/about',
      component:About

    },

    { //重定向 path:'/', redirect:'/home'

    }
  ]
});

 

在父組件中設置路由連接

<ul class="nav nav-stacked col-md-6" role="tablist">
          <li role="presentation" class="active">
            <router-link to="/home" aria-controls="home" role="tab" data-toggle="tab">Home</router-link>
            <!-- <a href="#home" aria-controls="home" role="tab" data-toggle="tab">Home</a> -->
          </li>
          <li role="presentation">
            <router-link to="/about" aria-controls="About" role="tab" data-toggle="tab">About</router-link>
            <!-- <a href="#About" aria-controls="About" role="tab" data-toggle="tab">About</a> -->
          </li>
        </ul>
<div class="tab-content col-md-6">
          <keep-alive include="Home">
            <router-view></router-view>
          </keep-alive>
        </div>

 

5.給點擊的路由連接設置樣式,.router-link-active點擊a標簽,會自動有這個類

.router-link-active{
      color: red !important;
    }

 

 

 

6.設置二級路由

在router的文件中,引入組件,配置二級路由對象

import Message  from '@/pages/Message'
import News  from '@/pages/News'

// 暴露路由
export default new Vuerouter({

  routes:[
    {
      path:'/home',
      component:Home,
    children:[
        {
          // path:'/home/message',子路由組件,可以省略
      path:'message', //簡寫
          component:Message
        },

        {
          path:'news',  //簡寫
          component:News
        },

        {
         path:'', //默認代表/home路徑,重定向 redirect:'message' //可以簡寫成路徑,默認跳轉到message路徑
        }
      ]
    },

 

 

7.設置三級路由

export default new Vuerouter({
  routes: [
    {
      path: "/home",
      component: Home,
      children: [
        {
          // path:'/home/message',子路由組件,可以省略
          path: "message", //簡寫
          component: Message, children: [
            {
              path: "msgdtil",
              component: MsgDtil,
            },
          ],
        },

 

設置路由連接

<div role="tabpanel" class="tab-pane active" id="Message">
    <ul class="list-group">
      <li class="list-group-item" v-for="(message, index) in messages" :key="message.id">
        <router-link to="/home/message/msgdtil"  >{{message.content}}</router-link>
        <!-- <a href="##">message01</a> -->
      </li>
    
    </ul>
    <div class="alert alert-success" role="alert">
        <!-- 設置路由組件 -->
        <router-view></router-view>
    </div>
  </div>

 

 

八,原始路由傳參,params和query參數

最原始的傳參
                參數:params參數和路徑一樣       /message/10
                      query參數路徑后使用?去拼接起來的    /xxx/  ? aa = bb && xx = yy  
<router-link :to="`/home/message/msgdetail/${m.id}?msgcontent=${m.content}`">{{m.content}}</router-link>

此時params參數,需要在改路由對象中設置鍵

 {
              path: "msgdtil/:mid",
              component: MsgDtil,
            },

 

路由組件中接收參數

  <li class="list-group-item">messageID:{{$route.params.mid}}</li>
    <li class="list-group-item">message:{{$route.query.msgcontent}}</li>

 

九, 路由傳參,props簡化傳遞

如果路由組件不需要這么麻煩接收參數{{$route.params.mid}},  那么可以通過在路由對象中配置props來簡化接收參數

使用props簡化路由傳參給子組件操作(路由當中傳參的三種操作)
                1)布爾值  
                路由當中需要配置 props:true,只能接收params參數,它會把路由當中接收的參數,置為子組件的屬性     
                2)對象
                很少用,只能給子組件傳遞默認靜態值
                3)函數
                用的比較多,比較靈活,可以把params和query的參數都映射為子組件的屬性
                props(route){ //route就是當前我這個路由對象
                                    //把路由對象當中的參數,不管什么參數
                                    //全部拿到作為子組件的屬性去使用
                                    return {
                                            msgId:route.params.msgId,
                                            msgContent:route.query.msgContent
                                    }
                                }

 

在路由對象中配置props

 {
              path:'msgdetail/:mid',
              component:MsgDetail,
              // props:true  //代表只是針對params參數,屬性傳遞給相應的路由組件對象
              // props:{username:'趙麗穎'} //props可以是一個對象,對象內部的數據是要傳遞給路由組件的靜態數據
              // props(route){
              //   //把路徑傳參傳遞過來的params參數和query參數,都取出來,自己封裝為一個對象
              //   //好讓props可以進行屬性傳遞
              //   return {mid:route.params.mid,msgcontent:route.query.msgcontent}
              // },
          //箭頭函數寫法 props: route => ({mid:route.params.mid,msgcontent:route.query.msgcontent}), name:'msgdetail' }

 

路由組件中接收參數
在組件中需要設置下props
export default {
  name: "MsgDetail",
 props: ["mid", "msgcontent"],
  data() {
    return {
      title: ""
    };
  },
在模板中填充參數
 <!-- <li class="list-group-item">messageID:{{$route.params.mid}}</li> -->
    <li class="list-group-item">messageID:{{mid}}</li>
    <!-- <li class="list-group-item">message:{{$route.query.msgcontent}}</li> -->
    <li class="list-group-item">message:{{msgcontent}}</li>

 

十,命名路由寫法,對象形式

路由鏈接組件中給路由傳參可以寫成對象形式,前提需要給路由起名字name,也叫命名路由

在路由對象中命名該路由

 {
              path:'msgdetail/:mid',
              component:MsgDetail,
              // props:true  //代表只是針對params參數,屬性傳遞給相應的路由組件對象
              // props:{username:'趙麗穎'} //props可以是一個對象,對象內部的數據是要傳遞給路由組件的靜態數據
              // props(route){
              //   //把路徑傳參傳遞過來的params參數和query參數,都取出來,自己封裝為一個對象
              //   //好讓props可以進行屬性傳遞
              //   return {mid:route.params.mid,msgcontent:route.query.msgcontent}
              // },
              props: route => ({mid:route.params.mid,msgcontent:route.query.msgcontent}),
             name:'msgdetail'

            }

 

路由連接命名寫法

 <!-- 原始字符串路徑寫法 -->
        <!-- <router-link :to="`/home/message/msgdetail/${m.id}?msgcontent=${m.content}`">{{m.content}}</router-link> -->
        <!-- 對象寫法 -->
        <router-link :to="{name:'msgdetail',params:{mid:m.id},query:{msgcontent:m.content}}">{{m.content}}</router-link>

 

對於路由傳參的id和組件自定義的id去匹配,獲取title,填充模板數據
<template>
  <ul class="list-group">
    <!-- <li class="list-group-item">messageID:{{$route.params.mid}}</li> -->
    <li class="list-group-item">messageID:{{mid}}</li>
    <!-- <li class="list-group-item">message:{{$route.query.msgcontent}}</li> -->
    <li class="list-group-item">message:{{msgcontent}}</li>
    <li class="list-group-item">{{title}}</li>
   
  </ul>
</template>

<script> const titleArr = [ { id: 1, title: "msg01" }, { id: 2, title: "msg02" }, { id: 3, title: "msg03" } ];
export default {
  //關於路由組件銷毀的問題,因為多個路由連接,跳轉的都是同一個組件,
  //路由傳參的id和組件自定義的id去匹配,獲取title,填充模板數據

  name:'MsgDtil',
  //路由傳參,props傳遞
  props:['mid', 'msgcontent'],
  data() {
    return {
     title:''
    };
  },

  mounted(){
    //路由傳參過來的數字,自動變成了字符竄形式
    console.log(typeof(this.mid))  // string
    this.title= titleArr.find(item =>item.id === this.mid*1).title
  }
};
</script>

<style scoped ></style>

 

效果圖

 

 

數據一直沒有變化,因為多個路由連接都是跳轉同一個路由組件,路由組件的生命周期一直存在,沒有銷毀,所以mounted加載后,新數據不會渲染

 此時需要解決該bug,因為路由對象的params和query參數是不斷變化的,此時我們需要監視路由對象$route, 只要路由對象的參數發生變化,就可以重新更新數據

<template>
  <ul class="list-group">
    <!-- <li class="list-group-item">messageID:{{$route.params.mid}}</li> -->
    <li class="list-group-item">messageID:{{mid}}</li>
    <!-- <li class="list-group-item">message:{{$route.query.msgcontent}}</li> -->
    <li class="list-group-item">message:{{msgcontent}}</li>
    <li class="list-group-item">{{title}}</li>
   
  </ul>
</template>

<script>

const titleArr = [
  { id: 1, title: "msg01" },
  { id: 2, title: "msg02" },
  { id: 3, title: "msg03" }
];
export default {
  //關於路由組件銷毀的問題,因為多個路由連接,跳轉的都是同一個組件,
  //路由傳參的id和組件自定義的id去匹配,獲取title,填充模板數據

  name:'MsgDtil',
  //路由傳參,props傳遞
  props:['mid', 'msgcontent'],
  data() {
    return {
      title:''
    };
  },

  mounted(){
    //路由傳參過來的數字,自動變成了字符竄形式
    console.log(typeof(this.mid))  // string
    this.changeTitle()
  },

  //監視路由變化
 watch:{ $route(newRoute, oldRoute){ this.changeTitle() } },

  methods:{
    changeTitle(){
      this.title= titleArr.find(item =>item.id ===this.mid*1 ).title
    }
  }


};
</script>

<style scoped ></style>

 

路由組件和非路由組件的最大區別
            路由組件的生命周期是點擊鏈接的時候,才開始的,路由組件才會創建,mounted才能執行
            路由組件在切換的時候,會被銷毀,顯示的時候重新創建
            同一個路由組件傳參顯示不同數據,mounted回調只會執行一次,因為是一個組件

 

 

十一,緩存路由組件

使用的是vue的一個組件,參考vue的官方文檔
        使用這個東西可以保證我們在切換組件的時候,原來顯示的組件不被銷毀。數據不會銷毀 <keep-alive include="Home">   Home是對應的組件對象的名字,不是路由的名字
                    <router-view></router-view>
              </keep-alive>

 

十二,編程式路由導航

定義一個事件,函數

<ul class="list-group">
      <li class="list-group-item" v-for="(n, index) in news" :key="n.id">
        {{n.content}}
        <button
          type="button"
          class="btn btn-primary"
          data-toggle="button"
          aria-pressed="false"
          autocomplete="off" @click="changeLr(n)"
        > {{ n.id }}</button>
      </li>
    
    </ul>

 

 methods: {
    // handlerBack(){
    //   this.$router.back()
    // },

    toNewsDetail(n) {
      //編程式導航(路由)
      // this.$router.push(`/home/news/newsdetail/${n.id}?newscontent=${n.content}`)//就是實現路由鏈接的效果
      //對象形式
      const location = {
        name: "newsdetail",
        params: { nid: n.id },
        query: { newscontent: n.content },
      };

    // this.$router.push(location); //就是實現路由鏈接的效果 
      this.$router.replace(location);
    },
  },

 

1)this.$router.push(path): 相當於點擊路由鏈接(可以返回到當前路由界面)
2) this.$router.replace(path): 用新路由替換當前路由(不可以返回到當前路由界面)
3) this.$router.back(): 請求(返回)上一個記錄路由

 

$router.push()和$router.replace()的區別,返回有區別。
$router.push()是往歷史記錄里面追加
$router.replace()每一次都是覆蓋添加

 <button @click="$router.back()">返回</button>

 

路由模式hash和history之間的區別

解決history路由404

        hash模式:
                路徑中帶#: http://localhost:8080/#/home/news
                發請求的路徑: http://localhost:8080  項目根路徑,將域和路由路徑用#隔開,
                響應: 返回的總是index頁面  ==> path部分(/home/news)被解析為前台路由路徑

        history模式:
                路徑中不帶#: http://localhost:8080/home/news
                發請求的路徑: http://localhost:8080/home/news
                響應: 404錯誤,被當做后台路由,去找資源,顯然8080端口是沒有該資源的
                希望: 如果沒有對應的資源, 返回index頁面, path部分(/home/news)被解析為前台路由路徑

 在路由對象中配置路由模式

export default new VueRouter({
 mode:'history',
  ///home/message/msgdetail/1
  routes:[
    {
      path:'/home',
      component:Home,

 

解決history模式404的方式

解決: 添加配置
                    devServer添加: historyApiFallback: true, // 任意的 404 響應都被替代為 index.html
                    output添加: publicPath: '/', // 引入打包的文件時路徑以/開頭

在webpack配置文件配置

//3. 增加 devServer 配置
   devServer: {
    historyApiFallback: true, // 任意的 404 響應都被替代為 index.html
    open: true,     // 自動打開瀏覽器
    compress: true, // 啟動gzip壓縮
    port: 3000,     // 端口號
    quiet:true,
// 輸出配置
  output: {         
    // 輸出文件名
    filename: 'built.js',    
    //輸出文件路徑配置
    path: path.resolve(__dirname, 'dist'),  
    //1. 添加 devServer 服務后需要調整輸出的路徑
  publicPath: '/' 

此時在index.html引入的css不能是相對路徑了, 

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <!-- <link rel="stylesheet" href="./css/bootstrap.css"> -->
  <link rel="stylesheet" href="/css/bootstrap.css">
  <style>
    .list-group-item {
        position: relative;
    }

    .btn {
        width: 80px;
        height: 30px;
        position: absolute;
        right: 0;
        bottom: 5px;
    }
    .router-link-active{
      color: red !important;
    }
</style>
</head>

<body>
  <div id="root"></div>
</body>

</html>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM