VUE開發(fā)--路由Vue-router(十七)

一、vue路由

vue路由:vue-router
??vue-router是Vue.js官方的路由插件,它和vue.js是深度集成的,適合用于構建單頁面應用。vue的單頁面應用是基于路由和組件的,路由用于設定訪問路徑,并將路徑和組件映射起來。傳統(tǒng)的頁面應用,是用一些超鏈接來實現(xiàn)頁面切換和跳轉的。在vue-router單頁面應用中,則是路徑之間的切換,也就是組件的切換。
https://router.vuejs.org/zh/installation.html

安裝:

D:\vue-project>npm install vue-router

單頁面應用有兩個路徑:/home和/about,與這兩個路徑對應的是兩個組件Home和About。


路由

二、創(chuàng)建路由

  1. 引入路由
//導入路由
import Router from 'vue-router'
 //使用/注冊
Vue.use(Router)
  1. 創(chuàng)建路由對象
//創(chuàng)建路由對象
export default new Router({
  routes: [
    {
      path: '/',
      name: 'HelloWorld',
      component: HelloWorld
    }
  ]
})
  1. 創(chuàng)建組件,并配置路由

創(chuàng)建Home組件:

//Home.vue
<template>
  <div class="container">
    <h2>Home</h2>
  </div>
</template>
<script>
export default {
  name: 'Home'
}
</script>
<style scoped>

</style>

// router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/components/Home'

Vue.use(Router)
//創(chuàng)建路由對象
export default new Router({
  routes: [
    {
      path: '/Home',
      name: 'Home',
      component: Home
    }
  ]
})

注: @指向src目錄

  1. 路由切換 router-link
 <!-- <router-link> 默認會被渲染成一個 `<a>` 標簽 -->
  <router-link to="/Home">Home</router-link>

 <router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>
  1. router-view
    主要是構建 SPA (單頁應用) 時,方便渲染你指定路由對應的組件??梢?router-view 當做是一個容器,它渲染的組件是你使用 vue-router 指定的。
//app.vue
<template>
  <div id="app">
    <!--渲染路由顯示-->
    <router-view/>
  </div>
</template>

<script>
export default {
  name: 'App'
}
</script>
  1. 動態(tài)路由匹配
    我們經(jīng)常需要把某種模式匹配到的所有路由,全都映射到同個組件。例如,我們有一個 User 組件,對于所有 ID 各不相同的用戶,都要使用這個組件來渲染。那么,我們可以在 vue-router 的路由路徑中使用“動態(tài)路徑參數(shù)”(dynamic segment) 來達到這個效果:
 routes: [
    // 動態(tài)路徑參數(shù) 以冒號開頭
    { path: '/user/:id', component: User }
  ]

一個“路徑參數(shù)”使用冒號 : 標記。當匹配到一個路由時,參數(shù)值會被設置到 this.$route.params,可以在每個組件內(nèi)使用。于是,我們可以更新 User 的模板,輸出當前用戶的 ID:

# $route一定不要加this。
{{ $route.params.id }}

<template>
  <div id="container">
    <div v-if="'menu'===$route.params.id">
            菜單管理
    </div>
    <div v-if="'user'===$route.params.id">
           用戶管理
    </div>
  </div>
</template>
<script>
export default {};
</script>
<style scoped>
</style>
參數(shù)傳遞

顯示菜單

可以在一個路由中設置多段“路徑參數(shù)”,對應的值都會設置到 $route.params 中。例如:

模式 匹配路徑 $route.params
/user/:username /user/evan { username: 'evan' }
/user/:username/post/:post_id /user/evan/post/123 { username: 'evan', post_id: '123' }

除了$route.params 外,$route 對象還提供了其它有用的信息,例如,$route.query (如果 URL 中有查詢參數(shù))、$route.hash 等等。

三、嵌套路由

實際應用界面,通常由多層嵌套的組件組合而成。
比如,我們 “首頁”組件中,還嵌套著 “登錄”和 “注冊”組件,那么URL對應就是/home/login和/home/reg。

