跟上俺,俩小时轻松搞定Vue Router

前言

点进这篇文章的童鞋,俺默认你已经对 路由、前端路由等有了一定的了解,如果对路由还不太了解的童鞋,点我可以先去了解一下路由、前端路由、后端路由等等的概念,再来食用这篇文章效果会更佳哦~

起步…走

vue-router 是 Vue 核心的一个插件,是 Vue 官方提供的一个路由管理器,必然属于前端路由的范畴。

我们会一步步实现一个简单的 HelloWorld ,快速认识一下它。


第一步我们引入 vue 、 vue-router ,这里直接使用 CDN 了,如果网速不好的同学可以将这两个文件保存到本地然后引入。

<head>
	<script src="https://unpkg.com/vue/dist/vue.js"></script>
	<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
</head>

我们首先创建一个 Vue 实例 ,这是必不可少的。

<div id="#app"></div>

<script>
	const vm = new Vue({
		el:'#app'
	})
</script>

紧接着我们创建两个简单的局部组件,并且注册给 Vue 实例

const position = {
	template:`<h2>position...</h2>`
}

const home = {
	template:`<h2>home...</h2>`
}

const vm = new Vue({
	el:'#app',
	components:{
		// 注册组件
		home,
		position
	}
})

接下来我们配置一下链接,在 app 元素内添加以下内容,router-link 默认会渲染成一个 a 标签,to 相当于 href 属性,可以配置跳转到对应的路由,路由地址可以在这里定义。

<router-link to="/home">首页</router-link>
<router-link to="/position">职位</router-link>


接下来需要定义一个 <router-view>,表示路由在切换时,内容显示在这里。

<router-view>
	// 路由切换时在这里显示对应组件的内容....
</router-view>

接下来我们就可以配置 vue-router 了!首先创建一个vue-router 的实例。配置一个 routes 选项,是一个路由对象的数组。
路由对象第一个参数代表的是路由匹配的地址,第二个参数是跳转后显示哪个组件。

// 组件....

// vue-router 实例
const router = new VueRouter({
	routes:[
		{path:'/home',component:home},
		{path:'/position',component:position}
	]
})

// vue 实例....

光创建了 vue-router 实例还不行,还需要和 Vue 实例做一个关联,非常简单

const vm = new Vue({
  el: '#app',
  components: {
    home, position
  },
  router: router,  // 关联 vue-router ,因为key-value一致,这里可以简写为 router
})

到此为止,一个简单的 vue-router HelloWorld 就搞定了。我们可以打开浏览器看一下效果。

继续完善

这个样子太丑了,俺想继续完善、优化一下代码,加入一些新的功能,例如:

1、网页第一次加载的时候就显示 首页 的内容
2、当连接被选中时,俺希望添加一个样式,表示当前是选中状态
3、网页 URL 地址有一个很难看很丑的 # ,俺想…去掉…

其实上述几个功能在我们 vue-router 中实现起来轻轻松松,赶赶单单。

1、第一次加载时显示 首页

我们先来说第一个,在 vue-router 中有一个重定向的概念,可以在访问 / 根目录的时候让它重定向到我们需要显示的路由。

我们在 vue-router 实例中,再配置一个匹配 / 的路由 ,然后使用 redirect 这个选项可以让它进行重定向。

const router = new VueRouter({
  routes: [
    { path: '/home', component: home },
    { path: '/position', component: position },
	{ path: '/', redirect: '/home' }
  ]
})


ok! 这就完了? 是的这就完了,在 vue-router 中就是这么简单!

2、连接被选中时,添加一个样式

我们首先需要在 css 中创建这么一个样式,例如说就叫做 active

.active{
	color: #fff;
	background: #f78;
	font-weight: bold;
}

然后我们需要在 router-link 上添加一些代码,表示选中时使用 active 这个样式。注意: active-class 是固定写法!

<router-link to="/home" active-class="active">首页</router-link>
<router-link to="/position" active-class="active">职位</router-link>

我们再来看一下效果
在这里插入图片描述
so…easy…

