官网:https://router.vuejs.org/zh-cn/
因为我们更多的是利用vue+webpack搭建整个项目的框架(例如vue-cli),所以我们这里利用vue-cli讲解
何为前端路由
何时使用前端路由
前端路由优点
前端路由缺点
用 Vue.js + vue-router 创建单页应用很常用,vue-router 用来搭建路由,这里的路由并不是指我们平时所说的硬件路由器,这里的路由就是SPA(单页应用)的路径管理器。再通俗的说,vue-router就是我们WebApp的链接路径管理系统。
npm install vue-router --save-dev
//引入Vue
import Vue from 'vue';
//引入vue-router
import Router from 'vue-router';
//引入根目录下的HelloWorld.vue组件
import HelloWorld from '@/components/HelloWorld';
//Vue全局使用Router
Vue.use(Router);
export default new Router({
//配置路由,这里是个数组
routes: [
{ //每一个链接都是一个对象
path: '/', //链接路径
name: 'HelloWorld', //路由名称,可以在router-link和router.push中使用,就相当于这个组件了
component: HelloWorld //对应的组件模板
}
]
});
可以看到http://localhost:8080/#/ 就是我们的根‘/’页面
import Vue from 'vue';
import Router from 'vue-router';
import HelloWorld from '@/components/HelloWorld';
import First from '@/components/first';
Vue.use(Router);
export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
},
{
path: '/first',
name: 'First',
component: First
}
]
});
结果:
可以看到http://localhost:8080/#/first 就是我们的根‘/first’页面
我们可以发现vue路径中是带有 # 号,例如: http://localhost:8080/#/first
这是因为:
vue-router 默认 hash 模式 —— 使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载。
如果不想要很丑的 hash,我们可以用路由的 history 模式,这种模式充分利用 history.pushState API 来完成 URL 跳转而无须重新加载页面。
import Vue from 'vue';
import Router from 'vue-router';
import First from '@/components/first';
Vue.use(Router);
export default new Router({
// 更改模式
mode: 'history',
routes: [
{
path: '/first',
name: 'First',
component: First
}
]
});
我们利用 mode: ‘history’, 更改模式
这样一来http://localhost:8080/#/first就访问不到,需要采用http://localhost:8080/first访问
我们在模板文件将 this.$router打印
methods: {
go() {
console.log(this.$router);
}
},
具体的作用可以看后面的 6.编程式的导航
访问当前路由
我们在模板文件中将$route打印出来
methods: {
go() {
console.log(this.$route);
}
},
结果:
我们可以获取$route的params和query获取到当前路由的信息
关于设置路由参数可以看下文章后面的内容
params一旦在路由中配置,params就是路由的一部分,如果在跳转的时候没有传这个参数,会导致跳转失败或者页面会没有内容。
例如我们设置路由为
{
path: '/first/:from/:age',
name: 'First',
component: First
}
:from 和 :age 是形参,我们需要传递实参,可以通过this.route.params.[name]获取实参
如果我们少一个参数,如http://localhost:8080/#/first/one 那么就是无法访问
如果我们不设置params,我们直接在url中加上,那么我们也是无法访问的
query是拼接在url后面的查询参数,没有也没关系。
例如我们路由设置
var c = china;
this.$router.push('/first?from=' + c);
可以通过this.route.query.[name]获取
我们经常需要把某种模式匹配到的所有路由,全都映射到同个组件。例如,我们有一个 User 组件,对于所有 ID 各不相同的用户,都要使用这个组件来渲染
在路由配置文件里以冒号的形式设置参数。动态路径参数 以冒号开头
import Vue from 'vue';
impimport Vue from 'vue';
import Router from 'vue-router';
import User from '@/components/User';
Vue.use(Router);
export default new Router({
routes: [
{
//设置
path: '/user/:id',
name: 'User',
component: User
}
]
});
现在呢,像 /user/foo 和 /user/bar 都将映射到相同的路由。
this.$route.params.id
路由中可以设置多段『路径参数』,对应的值都会设置到 $route.params 中
router-link 比起写死的 a href=”…” 会好一些,理由如下:
<router-link to="/foo">Go to Foorouter-link>
当被点击后,内部会立刻把 to 的值传到 router.push(),直接写string表示根路径
<router-link to="home">Homerouter-link>
<a href="home">Homea>
<router-link v-bind:to="'home'">Homerouter-link>
<router-link :to="'home'">Homerouter-link>
<router-link :to="{ path: 'home' }">Homerouter-link>
<router-link :to="{ name: 'user', params: { userId: 123 }}">Userrouter-link>
<router-link :to="{ path: 'register', query: { plan: 'private' }}">Registerrouter-link>
如果 router-link to指向path,params 会被忽略
路径还是/user 不是/uer/123
:to="{ path: 'user', params: { userId: 123 }}">User
路由配置文件中引入组件:
{
path: '/first',
name: 'FirstVue',
component: First
}
跳转
:to="{ name: 'FirstVue', params: { userId: 123 }}">FirstVue
设置 replace 属性的话,当点击时,会调用 router.replace() 而不是 router.push(),于是导航后不会留下 history 记录。
<router-link :to="{ path: '/abc'}" replace></router-link>
设置 append 属性后,则在当前(相对)路径前添加基路径。例如,我们从 /a 导航到一个相对路径 b,如果没有配置 append,则路径为 /b,如果配了,则为 /a/b
<router-link :to="{ path: 'relative/path'}" append></router-link>
有时候想要 router-link渲染成某种标签,例如 li。 于是我们使用 tag prop 类指定何种标签,同样它还是会监听点击,触发导航。
<router-link to="/foo" tag="li">foorouter-link>
<li>fooli>
当router-link被激活时,或自动加上 class属性名:router-link-active
链接激活时使用的 CSS 类名。默认值可以通过路由的构造选项 linkActiveClass 来全局配置。
有时候我们要让激活 class 应用在外层元素,而不是 a 标签本身,那么可以用 router-link 渲染外层元素,包裹着内层的原生 a标签:
<router-link tag="li" to="/foo">
<a>/fooa>
router-link>
在这种情况下,a 将作为真实的链接(它会获得正确的 href 的),而 “激活时的CSS类名” 则设置到外层的 li。
就是路由器嵌套路由
first.vue:
<p>导航 :
<router-link to="/first/one">one首页router-link>
<router-link to="/first/two">two页面router-link>
p>
<router-view>router-view>
注意这里的router-link 的to要写真实路径,不能直接写/[name]
router配置文件
import Vue from 'vue';
import Router from 'vue-router';
import HelloWorld from '@/components/HelloWorld';
import First from '@/components/first';
import firstOne from '@/components/first-one';
import firstTwo from '@/components/first-two';
Vue.use(Router);
export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
},
{
path: '/first',
name: 'First',
component: First,
// 设置子路由
children: [
{
// 不能加‘/’,不然就变为根路径了
path: 'one',
name: 'firstOne',
component: firstOne
},
{
path: 'two',
name: 'firstTwo',
component: firstTwo
}
]
}
]
});
其实就是在父路由下面加一个children,但是注意不要加‘/’,不然就变为根路径了 ,子路径会自动继承父路径,例如’
http://localhost:8080/#/first/one
http://localhost:8080/#/first/two
关于$router 请看前面. 2.3router
想要导航到不同的 URL,使用 router.push 方法。这个方法会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,则回到之前的 URL。
router.push(location, onComplete?, onAbort?)
该方法的参数可以是一个字符串路径,或者一个描述地址的对象。例如:
// 字符串 (会直接跳到根路径,/home)
router.push('home')
// 对象
router.push({ path: 'home' })
// 命名的路由,这里的name是路径配置中你自己起的名字
router.push({ name: 'user', params: { userId: 123 }})
// 带查询参数,变成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})
注意:
如果提供了 path,params 会被忽略,上述例子中的 query 并不属于这种情况。取而代之的是下面例子的做法,你需要提供路由的 name 或手写完整的带有参数的 path:
const userId = 123
router.push({ name: 'user', params: { userId }}) // -> /user/123
router.push({ path: `/user/${userId}` }) // -> /user/123
// 这里的 params 不生效
router.push({ path: '/user', params: { userId }}) // -> /user
引入组件:
{
path: '/first',
name: 'FirstVue',
component: First
}
点击跳转:
<button @click="go">button>
methods: {
go() {
this.$router.push({name: 'FirstVue',params: {userId});
}
},
跟 router.push 很像,唯一的不同就是,它不会向 history 添加新记录,而是跟它的方法名一样 —— 替换掉当前的 history 记录。
这个方法的参数是一个整数,意思是在 history 记录中向前或者后退多少步,类似 window.history.go(n)
// 在浏览器记录中前进一步,等同于 history.forward()
router.go(1)
// 后退一步记录,等同于 history.back()
router.go(-1)
// 前进 3 步记录
router.go(3)
// 如果 history 记录不够用,那就默默地失败呗
router.go(-100)
router.go(100)
有时候想同时(同级)展示多个视图,而不是嵌套展示.
例如创建一个布局,有 sidebar(侧导航) 和 main(主内容) 两个视图,
一个视图使用一个组件渲染,因此对于同个路由,多个视图就需要多个组件。确保正确使用 components 配置(带上 s):
import Vue from 'vue';
import Router from 'vue-router';
import HelloWorld from '@/components/HelloWorld';
import Left from '@/components/left';
import Right from '@/components/right';
Vue.use(Router);
export default new Router({
model: 'history',
routes: [
{
path: '/',
name: 'welcom',
components: {
default: HelloWorld,
letVue: Left,
rightVue: Right,
}
}
]
});
在界面中拥有多个单独命名的视图,而不是只有一个单独的出口。如果 router-view 没有设置名字,那么默认为 default。
<router-view >router-view>
<router-view name="letVue">router-view>
<router-view name="rightVue">router-view>
『重定向』的意思是,当用户访问 /a时,URL 将会被替换成 /b,然后匹配路由为 /b
路由配置文件中(/src/router/index.js)把原来的component换成redirect参数就可以了
下面例子是从 / hello 重定向 / first, 重定向的目标也可以是一个命名的路由比如/addiress重定向 / first。
export default new Router({
routes: [
{
path: '/first',
name: 'firstVue'
component: first
},
{
path:'/hello',
redirect:'/'
},
{
path:'/addiress',
redirect: {
name: 'firstVue'
}
//或者
//redirect: '/first'
}
]
})
/a 的别名是 /b,意味着,当用户访问 /b 时,URL 会保持为 /b,但是路由匹配则为 /a,就像用户访问 /a 一样
export default new Router({
routes: [
{
path: '/first',
name: 'FirstVue',
component: First,
alias: '/hcd'
}
]
});
利用alias 设置别名’/hcd‘
结果:
http://localhost:8080/#/hcd 和 http://localhost:8080/#/first访问的是同一个页面
import Vue from 'vue';
import Router from 'vue-router';
import ErrorVue from '@/components/ErrorVue';
Vue.use(Router);
export default new Router({
routes: [
{
path: '*',
name: 'Error',
component: ErrorVue
}
]
});
将path设置为 * 代表所有找不到的页面
我们只能使用beforeEnter,也就是该路径加载时触发
三个参数:
import Vue from 'vue';
import Router from 'vue-router';
import HelloWorld from '@/components/HelloWorld';
import First from '@/components/first';
Vue.use(Router);
export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
},
{
path: '/first',
name: 'FirstVue',
component: First,
beforeEnter: (to, from, next) => {
console.log('我们来到了first页面');
console.log('to:', to);
console.log('from:', from);
next();
}
}
]
});
在模板中就可以有两个钩子函数可以使用:
beforeRouteEnter:在路由进入前的钩子函数。
beforeRouteLeave:在路由离开前的钩子函数。
参数和上面的beforeEnter是一样的
export default {
name: 'params',
data () {
return {
msg: 'params page'
}
},
beforeRouteEnter:(to,from,next)=>{
console.log("准备进入路由模板");
next();
},
beforeRouteLeave: (to, from, next) => {
console.log("准备离开路由模板");
next();
}
}