<template id="home">
        <!-- 注意:組件只能有一個根元素,所以我們包裝到這個div中 -->
        <div>
            <h2>首頁</h2>
             <router-link to="/home/login">登錄</router-link>
            <router-link to="/home/reg">注冊</router-link>
            <!-- 路由匹配到的組件將渲染在這里 -->
            <router-view></router-view>
        </div>
    </template>

模板

新聞
 <template id="news">
        <div>新聞</div>
    </template>
登錄
    <template id="login">
        <div>登錄界面</div>
    </template>
注冊
    <template id="reg">
        <div>注冊界面</div>
    </template>

定義路由

  // 2. 定義路由
        const routes = [
            //重定向
             { path: '/', redirect: '/home' },
            { 
                path: '/home', 
                component: Home, 
                children:[
                    { path: 'login', component: Login},
                    { path: 'reg', component: Reg}
                ]
            },
            { path: '/news', component: News}
        ]

四、重定向

    { path: '/', redirect: '/home' },

五、路由高亮

在index.js 中, 添加 路由選中class名
默認是 router-link-active, 更改
active-class是vue-router模塊的router-link組件中的屬性,用來做選中樣式的切換;
https://router.vuejs.org/zh/api/#active-class

  1. 組件:Home.vue
<template>
  <div class="container">
    <ul>
        <li><router-link to="/" exact>首頁</router-link></li>
        <li><router-link to="/List">列表</router-link></li>
        <li><router-link to="/About">關于我們</router-link></li>
    </ul>
   <br>
  <router-view/>
  </div>
</template>
  1. 路由:index.js
Vue.use(Router)
//創(chuàng)建路由對象
export default new Router({
  mode: 'history',  // 去掉路由地址的#
  linkActiveClass: "active",
  // linkExactActiveClass:"active",
  routes: [
    {
      path: '/',
      name: 'Home',
      component: Home,
      children:[
        {
          path: '/List',
          name: 'List',
          component: List
        },
        {
          path: '/About',
          name: 'About',
          component: About
        }
      ]
    }]
})
  1. 在全局中配置, css 樣式:
 .active {
    color: red
  }

對于匹配 / 的, 會始終顯示高亮, 需要添加 exact 屬性;

 <li><router-link :to="index" exact>首頁</router-link></li>
激活選中

六、參數(shù)傳遞

(一) 在 router-link 中, 使用 :to={} 的形式進行傳遞參數(shù)

#使用對象傳參
<li><router-link :to="{ name: 'Master', params:{count: 100, obj: user}}">用戶列表</router-link></li>
<script>
export default {
  data() {
    return { user: {name:"張三",age:20} };
  }
};
</script>

在 master 頁面, 接受參數(shù)

<template>
    <div>
      用戶: {{ $route.params.count }} - {{ $route.params.obj.name }}
    </div>
</template>
<script>
    export default {
    }
</script>
<style scoped>
</style>

(二)this.$route.query和this.$route.params的使用與區(qū)別

1. this.$route.query

1)路由 index.js
Vue.use(Router)
//創(chuàng)建路由對象
export default new Router({
  routes: [
    {
      path: '/',
      name: 'Home',
      component: Home,
      children: [
        {
          path: '/List',
          name: 'List',
          component: List
        },
        {
          path: '/About',
          name: 'About',
          component: About
        }
      ]
    }, {
      path: '/ListTest',
      name: 'ListTest',
      component: List
    }
  ]}
)
2) 聲明式導航傳參
<template>
  <div class="container">
    <div class="top">
      <ul>
        <!-- 標簽式傳參 -->
        <li>
          <router-link :to="{name:'List',params: { name: '張三',age: 20},query: { queryId: 1 }}">列表</router-link>
        </li>
      </ul>
    </div>
    <div class="buttom">
      <router-view/>
    </div>
  </div>