3、优化 URL 地址
在这里插入图片描述
首先观察一下 url 地址,emmm 确实有一个挺让人烦心的 # ,这其实是 vue-router 的一种默认路由模式 hash 模式。
还有另外一种 history 模式,这种 history 模式可以让这烦人的 # 号干掉,那我们应该怎么样去配置路由模式呢?

其实也是非常简单的,在 vue-router 实例中有一个配置选项 mode 是用来配置路由模式的。

const router = new VueRouter({
  mode: 'history', // 默认不写是 hash,可以设置 history
  routes: [
    { path: '/home', component: home },
    { path: '/position', component: position },
    { path: '/', redirect: '/home' }
  ]
})

重新打开浏览器看一下 URL ,就找不到 # 啦,但是现在有出现了一个问题,我们首次打开页面的时候并没有显示 首页 的内容
在这里插入图片描述
仔细观察 URL ,俺猜测原因可能是因为没有匹配到 / ,所以没有重定向。我们稍微修改一下代码看看

{ path: '/', redirect: '/home' } ---> { path: '*', redirect: '/home' }

在这里插入图片描述
这个问题算是解决了,但是细心的同学可能就发现了,使用 history 这种模式,在刷新页面的时候会有问题!
在这里插入图片描述
这种刷新的问题,根据官方文档可以看到,我们如果要使用 history 模式,需要在后端进行配置,具体配置方法请参考官方文档后端配置栗子

嵌套路由

啥是嵌套路由呢?就拿 HelloWorld 栗子来说,假如说在首页中不仅仅显示的是 home... ,显示的是一个导航,点击导航选项的时候,会显示对应的内容。在职位中,显示的也不仅仅是 position... ,显示的同样是一个列表或者多个链接,点击对应的连接时,显示不同的内容。 类似于这样的场景就会用到 嵌套路由。

接下来我们就用 嵌套路由 实现上述的功能

第一步,需要修改一下 home 组件 和 position 组件中的内容

const position = {
  template: `
    <div>
      <nav>
        <router-link to="/position/add" active-class="active">添加职位</router-link>
        <router-link to="/position/update" active-class="active">修改职位</router-link>
        <router-link to="/position/del" active-class="active">删除职位</router-link>  
      </nav>
      // 点击添加/修改/删除后内容显示到 router-view 中
      <router-view></router-view>
    </div>
  `
}

const home = {
  template: `
    <div>
      <nav>
        <router-link tag="li" to="/home/menu1" active-class="active">Menu one</router-link>
        <router-link tag="li" to="/home/menu2" active-class="active">Menu two</router-link>
        <router-link tag="li" to="/home/menu3" active-class="active">Menu three</router-link>
        <router-link tag="li" to="/home/menu4" active-class="active">Menu four</router-link>
      </nav>
      // 内容也是显示到这里
      <router-view></router-view>
    </div>
  `
}

细心的同学可能发现了,在 home 组件模板中,router-link 上使用了一个 tag 属性,这个属性的意思是将 router-link 以什么样的标签进行渲染,这里指定了 li ,也就是说, router-link 渲染出来是 li 标签 。如果不设置 tag 属性,router-link默认是以 a 标签的形式进行渲染的。

看一下浏览器的结果就知道啦~
在这里插入图片描述
页面 ok 了,接下来我们配置一下路由,在路由对象中,有一个 children 配置选项,它是一个数组,可以配置多个子路由对象。

{
  path: '/home',
  component: home,
  children: [
    {
      // 这里的 path 可以写绝对路径 /home/menu1 ,也可以写相对路径 menu1
      path: 'menu1',
      component: {  // 组件这里当然可以单独抽取成一个对象,也可以直接写到这里,没啥毛病.
        template: `<p>menu1的内容...1</p>`
      }
    },
    {path: 'menu2',component: {template: `<p>menu2的内容...2</p>`}},
    {path: 'menu3',component: {template: `<p>menu2的内容...3</p>`}},
    {path: 'menu4',component: {template: `<p>menu2的内容...4</p>`}},
  ]
}

配置 position 的子路由

