Vue-Router学习笔记

Vue-Router

简介

路由就是通过互联的网络把信息从源地址传输到目的地址的活动

后端路由:后端处理URL和页面之间的映射关系

随着前后端分离阶段的出现,之后便到了单页面富应用阶段:

  • 其实SPA最主要的特点就是在前后端分离的基础上加了一层前端路由
  • 也就是前端来维护一套路有规则

当我们进入一个网站我们会把他的所有资源html+css+js全部资源下载下来,这时候我们使用前端路由 比如 url:自己的域名/home url:自己的域名/about

这时候我们是从所有资源里面抽取所需要的资源,在我们vue里面就是一个个组件

实质上前端路由就是url和组件的映射关系,抽取资源是从所有资源中抽取相映射的资源并渲染

准备阶段

URL的hash

实质上是对网址的参数拼接,是不会刷新页面请求资源的

可以在控制台中

location.hash = “home”

H5中的pushState

可以在控制台中

history.pushState({},’’,‘home’);

这里我们比较类似栈结构

history.pushState({},’’,‘me’);

当前的栈顶是me页面

输入history.back()我们会回到home页面

H5中的replaceState

history.replaceState({},’’,‘home’)

history.replaceState({},’’,‘about’)

这时候我们没有返回按钮

H5中的go

这个是跳到某个栈的作用

history.pushState({},’’,‘home’);

history.pushState({},’’,‘me’);

history.pushState({},’’,‘about’);

history.pushState({},’’,‘test’);

history.pushState({},’’,‘demo’);

这时候我们在demo页面输入

history.go(-3)

这时候栈跳出三个,我们到达了me页面

history.go(2)

这时候我们给栈压入两个到达了test页面

所以history.back()相当于history.go(-1),history.forward()则等价于go(1)

认识配置

目前前端流行的三大框架,都有自己的路由实现:

  • Angular的ngRouter
  • React的ReactRouter
  • Vue的vue-router

安装

①npm install vue-router --save

②在模块化工程中使用它(因为是一个插件,所以可以通过Vue.use()来安装路由功能)

  1. 导入路由对象,并调用Vue.use(VueRouter)
  2. 创建路由实例,并且传入路由映射配置
  3. Vue实例挂载创建的路由实例

搭建路由框架

以下是我们router文件夹中index.js路由相关的配置

//配置路由信息

import Vue from 'vue'
import VueRouter from 'vue-router' 
import Home from '../views/Home.vue'

// 1. 调用Vue.use来安装这个vue的插件,前提是引入了Vue(第三行)
Vue.use(VueRouter)


// 这是我们配置url映射关系的地方
const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
  }
]
// 2.创建VueRouter对象
const router = new VueRouter({
  routes
})

// 3.将router对象传入到Vue实例
export default router

配置路由的映射关系

  1. 创建路由组件
  2. 配置路由映射:组件和路径映射关系

在router文件夹中的index.js文件中的配置关系

//导入组件
import Home from "../components/Home"
import About from "../components/About"

const routes = [
    {
        path:'/home',
        component:Home
    },
    {
        path:'/about',
        component:About
    }
]
  1. 使用路由:通过和

在app.vue文件中

<template>
  <div id="app">
       <router-view></router-view>
    <router-link to="/home">首页</router-link>
    <router-link to="/about">关于</router-link>
 
  </div>
</template>

路由的默认路径

  • 即一打开网页就到某个组件处

这里我们同样需要在router里面定义,

const routes = [
	{
		path:'/',
		// redirect重定向
		redirect:'/home'
	}
    {
        path:'/home',
        component:Home
    },
    {
        path:'/about',
        component:About
    }
]

修改哈希模式

在我们更改路径时会有“#”的出现,只要我们将模式从哈希更改为history模式即可

在创建VueRouter对象时候设置

// 2.创建VueRouter对象
const router = new VueRouter({
  routes,
  mode:'history'
})

使用

<router - link>

  • tag属性

默认情况下,我们这个标签会渲染成a标签,但是我们可以利用它的tag属性改变它的标签

tag="button"这时候就会变成一个按钮

 <router-link to="/home" tag="button">首页</router-link>
  • replace

有时候我们不希望后退和前进按钮的出现,就利用replace标签

  • active-class属性

修改被点击时候的默认名,在结合CSS使用时很方便

active-class = “actived”

<router-link to="/home" tag="button" active-class="actived">首页</router-link>
<router-link to="/home" tag="button" active-class="actived">关于</router-link>

有时候我们不希望大量标签都要写上active-class,所以我们可以在index.js中修改被点击后的组件默认的名称

const router = new VueRouter({
  routes,
  mode:'history',
  linkActiveClass:'actived'
})

代码实现路由

<template>
  <div id="app">
       <router-view></router-view>
    <!-- <router-link to="/home" tag="button" replace>首页</router-link>
    <router-link to="/about" tag="li" replace>关于</router-link> -->
  <button @click="homeBtn">首页</button>
 <button @click="aboutBtn">关于</button>
  </div>