</template>
<style scoped>
.buttom{
 clear: both;
}
ul {
  list-style: none;
}
li {
  float: left;
  margin: 20px;
}
</style>
3) 編程式導航:
<template>
  <div class="container">
    <!--編程式導航-->
    <button @click="urlLink">關于我們</button>
  </div>
</template>
<script>
export default {
  name: "Home",
  data() {
    return { item: { id: 1, name: "西瓜" } };
  },
  methods: {
    urlLink() {
       //編程跳轉寫在一個函數(shù)里面,通過click等方法來觸發(fā)
      this.$router.push("/ListTest");
    }
  }
};
</script>

4) 編程式導航傳參:

<template>
  <div class="container">
    <!--編程式導航-->
    <button @click="urlLink">關于我們</button>
  </div>
</template>
<script>
export default {
  name: "Home",
  data() {
    return { item: { id: 1, name: "西瓜" } };
  },
  methods: {
    urlLink() {
    this.$router.push({ name:'ListTest',params: { name: '張三',age: 20},query: { queryId: 1}});
    }
  }
};
</script>
3) 獲取參數(shù)

組件:List.vue

<template>
  <div class="container">
    列表
    <!-- 注意:$route 就route不要寫錯 -->
    {{ $route.params.name }}<br>
    {{$route.query.queryId}}
  </div>
</template>
4) url的表現(xiàn)形式(url中帶有參數(shù))
http://localhost:8080/ListTest?queryId=1

2. params傳參和query傳參有什么區(qū)別?

1、用法上的
剛query要用path來引入,params要用name來引入,接收參數(shù)都是類似的,分別是this.route.query.name和this.route.params.name。
注意接收參數(shù)的時候,已經(jīng)是route而不是router。
2、展示上的
query更加類似于我們ajax中get傳參,params則類似于post,說的再簡單一點,前者在瀏覽器地址欄中顯示參數(shù),后者則不顯示。
3、params是路由的一部分,必須要有。query是拼接在url后面的參數(shù),沒有也沒關系。
params一旦設置在路由,params就是路由的一部分,如果這個路由有params傳參,但是在跳轉的時候沒有傳這個參數(shù),會導致跳轉失敗或者頁面會沒有內(nèi)容。
比如:跳轉/router1/:id

<router-link :to="{ name:'router1',params: { id: status}}" >正確</router-link>
<router-link :to="{ name:'router1',params: { id2: status}}">錯誤</router-link>

七、多視圖(命名視圖)

https://router.vuejs.org/zh/guide/essentials/named-views.html
有時候想同時 (同級) 展示多個視圖,而不是嵌套展示,例如創(chuàng)建一個布局,有 sidebar (側導航) 和 main (主內(nèi)容) 兩個視圖,這個時候命名視圖就派上用場了。你可以在界面中擁有多個單獨命名的視圖,而不是只有一個單獨的出口。如果 router-view 沒有設置名字,那么默認為 default。

  1. app.vue
<template>
  <div id="app">
    <router-view class="top" name="top"/>
    <router-view class="left" name="left"/>
    <router-view class="main"/>
  </div>
</template>

<script>
export default {
  name: "App"
};
</script>

<style>
#app {
  font-family: "Avenir", Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
  margin: auto;
}
.active {
  color: red;
}
.top {
  height: 160px;
  background-color: blueviolet;
}
.left {
  float: left;
  width: 200px;
  background-color: chartreuse;
  height: 500px;
}
.main {
  float: left;
   background-color:darkcyan;
    width: 1200px;
     height: 500px;
}
</style>
  1. 路由index.js
// 使用組件
Vue.use(Router)
// 導出一個默認的組件
export default new Router({
  routes: [
    {
      path: '/layout',
      components: {
        default: Main,
        top: Top,
        left: Left
      }
    }]
})
  1. 分別創(chuàng)建3個組件
    left.vue
<template>
    <div id="container">
        菜單視圖
    </div>
</template>
<script>
export default { 
}
</script>
<style scoped>
</style>

main.vue

<template>
    <div id="container">
        內(nèi)容視圖
    </div>