{
  path: '/position',
  component: position,
  children: [
    { path: 'add', component: { template: `<p>添加职位啦....</p>` } },
    { path: 'update', component: { template: `<p>修改职位啦....</p>` } },
    { path: 'del', component: { template: `<p>删除职位啦....</p>` } },
  ]
},

这就是嵌套路由的配置方式啦,其实也是蛮简单的嘛~ 打开浏览器看一下效果!
在这里插入图片描述
如果我们希望网页一加载就显示 首页中的第一个导航选项的内容,可以跟上面一样,修改匹配/的路由,然后使用 redirect 重定向到对应的路由就可以了。

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

在这里插入图片描述

动态路由

高大上的名字总是朴实无华…且枯燥… 哈哈哈,开个玩笑。 啥是动态路由呢? 其实就是匹配路由路径里动态的参数。 举个例子
{path: '/position/del/:id'} :id 就是一个动态的参数,可以传递任意值。

删除内容的时候,总是需要一个唯一标识来确定删除的是哪一条内容。我们可以在路由匹配里面配置

 { path: 'del/:id', component: { template: `<p>删除职位啦....</p>` } },

修改路由对应的连接,我们可以传递一个参数

<router-link to="/position/del/10010" active-class="active">删除职位</router-link> 

那怎么才能取到这个 10010 数据呢,我们可以通过 $router.params 获取到动态参数对象
修改组件中的代码,获取一下这个 id

{ path: 'del/:id', component: { template: `<p>删除职位啦....{{$route.params}}</p>` } },

在这里插入图片描述
传递多个值

<router-link to="/position/del/10010/29312/" active-class="active">删除职位</router-link> 

配置path,获取的时候也是一样 ,使用 $router.params

{ path: 'del/:id/:userid', component: { template: `<p>删除职位啦....{{$route.params}}</p>` } },

在这里插入图片描述

命名路由

说白了就是给 路由起个名字,可以在路由对象中通过 name 选项配置路由的别名。

{ path: 'del/:id/:userid', name : 'del',component: { template: `<p>删除职位啦....{{$route.params}}</p>` } },

修改 <router-link> 的代码

<router-link :to="{name:'del',params:{id:10010,userid:29312}}" active-class="active">删除职位</router-link>

结果是一样的
在这里插入图片描述

命名视图

官方介绍 有时候想同时 (同级) 展示多个视图,而不是嵌套展示,例如创建一个布局,有 sidebar (侧导航) 和 main (主内容) 两个视图,这个时候命名视图就派上用场了。你可以在界面中拥有多个单独命名的视图,而不是只有一个单独的出口。如果 router-view 没有设置名字,那么默认为 default。

<router-view> 就是视图, 我们来简单实现以下上述的功能。

视图代码

<div id="app">
	<router-link to="/home">首页</router-link>
	
	<div class="container">
	  <!--可以给视图起一个名字,如果不设置 name ,默认是 default-->
	  <router-view class="sidebar"></router-view>
	  <router-view name="main" class="main"></router-view>
	</div>
</div>

创建两个组件

var sidebar = {
  template: `<h2>侧边导航</h2>`
}

var main = {
  template: `<h2>主内容</h2>`
}

配置 路由对象

routes: [
  {
    path: '/home', 
    components: {
      default : sidebar,
      main: main  // 第一个 main 是 router-view 的name 属性值,第二个 main 是组件的名字
      // 也可以直接简写为 main
    }
  }
]

命名视图其实也就是给视图起名字区分一下,如果不写 name 属性,默认是 defalult
命名视图也是可以嵌套的,其实和嵌套路由差不多,有兴趣的同学可以点我去看一下官方文档的介绍,我这里就不演示了。
在这里插入图片描述

路由组件传参

路由传参这块在 Vue 整个路由中是非常重要的一部分,也是面试经常要考的。

在上述动态路由中,我们给 删除 路由设置了2个动态路由参数,在使用的时候通过 $route.params 这种方式获取的参数,使用$route这种方式会增加路由和组件的耦合性,因此我们需要使用 props 进行解耦。

使用 props 解耦
修改路由配置对象设置 props:true,这种方式也叫 布尔模式

{ path: 'del/:id/:userid', props: true, name: 'del', component: { template: `<p>删除职位啦....</p>` } }