</template>

<script>
export default{
    name:'App',
    methods: {
      homeBtn(){
       //这里的router就是index.js文件中的变量名const router
        //this.$router.push('/home')有返回按键的
        this.$router.replace('/home').catch(err=>[])
        console.log("home")
      },
        aboutBtn(){
        this.$router.replace('/about').catch(err=>[])
        console.log("about")
      },
    }
  }
</script>

动态路由

有时候我们需要加载用户界面,我们是需要根据用户id来跳转的

首先我们需要在index.js中配置用户
  • 变量名 是规定的
 {
    path:'/user/:userId',
    component:User
  },

data中的数据

data(){
      return{
      userId:"Joseph"
      }

模板中我们要使用v-bind来使用变量

<template>
  <div id="app">
  

    <router-link v-bind:to="/user/+userId"  tag="button" replace>我的</router-link>
         <router-view></router-view>

  </div>
</template>

我们从父组件里面获取数据在子组件user中进行展示

User.vue文件中我们进行展示

<template>
  <div>
      <h2>我是用户</h2>
      <p>我是用户的相关信息</p>
      <h3>{{userId}}</h3>
      <h3>{{$route.params.userId}}</h3>
  </div>
</template>

<script>
export default {
    name:"User",
    computed: {
        userId(){
            // 这里拿到的route是路由表中处于活跃状态的路由
            // 活跃状态就是指你当前显示(使用)的哪个组件
                return this.$route.params.userId
            }
    }
}

</script>

$router 和 $route不一样

前者是我们获取我们的VueRouter,后者是我们获取当前活跃状态的路由

路由的懒加载

由于我们的bundle.js的资源过大(因为各种打包底层代码转换都在里面),我们并不希望一打开加载资源要很很久,即有一个页面 空白期

  • 所以如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了

实质:将不同的路由打包到不同的JS文件即可

写法我们只需要在index.js中的路由表修改写法即可

const routes = [

    {
        path:'/',
        redirect: '/home'
    },
    {
        path:'/user/:userId',
        //新写法
        component:()=>import('../components/User')
    },
    {
        path:'/home',
        component:()=>import('../components/Home')
    },
    {
        path:'/about',
        component:()=>import('../components/About')
    }
]

在这里插入图片描述

或者说我们一开始定义变量为一个导入的语句

const Home =  ()=> import('../components/Home');
const About = ()=> import('../components/About');
const User = ()=> import('../components/User');

const routes = [
  {
    path:'/',
    redirect: '/home'
  },
  {
    path:'/user/:userId',
    component:User
  },
 {
  path:'/home',
  component:Home
 },
 {
  path:'/about',
  component:About
 }
]

路由的嵌套使用

  • 比如我们在home/news和home/message访问一些内容
  • 一个路径映射一个组件,访问这两个路径也会分别渲染两个组件

实现嵌套路由有两个步骤:

  1. 创建对应的子组件,并且在路由映射中配置对应的子路由

这里我们创建了HomeNews和HomeMessage两个vue组件,引入方式如下

const HomeNews = ()=> import('../components/HomeNews');
const HomeMessage = ()=> import('../components/HomeMessage');
//我们在路由表中的Home的childern进行添加
{
  path:'/home',
  component:Home,
  childern:[
    {
      path:'news',
      component:HomeNews
    },
    {
      path:'message',
      component:HomeMessage
    }
  ]
 }

注意:这里的子路径path前面不用加 “ / ”,因为是相对路径

  1. 在组件内部使用标签

这里我们就需要在home组件的模板中添加标签

Home.vue文件中的模板

<template>
    <div>
        <h2>我是首页</h2>
        <p>
            我是首页内容
        </p>
        <router-link to="/home/news" tag="button">新闻</router-link>
        <router-link to="/home/message" tag="button">消息</router-link>
        <router-view></router-view>
    </div>
</template>

注意:这里的to我们要用绝对路径

同样,我们给其一个进入页面的默认路径

 children:[
    {
      path:'',
      redirect: 'news'

    },
    ...
   ]

参数传递

  • 在动态路由时,我们用到了$route.params.userId,这是其中一直传递参数的方式

我们传递参数主要有两种类型 :params和quert

  • params的类型

    • 配置路由格式: /router/:id
    • 传递的方式:在path后面跟上对应的值(router-link标签里面to属性的字符串拼接)
    • 传递后形成的路径: /router/123 , /router/abc
  • query

    • 配置路由格式:/router,也就是普通配置
    • 传递的方式:对象中使用query的key作为传递方式
    • 传递后形成的路径: /router?id=123, /router?id=abc
     <router-link :to="{path:'/profile',query:{name:userId,age:19,height:1.70}}" tag="button" replace>档案</router-link>
    

http://localhost:8080/profile?name=Joseph&age=19&height=1.7

URL: 协议://主机:端口/路径?查询#片段

​ scheme://host:port/path?query#fragment

那么我们如何从query中取信息呢?

this.$route.query我们就可以取到这个对象

<template>
  <div>
      <h2>
          我是Profile
      </h2>
      <span>
          {{this.$route.query}}
      </span>
  </div>
</template>

<script>
export default {
    name:'Profile'
}
</script>

导航守卫

  • 有时候我们想要对组件来换跳转进行监听,按照以前的方法我们会采用生命周期,created,mouted,updated,当被创建,挂载和数据更新的时候执行的回调函数
  • 现在的需求:点击组件,document.title会改变,我们可以在生命周期函数里面回调,但是这样会在每个组件中都写

所以我们利用的我们全局导航守卫

首先我们要给每个路由都定义一下元数据(描述数据的数据)meta

const routes = [

  {
    path:'/',
    redirect: '/home',
    meta:{
      title:'首页'
    }
  },
  {
    path:'/user/:userId',
    component:User,
    meta:{
      title:'用户'
    }
  },
  {
    path:'/home',
    component:Home,
    children:[
      {
        path:'',
        redirect: 'news'

      },
      {
        path:'news',
        component:HomeNews
      },
      {
        path:'message',
        component:HomeMessage
      }
    ],
    meta:{
      title:'首页'
    }
  },
  {
    path:'/about',
    component:About,
    meta:{
      title:'关于'
    }
  },
  {
    path:'/profile',
    component:Profile,
    meta:{
      title:'用户档案'
    }
  }
]

然后我们利用导航守卫

//这是VueRouter对象
const router = new VueRouter({
  routes,
  mode:'history',
  linkActiveClass:'actived'
})

//前置钩子、守卫(需要主动调用next()函数)
router.beforeEach((to,from,next)=>{
    
   	//实现需求的代码
    document.title = to.meta.title
    
    //这个next()一定要写,不写的话router路由器中所有的组件都无法跳转
    //调用该方法后,才能进入下一个钩子
    next();
    
    //有时候我们也不希望用户直接跳转,比如登录注册
    //我们可以加一些条件判断,然后跳转到对应的路径
    //比如if(){next('/login')}
    
})

注意

当我们进去第一个得到的首页标题是undefined,这是由于路由的嵌套造成的

我们打印to,发现里面有一个matched数组,matcher[0]的path是’/home’,matcher[1]的path是’/home/news’,所以我们要更改一下document.title = to.matched[0].meta.title

后置钩子、守卫

router.afterEach((to,from)=>{

})

以上我们用的都是全局守卫,除此之外还有

  • 路由独享的守卫
const routes = [

  {
    path:'/user/:userId',
    component:User,
    meta:{
      title:'用户'
    },
    beforeEnter:(to,from,next)=>{
    	...
    	next()
    }
  },
 	...
 ]
  • 组件内的守卫(文档使用)

keep-alive

  • 注意:当我们切换组件的时候,是没有东西保留下来的,所以每次切换组件都会调用他们生命周期函数中的create函数,也就是每次都是创建。

    • 因此我们组件内部存在一个destoryed()这样一个周期函数
  • keep-alive是Vue内置的一个组件,可以使包含的组件保留状态,或避免重新渲染

  • router-view 也是一个组件(是new vue-router时候定义的),如果直接被包在keep-alive里面,所有路径匹配到的视图组件都会被缓存

         <keep-alive>
            <router-view></router-view>
         </keep-alive>

现在需求:进入首页默认是显示新闻,先点击首页消息,然后点击用户,再回到首页的时候,看到的是首页消息

这个可以用我们之前提到的导航守卫,活跃状态函数来解决

在home.vue中

<template>
    <div>
        <h2>我是首页</h2>
        <p>
            我是首页内容
        </p>
        <router-link to="/home/news" tag="button">新闻</router-link>
        <router-link to="/home/message" tag="button">消息</router-link>
        <router-view></router-view>
    </div>
</template>

<script>
export default {
        name:"Home",
        data(){
            return{
                path:'/home/news'
            }
        },
        created () {
            console.log("created")
        },
        destroyed () {
            console.log("destory")
        },

    //下面这两个函数是在keep-alive情况下才是有效的
        activated () {
          console.log("HOME组件正处于活跃中");
          this.$router.push(this.path).catch(err=>{})
            //这里要.catch的原因是避免/home/news这个路径重复提交路由控制台报错
        },
        deactivated () {
            console.log("HOME组件在缓存中休息中")
        },

        beforeRouteLeave(to,from,next){
            console.log(this.$route.path);
            this.path = this.$route.path

            next();
        }
    }
</script>

注意:有时候我们并不希望app里面所有的组件都被缓存,比如档案一些我们是希望能够重新create,这时候我们有两个非常重要的属性

  • include - 字符串或正则表达,照顾匹配的组件会被缓存

  • exclude - 字符串或正则表达式,任何匹配的组件都不会被缓存

  • 里面放的字符串是我们每个vue组件导出时候的name属性

         <keep-alive exclude="Profile,User">
            <router-view></router-view>
         </keep-alive>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值