</template>
<script>
export default { 
}
</script>
<style scoped>
</style>

top.vue

<template>
    <div id="container">
        頂部導航視圖
    </div>
</template>
<script>
export default { 
}
</script>
<style scoped>
</style>

this.$router.push()
跳轉到不同的url,但這個方法會向history棧添加一個記錄,點擊后退會返回到上一個頁面。
this.router.replace 跳轉到指定url路徑,但是history棧中不會有記錄. this.router.replace
跳轉到指定url路徑,但是history棧中不會有記錄,點擊返回會跳轉到上上個頁面

八、路由常用屬性

1.$route.path 
字符串,等于當前路由對象的路徑,會被解析為絕對路徑,如 "/home/news" 。
2.$route.params 
對象,包含路由中的動態(tài)片段和全匹配片段的鍵值對。
3.$route.query 
對象,包含路由中查詢參數(shù)的鍵值對。例如,對于 /home/news/detail/01?favorite=yes ,會得到$route.query.favorite == ‘yes‘ 。
4.$route.router 
路由規(guī)則所屬的路由器(以及其所屬的組件)。
5.$route.matched 
數(shù)組,包含當前匹配的路徑中所包含的所有片段所對應的配置參數(shù)對象。
6.$route.name 
當前路徑的名字,如果沒有使用具名路徑,則名字為空。

九、Vue:router的beforeEach與afterEach鉤子函數(shù)

??在路由跳轉的時候,我們需要一些權限判斷或者其他操作。這個時候就需要使用路由的鉤子函數(shù)。
定義:路由鉤子主要是給使用者在路由發(fā)生變化時進行一些特殊的處理而定義的函數(shù)。
總體來講vue里面提供了三大類鉤子,兩種函數(shù)
1、全局鉤子
2、某個路由的鉤子
3、組件內(nèi)鉤子
兩種函數(shù):
1、在跳轉之前執(zhí)行

/*在跳轉之前執(zhí)行*/
Vue.beforeEach(function(to,form,next){})  
  1. 在跳轉之后判斷
/*在跳轉之后判斷*/
Vue.afterEach(function(to,form))

全局鉤子函數(shù):

router.beforeEach((to, from, next) => {
    let token = router.app.$storage.fetch("token");
    let needAuth = to.matched.some(item => item.meta.login);
    if(!token && needAuth) return next({path: "/login"});
    next();
});

beforeEach函數(shù)有三個參數(shù):
to:router即將進入的路由對象
from:當前導航即將離開的路由
next:Function,進行管道中的一個鉤子,如果執(zhí)行完了,則導航的狀態(tài)就是 confirmed (確認的);否則為false,終止導航。
afterEach函數(shù)不用傳next()函數(shù)
某個路由的鉤子函數(shù)
顧名思義,它是寫在某個路由里頭的函數(shù),本質上跟組件內(nèi)函數(shù)沒有區(qū)別。

const router = new VueRouter({
  routes: [
    {
      path: '/login',
      component: Login,
      beforeEnter: (to, from, next) => {
        // ...
      },
      beforeLeave: (to, from, next) => {
        // ...
      }
    }
  ]
})

路由組件的鉤子
注意:這里說的是路由組件!
路由組件屬于組件,但組件不等同于路由組件!所謂的路由組件:直接定義在router中component處的組件。如

var routes = [
    {
    path:'/home',
    component:home,
    name:"home"
    }
]

在子組件中調用路由的鉤子函數(shù)時無效的。
示例:
permission.js

/**
 * 全站權限配置
 */
import router from '@/router.js'

// 最先執(zhí)行的是 beforeEach鉤子,所有路由開始的時候最先執(zhí)行
router.beforeEach((to, from, next) => {
    console.log("跳轉路徑:"+to);
    console.log("當前路徑:"+from);
    // 繼續(xù)執(zhí)行
    next();
});

// 在跳轉之后判斷
router.afterEach(() => {
    console.log("路由執(zhí)行完畢");
});