在组件中,通过 props 来接收参数,然后使用即可

component: {
  props:["id","userid"],
  template: `<p>删除职位啦....{{id}}--{{userid}}</p>`
}

打开浏览器查看运行结果,一样可以获取到动态参数的值,但是这样写就降低了组件和路由之间的耦合性
在这里插入图片描述
对象模式
我们可以给 props 传递一个对象,修改 修改职位 的路由配置信息

{
  path: 'update',
  props: { name: 'xiaosai', age: 18 },
  component: {
    props: ["name", "age"],
    template: `<p>修改职位啦....{{name}}---{{age}}</p>`
  }
}

效果
在这里插入图片描述
传递对象时需要注意: 只有 当 props 是静态的时候有用,动态参数是获取不到的。

函数模式

可以创建一个 函数 返回 props , vue 会自动为该函数注入一个 route 对象,可以通过 route.params.xxx 获取参数。

修改 修改职位 路由配置信息

{
  path: 'update/:name/:age',
  props: route => ({
    name: route.params.name + '111', // 对参数做一些简单的处理
    age: parseInt(route.params.age) + 5 
  }),
  component: {
    props: ["name", "age"],
    template: `<p>修改职位啦....{{name}}---{{age}}</p>`
  }
},

修改 <router-link> 内容

<router-link to="/position/update/zhangsan/21"  active-class="active">修改职位</router-link>

在这里插入图片描述

编程式导航

前面也说过 <router-link> 默认会渲染成 a 标签,如果想渲染成 li 可以使用 tag 来设置,如果是其他元素呢,按钮、图片等等… 这时候显然使用 <router-link> 就不行了。我们可以使用原生的 html 标签,使用 $router 的 一些方法手动来实现路由的跳转,这就是编程式导航。

我们还是以最初的栗子来演示,把 首页、职位分别替换成 按钮和图片,我们直接使用原生的 html 标签替换 <router-link>

<button>首页</button>
<img src="https://img-blog.csdnimg.cn/20200406114911306.png" alt="">

先打开网页看一下效果
在这里插入图片描述
可以看到,按钮和图片都添加上去了,但是我们点击是没有任何效果的,需要给按钮和图片分别添加点击事件。

 <button @click="btnHandler">首页</button>
 <img src="https://img-blog.csdnimg.cn/20200406114911306.png" alt="" @click="imgHandler">

在 vue 实例中实现这两个函数

methods: {
  btnHandler() {
    this.$router.push('/home')
  },
  imgHandler() {
    this.$router.push('/position')
  }
}

可以通过 $router 访问 路由的实例,push 方法会在 history 栈中添加一个新纪录,可以通过浏览器的前进后退按钮进行操作。
在这里插入图片描述
push 方法的参数

  • 字符串
  • 对象
  • 命名的路由
  • 带查询参数的路由

    go 方法

使用 $router.go(step) 可以实现前进后退几步的操作,我们直接用一下试试

再创建两个按钮,并且实现点击前进和后退的功能

<button @click="$router.go(1)">前进</button>
<button @click="$router.go(-1)">后退</button>

导航守卫

官方文档第一句话 “导航” 表示路由正在发生改变,而守卫的意思说白了其实就是钩子函数。合起来就是可以用来监听到路由发生改变的钩子函数, 这样是不是更好理解了?守卫分为三类 全局守卫路由守卫组件守卫

全局守卫有以下三个

router.beforeEach() 在路由跳转之前会执行该函数,参数是一个回调函数,并且会注入三个参数,分别为 from to next

router.beforeEach((to, from, next) => {
  console.log("to:", to);
  console.log("from:", from);
})

因为 beforeEach 是全局守卫,所以每个路由在跳转之前都会被执行。
在这里插入图片描述
from 就是从哪个路由来,to 要跳转到哪里去。可以看到,此时内容并没有显示出来,因为我们没有执行 next

router.beforeEach((to, from, next) => {
  console.log("to:", to);
  console.log("from:", from);
  next();  // 执行 next 放行
})

在这里插入图片描述
我们一般会使用这种方式来做一些权限的验证。

