vue-router 路由
vue-router是Vue.js官方的路由插件,它和vue.js是深度集成的,适合用于构建单页面应用。路由用于设定访问路径, 将路径和组件映射起来.在vue-router的单页面应用中, 页面的路径的改变就是组件的切换.https://router.vuejs.org/zh/(一) 基本使用[1]. 安装vue-routernpm install vue-router --save[2]. 新建
- vue-router是Vue.js官方的路由插件,它和vue.js是深度集成的,适合用于构建单页面应用。
- 路由用于设定访问路径, 将路径和组件映射起来.
- 在vue-router的单页面应用中, 页面的路径的改变就是组件的切换.
- https://router.vuejs.org/zh/
(一) 基本使用
[1]. 安装vue-router
npm install vue-router --save
[2]. 新建映射的组件
在src\components目录下新建Home.vue和About.vue文件,并在template里边输入内容。
如Home.vue文件中的内容:
<template>
<div>
<p>这里是Home.vue</p>
</div>
</template>
<script>
export default {
name: 'Home'
}
</script>
[3]. 引入组件并和路径对应
-
新建\src\router文件夹,并在文件夹下新建index.js文件
-
引入router插件并注册,引入刚创建的两个组件文件
-
创建VueRouter对象,使路径和组件对应。
import Vue from "vue"; import Router from "vue-router"; //引入router Vue.use(VueRouter);//注册router //下面引入方式等价,这里的@ 等于/src import Home from '../components/Home' //引入组件Home import About from '@/components/About' export default new Router({ routes: [ { path: '/home', name: 'Home', //name属性,这里和组件中至少要有一处有该属性 component: Home }, { path: '/about', name: 'About', component: About } ] })
-
在main.js文件中引入路由文件
import Vue from 'vue' import App from './App.vue' import router from './router'; //引入路由文件 Vue.config.productionTip = false new Vue({ router,//使用 render: h => h(App), }).$mount('#app')
[4]. 显示组件
在src/app.vue中添加
<template>
<div id="app">
<router-link to="/home">首页</router-link>
<router-link to="/about">关于</router-link>
<router-view></router-view>
</div>
</template>
- <router-link>: 该标签是一个vue-router中已经内置的组件, 它会被渲染成一个<a>标签.
- <router-view>: 该标签会根据当前的路径, 动态渲染出不同的组件.
- 网页的其他内容, 比如顶部的标题/导航, 或者底部的一些版权信息等会和<router-view>处于同一个等级.
- 在路由切换时, 切换的是挂载的组件, 其他内容不会发生改变.
[5].设置默认路径
在路由映射文件中 ( router/index.js),redirect属性是重定向,即当路径为空时(path也可以设置为" path: ‘/’ "),将页面重定向到home组件上。
export default new Router({
routes: [
{
path: '',
redirect: '/home'
},
....
]
})
[6].将hash模式换为history模式
当前的路径为下图,希望改为:“localhost:8080/home”形式
在路由映射文件router/index.js中的VueRouter对象添加,mode属性即可。
export default new Router({
routes: [...],
mode: 'history'
})
[7]. router-link补充
-
在前面的<router-link>中, 我们只是使用了一个属性
:to
, 用于指定跳转的路径。 -
tag
: tag可以指定<router-link>之后渲染成什么组件<router-link to='/home' tag='li'>Home</router-link>
上面的代码会被渲染成一个<li>元素, 而不是<a>
-
replace
: replace替换掉(浏览历史)栈中的最上边的历史记录。<router-link to='/home' replace>Home</router-link>
-
active-class
: 当<router-link>对应的路由匹配成功时, 会自动给当前元素设置一个router-link-active的class, 设置active-class可以修改默认的名称。-
在进行高亮显示的导航菜单或者底部tabbar时, 会使用到该类。
-
但是通常不会修改类的属性, 会直接使用默认的router-link-active即可。
-
在路由映射文件router/index.js中,可以添加linkActiveClass属性,来统一管理当控件选中是的样式
export default new Router({ ..... linkActiveClass: 'active' })
-
[8]. 利用 路由信息对象$router 实现跳转
路由信息对象:每个组件会被注入$router,可以利用它进行一些信息的获取。
- router.push 方法。这个方法会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,则回到之前的 URL。
在/src/app.vue主组件文件中,利用方法实现跳转。
<template>
<div id="app">
<button @click="goHome()">首页</button>
<button @click="goAbout()">关于</button>
<router-view></router-view>
</div>
</template>
<script>
export default{
name: 'App',
methods: {
goHome(){
//字符串
this.$router.push('/home');
// 对象
//router.push({ path: 'home' })
// 命名的路由 /user/123 这里的name是routes中的name
//router.push({ name: 'user', params: { userId: '123' }})
// 带查询参数,变成 /register?plan=private
//router.push({ path: 'register', query: { plan: 'private' }})
},
goAbout(){
this.$router.push('/about');
}
}
}
</script>
(二) 动态路由匹配(参数传递)
[1]. query的类型:
- 传递的方式: 组件中使用query的key作为传递方式
- 传递后形成的路径: /router?id=123, /router?id=abc
- 在路由入口函数中引入和写入对应的路由关系。
home.vue中添加:<!-- 点击消息后url为:'/home/news?name=message&id=001' --> <router-link :to="{path:'/home/message', query: {name:'message', id: '001'}}">消息</router-link>
- 组件中获取query参数
在HomeMessage.vue中获取传递的参数<template> <div> <p>这里是HomeMessage.vue</p> <p>{{$route.query.name}}</p> <p>{{getQueryId}}</p> </div> </template> <script> export default { name: 'HomeMessage', computed:{ getQueryId(){ return this.$route.query.id; } } } </script>
[2]. params的类型:
注意:路由携带params参数时,若使用to的对象写法,则不能使用path配置项,必须使用name配置!
-
配置路由,声明接受params参数
在路由配置文件中router/index.jsimport Vue from 'vue'; import Router from 'vue-router'; Vue.use(Router); import Info from '@/components/Info' export default new Router({ routes:[ { name: 'xinxi', //如果使用to的对象写法则需要添加该属性 path: '/info/:id/:name',//使用占位符声明接收的params参数的key component: Info } ] });
-
传递参数
App.vue文件<template> <div id="app"> <!-- 跳转到info页面时携带 id为123,name为tom --> <!-- 跳转并携带params参数,to的字符串写法 --> <router-link to="/info/123/tom">信息</router-link> <!-- 跳转并携带params参数,to的对象写法, 这里的name必须和路由配置项中的name对应 --> <router-link :to="{ name: 'xinxi', params: { id: 123, name: 'tom', }, }">信息</router-link> <router-view></router-view> </div> </template>
-
接受参数的组件
<template> <div> <p>这里是Info.vue</p> <p>我的姓名:{{$route.params.name}},我的ID:{{getId}}</p> </div> </template> <script> export default { name:'Info', computed:{ getId(){ return this.$route.params.id } } } </script>
[3]. 路由的props配置
作用:让路由组件更方便的收到参数
- 路由配置文件router/index.js
import Vue from 'vue'; import Router from 'vue-router'; Vue.use(Router); import Detail from '@/components/Detail' export default new Router({ routes:[ { path: '/detail', //第一、三种写法需用到 // path: '/detail/:id/:title', //第二种写法需用到 component: Detail, //第一种写法: props值为对象,该对象所有的key-value的组合最终都会通过props传给组件 // props: {id: 13, title: '这是详情的标题'},. //第二种写法: props值为true,则把路由接收到的所有params参数通过props传给Detail组件 // props: true, //第三种写法: props值为函数,该函数返回的对象中每一组key-value都会通过props传给Detail组件 props(route){ console.log(route); return{ id: route.query.id, title: route.query.title } } } ] });
- Detail.vue组件中配置
<template> <div> <p>这里是Detail.vue</p> <p>id是:{{id}}, 标题是:{{title}}</p> </div> </template> <script> export default { name: 'Detail', props:['id', 'title'] } </script>
- App.vue组件中改变url和传递参数
<template>
<div id="app">
<!-- 第一种写法用到 -->
<!--<router-link to="/detail?id=123&title=asdf">详情</router-link> -->
<!-- 第二种写法用到 -->
<!-- <router-link to="/detail/123/asdf">详情</router-link> -->
<!-- 第三种写法用到 -->
<router-link to="/detail?id=123&title=asdf">详情</router-link>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: "App",
};
</script>
(三) 路由嵌套
[1]. 路由嵌套
嵌套路由是一个很常见的功能
- 比如在home页面中, 我们希望通过/home/news和/home/message访问一些内容.
- 一个路径映射一个组件, 访问这两个路径也会分别渲染两个组件.
-
在/src/components组件文件夹中新建HomeNews.vue组件和HomeMessage.vue组件
HomeNews内容如下:<template> <div> <p>这里是HomeNews.vue</p> </div> </template> <script> export default { name: "HomeNew", }; </script>
-
在路由配置文件src/router/index.js中引入这两个文件
const HomeNews = ()=>import('../components/HomeNews'); const HomeNews = ()=>import('../components/Message'); ... export default new Router({ routes: [ ... { path: '/home', name: 'Home', component: Home, children: [ { path: '', redirect: 'news' //这里没有斜线 '/' }, { path: 'news', //这里没有斜线 '/' name: 'News', component: HomeNews }, { path: 'message', name: 'Message', component: HomeMessage } ] }, ... })
-
在Home.vue组件中添加
<template> <div> <p>这里是Home.vue</p> <router-link to="/home/news">新闻</router-link> <router-link to="/home/message">消息</router-link> <router-view></router-view> </div> </template> <script> export default { name: 'Home' }; </script>
-
在本地服务器运行。
[2]. 命名路由
当url路径越来越长时,可以使用命名路由来简化路径。
- 如果想要查看 HomeNewsItem 组件的内容,写需要很长的路径,可以使用命名路由
<div>
<p>这里是HomeNews.vue</p>
<!-- 普通写法 -->
<router-link to="/home/news/item">新闻item</router-link>
<!-- 命名路由-->
<router-link :to="{name: 'new_item'}">新闻item</router-link>
<router-view></router-view>
</div>
//router/index.js中路由配置
export default new Router({
routes:[
{
path: '/home',
component: Home,
children:[
{
path: 'news',
component: HomeNews,
children: [
{
name: 'new_item',
path: 'item',
component: HomeNewsItem
}
]
}
]
},
]
});
(四)缓存路由组件:keep-alive
-
keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染(如果没有keep-alive组件是会被销毁和重新创建,添加keep-alive是不会被销毁的)。
-
router-view 也是一个组件,如果直接被包在 keep-alive 里面,所有路径匹配到的视图组件都会被缓存
-
当data中的数据改变时,组件里的变量也会相应的改变。
-
keep-alive实例:
<div id="app"> <button @click="currentCpn=1">btn1</button> <button @click="currentCpn=2">btn2</button> <button @click="currentCpn=3">btn3</button> <!-- 可以看看去掉keep-alive的效果 --> <keep-alive> <cpn v-if="currentCpn === 1"></cpn> <cpn2 v-if="currentCpn === 2"></cpn2> <cpn3 v-if="currentCpn === 3"></cpn3> </keep-alive> </div> <template id="cpn"> <p>{{name}}</p> </template> <template id="cpn2"> <p>cpn2</p> </template> <template id="cpn3"> <p>cpn3</p> </template> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> const cpn = { template: "#cpn", data(){ return{ name:"cpn" //可以实现响应式改变 } }, mounted() { console.log('cpn mounted'); }, destroyed() { console.log('cpn destroyed'); } } const cpn2 = { template: "#cpn2", mounted() { console.log('cpn2 mounted'); }, destroyed() { console.log('cpn2 destroyed'); } } const cpn3 = { template: "#cpn3", mounted() { console.log('cpn3 mounted'); }, destroyed() { console.log('cpn3 destroyed'); } } const app = new Vue({ el: "#app", data: { currentCpn: 1 }, components: { cpn, cpn2, cpn3 } }); </script>
[1]. include 和 exclude
-
include - 字符串或正则表达,只有匹配的组件会被缓存
<!-- Detail是组件的name属性的值 --> <!-- 缓存多个 可以使用 :include="['News', 'Detail']" --> <keep-alive include="Detail"> <router-view></router-view> </keep-alive>
-
exclude - 字符串或正则表达式,任何匹配的组件都不会被缓存
匹配首先检查组件自身的 name 选项,如果 name 选项不可用,则匹配它的局部注册名称 (父组件 components 选项的键值)。匿名组件不能被匹配。<!-- 不缓存Detail(组件的name的值) --> <keep-alive exclude="Detail"> <router-view></router-view> </keep-alive>
//Detail 组件 export default { name:"Detail", //与上面的对应 }
[2]. activated 和 deactivated 生命周期钩子
- 当组件在<keep-alive> 内被切换,它的
activated
和deactivated
这两个生命周期钩子函数将会被对应执行。 - 在 2.2.0 及其更高版本中,
activated
和deactivated
将会在 <keep-alive> 树内的所有嵌套组件中触发。
(五).注意点和 $router和$route
- 路由组件通常存放在
src\pages
文件夹中(自己创建),一般组件通常存放在components
文件夹中。 - 通过切换,“隐藏” 的路由组件默认是被销毁掉的,需要的时候再去挂载。
$router
是VueRouter的一个对象,通过Vue.use(VueRouter)和Vue构造函数得到一个router的实例对象,这个对象中是一个全局的对象,他包含了所有的路由,包含了许多关键的对象和属性。$route
是一个跳转的路由对象,每一个组件都会有一个$route对象,是一个局部的对象,可以获取对应的name,path,params,query等$router
和$route
在组件实例上可以看到。
(六) 路由守卫
-
vue-router提供的导航守卫主要用来监听监听路由的进入和离开的.
-
vue-router提供了beforeEach和afterEach的钩子函数, 它们会在路由即将改变前和改变后触发.
-
参数或查询的改变并不会触发进入/离开的导航守卫。
-
主要包括beforeEach(to, from, next) 和 afterEach(to, from)
beforeEach(to, from, next)
– 初始化和路由切换之前被调用
to : router即将进入的路由对象
from : 当前导航即将离开的路由
next : Function,进行管道中的一个钩子,如果执行完了,则导航的状态就是 confirmed (确认的);否则为false,终止导航。afterEach(to, from)
–初始化和路由切换之后被调用 -
这类钩子主要作用于全局,一般用来判断权限,以及以及页面丢失时候需要执行的操作
https://router.vuejs.org/zh/guide/advanced/navigation-guards.html#%E8%B7%AF%E7%94%B1%E7%8B%AC%E4%BA%AB%E7%9A%84%E5%AE%88%E5%8D%AB
[1]. 全局守卫
-
在路由配置文件router/index.js文件中, 定义的路由映射中,有一个属性
meta
,在其中添加一个title信息const router = new VueRouter({ routes: [ { path:'/profile', name: 'Profile', component: Profile, meta:{ //路由元信息,用户自己可以定义其中数据的类型 title:'档案' // title是自己定义的 }, } ] })
-
通过beforeEach钩子函数当路由改变之前调用该方法来修改页面的title
//全局前置路由守卫--初始化和每次路由切换之前被调用 router.beforeEach((to, from, next)=>{ window.document.title = to.matched[0].meta.title; next(); });
[2]. 独享路由守卫
如果你不想全局配置守卫的话,你可以为某些路由单独配置守卫
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => { //只有这一个独享路由守卫
// 参数用法什么的都一样,调用顺序在全局前置守卫后面,所以不会被全局守卫覆盖
// ...
}
}
]
})
[3]. 组件内的路由守卫
-
beforeRouteEnter(to, from, next)
通过路由规则,进入该组件时被调用。不能获取组件实例 this,组件实例还没被创建 -
beforeRouteUpdate (2.2) 路由复用同一个组件时, 在当前路由改变,但是该组件被复用时调用 可以访问组件实例 this
-
beforeRouteLeave(to, from, next)
通过路由规则,离开该组件时被调用。可以访问组件实例 thisexport default { name:'Info', computed:{ getId(){ console.log('$route', this.$route); } }, beforeRouteEnter (to, from, next) { console.log('进入Info.vue组件中'); console.log(this); //undefined console.log(to); //该页面 等于 $route console.log(from); //从哪个页面来的 next(); }, beforeRouteLeave (to, from, next) { console.log('离开Info.vue组件中'); console.log(this); console.log(to); //要去哪个页面 console.log(from);//该页面 等于 $route next() } }
(七) 路由懒加载
-
首先, 我们知道路由中通常会定义很多不同的页面.
-
这个页面最后被打包在哪里呢? 一般情况下, 是放在同一个js文件中.
-
但是, 页面这么多放在一个js文件中, 必然会造成这个页面非常的大.
-
如果我们一次性从服务器请求下来这个页面, 可能需要花费一定的时间, 甚至用户的电脑上还出现了短暂空白的情况.
-
如何避免这种情况呢? 使用路由懒加载就可以了.
-
按照如下方式修改路由入口文件router/index.js文件
方式一: 结合Vue的异步组件和Webpack的代码分析.
const Home = resolve => { require.ensure(['../components/Home.vue'], () => { resolve(require('../components/Home.vue')) })};
方式二: AMD写法
const About = resolve => require(['../components/About.vue'], resolve);
方式三: 在ES6中, 我们可以有更加简单的写法来组织Vue异步组件和Webpack的代码分割.
const Home = () => import('../components/Home.vue'); export default new Router({ routes: [ { path: '/home', name: 'Home', component: Home } ] })
[2].把组件按组分块
有时候我们想把某个路由下的所有组件都打包在同个异步块 (chunk) 中。只需要使用 命名 chunk,一个特殊的注释语法来提供 chunk name (需要 Webpack > 2.4)。
const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue')
const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue')
const Baz = () => import(/* webpackChunkName: "group-foo" */ './Baz.vue')
Webpack 会将任何一个异步模块与相同的块名称组合到相同的异步块中。
(八) 捕获所有路由或404 Not found路由
-
常规参数只会匹配被 / 分隔的 URL 片段中的字符。如果想匹配任意路径,我们可以使用通配符 (*):
{ // 会匹配所有路径 path: '*' } { // 会匹配以 `/user-` 开头的任意路径 path: '/user-*' }
-
当使用通配符路由时,请确保路由的顺序是正确的,也就是说含有通配符的路由应该放在最后。路由 { path: ‘*’ } 通常用于客户端 404 错误。如果你使用了History 模式,请确保正确配置你的服务器。
-
当使用一个通配符时,$route.params 内会自动添加一个名为 pathMatch 参数。它包含了 URL 通过通配符被匹配的部分:
// 给出一个路由 { path: '/user-*' } this.$router.push('/user-admin') this.$route.params.pathMatch // 'admin' // 给出一个路由 { path: '*' } this.$router.push('/non-existing') this.$route.params.pathMatch // '/non-existing'
更多推荐
所有评论(0)