main.js

// 導入權限文件
import  "@/utils/permission.js";

十、router-view組件間傳值

  1. router-view 子組件傳父組件
    父組件:
<template>
  <div id="app">
    一個簡單的測試
    <router-view @getUser="getUserInfo"/>
  </div>
</template>
<script>
export default {
  methods:{
    getUserInfo(val){
      console.log(val+"-》父組件");
    }
  }
}
</script>

子組件:

<template>
  <div class="home">
    <input type="button"  @click="test" value="登錄">
  </div>
</template>
<script>
export default {
  name: "home",
  components: {
  },
  methods: {
    test() {
      this.$emit("getUser", "我是home組件");
    }
  }
};
</script>

測試:


子傳父
  1. 父傳子
    父組件:
<template>
  <div id="app">
    一個簡單的測試
    <router-view :userSubValue="userData" />
  </div>
</template>
<script>
export default {
  data(){
    return { userData:" 父組件數(shù)據(jù)"}
  }
};
</script>

子組件:

<template>
  <div class="home">{{user}}</div>
</template>
<script>
export default {
  name: "home",
  data() {
    return { user: "" };
  },
  props: ["userSubValue"],
  created() {
    this.getUserValue();
  },
  methods: {
    getUserValue() {
      this.user=this.userSubValue;
    }
  }
};
</script>

路由:router.js

import Vue from 'vue'
import Router from 'vue-router'


Vue.use(Router)

export default new Router({
  mode: 'history',
  base: process.env.BASE_URL,
  routes: [
    {
      path: '/home',
      name: 'home',
      component: () => import(/* webpackChunkName: "about" */ './views/Home.vue')
    },
    {
      path: '/about',
      name: 'about',
      component: () => import(/* webpackChunkName: "about" */ './views/About.vue')
    }
  ]
})

測試:


測試結果
  1. 示例
    使用router-view將子組件home.vue數(shù)據(jù)傳給app.vue,app.vue再將數(shù)據(jù)傳給一個子組件about.vue。
    home.vue
<template>
  <div class="home">
    <input type="button"  @click="test" value="登錄">
  </div>
</template>
<script>
export default {
  name: "home",
  components: {
  },
  methods: {
    test() {
      this.$emit("getUser", "我是home組件");
    }
  }
};
</script>

app.vue

<template>
  <div id="app">
    <about :userInfo="user"/>
    一個簡單的測試
    <router-view @getUser="getUserInfo" />
  </div>
</template>
<script>
import About from "@/views/About.vue";
export default {
  data(){
    return { user:""}
  },
  components: {
    About
  },
  methods: {
    getUserInfo(val) {
      this.user=val;
      console.log(val + "-》父組件");
    }
  }
};
</script>

about.vue

<template>
  <div class="about">
    <h1>這是about組件</h1>
    {{userInfo}}
  </div>
</template>
<script>
export default {
  props: { userInfo: String },
  data() {
    return { msg: "" };
  }
};
</script>

路由:router.js

import Vue from 'vue'
import Router from 'vue-router'


Vue.use(Router)

export default new Router({
  mode: 'history',
  base: process.env.BASE_URL,
  routes: [
    {
      path: '/home',
      name: 'home',
      component: () => import(/* webpackChunkName: "about" */ './views/Home.vue')
    },
    {
      path: '/about',
      name: 'about',
      component: () => import(/* webpackChunkName: "about" */ './views/About.vue')
    }
  ]
})

測試:


home訪問

獲取數(shù)據(jù)

十一、常見問題

  1. NavigationDuplicated {_name: "NavigationDuplicated", name: "NavigationDuplicated", message: "Navigating to current location ("/welcome/index") is not allowed"
    原因:在路由中添加了相同的路由。
    解決:
    重寫路由的push方法:
/**
 * 重寫路由的push方法
 */
const routerPush = Router.prototype.push
Router.prototype.push = function push(location) {
  return routerPush.call(this, location).catch(error=> error)
}
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容