router.beforeResolve()

全局解析守卫 引用官方文档的解释

vue 2.5 版本新增的内容,和 beforeEach() 有点类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用。

router.beforeResolve((to, from, next) => {
  console.log("to:", to);
  console.log("from:", from);
  next();
})

router.afterEach()

全局后置守卫,该守卫的回调函数中只有两个参数fromto,因为这时候跳转已经完成了,所以没有next 参数了。

router.afterEach((to, from) => {
  console.log("afterEach:", to, from);
})

在这里插入图片描述
路由独享守卫 beforeEnter()

可以在路由上直接定义该守卫

修改 add 路由配置

{
  path: 'add',
  component: {
    template: `<p>添加职位啦....</p>`
  },
  beforeEnter: (to, from, next) => {
    console.log("beforeEnter:", from, to);
    next()
  }
},

在这里插入图片描述
组件守卫

可以在路由组件中定义守卫钩子函数

beforeRouteEnter() 在渲染该组件的对应路由被 confirm 前调用,需要注意的是 不能获取组件实例 this,此时组件实例还没有被创建。

beforeRouteUpdate() 路由改变的时候

举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1/foo/2 之间跳转的时候,
由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
可以访问组件实例 this

beforeRouteLeave() 路由离开组件之前,可以访问组件实例 this

{
  path: 'add',
  component: {
    template: `<p>添加职位啦....</p>`,
    beforeRouteEnter: (to, from, next) => {
      console.log("beforeRouterEnter");
      next();
    },
    beforeRouteUpdate: (to, from, next) => {
      console.log("beforeRouteUpdate");
      next();
    },
    beforeRouteLeave: (to, from, next) => {
      console.log("beforeRouteLeave");
      next();
    }
  }
},

修改 position 组件模板中的内容,添加一个 按钮,并且绑定点击事件,手动切换路由

const position = {
  template: `
    <div>
      <nav>
        <router-link to="/position/add/1001" active-class="active">添加职位</router-link>
        <button @click = "handler">update id</button> 
        <router-link to="/position/update/zhangsan/21"  active-class="active">修改职位</router-link>
        <router-link to="/position/del" active-class="active">删除职位</router-link>
      </nav>
      <router-view></router-view>
    </div>
  `,
  methods: {
    handler() {
      // id 自增1
      var path = `/position/add/${++this.$route.params.id}`
      // 切换路由
      this.$router.push(path)
    }
  }
}

注意控制台打印的内容.
在这里插入图片描述

细节

总结一些小知识点

1、routerroutesroute 分别是什么
router 是 VueRouter 的实例 , 每个实例中必须配置一个 routes,他是一个数组,里面可以配置多个路由对象,也就是 route
在这里插入图片描述
2、怎么处理 404

处理 404 非常简单,在路由的最后配置一个* ,然后指向一个组件就可以了。

{path : '*',component:{template:`<h2>404 not found</h2>`}}

注意: 异常处理的一定要配置在最后一个 因为路由的匹配顺序是按照定义顺序来匹配的,谁先定义的,就先匹配谁。 试想一下,如果把 * 写在最前面,或者中间, 遇到 * 就不会执行后面的了。

3、正则匹配路由
我们也可以使用正则来匹配路由(其实在处理 404 的时候 * 就是一个正则了…),还有很多高级的匹配模式,有兴趣的小伙伴也可以去看一下它的用法

总结

到此为止,vue-router 诈看上去可能会稍微有点复杂,没有接触过的会觉得vue-router 作为 vue 核心插件,肯定会有一些难度,其实每个知识点细品以后你会发现,也就这么回事,核心无非就是 跳转、传参…等等 。
写了这么多其实都是一些基础必会的知识点,vue-router 还有一些高级的功能 ,具体用法请参考 官方文档 vue-router进阶部分


如果各位小伙伴觉得文章写得还不错,请动动您的小手指,点个赞,收藏,+关注,您的支持是我最大的动力呢~
在这里插入图片描述

发布了20 篇原创文章 · 获赞 17 · 访问量 6906

猜你喜欢

转载自blog.csdn.net/actionActivity/article/details/105316259