Vue2笔记(五)Vue-Router

Vue Router

什么是前端路由

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

路由器提供了两种机制: 路由和转送.
路由是决定数据包从来源到目的地的路径.
转送将输入端的数据转移到合适的输出端.

路由中有一个非常重要的概念叫路由表.
路由表本质上就是一个映射表, 决定了数据包的指向.

二、前端渲染和后端渲染
1、后端渲染
如jsp,后端渲染好网页再传给前端

2、后端路由
后端处理url和页面之间的映射关系

3、前后端分离
后端只负责提供数据,不负责任何阶段的内容
ajax出现后出现的前后端分离模式
后端只提供api来返回数据,前端通过ajax获取数据,并且可以通过JavaScript将数据渲染到页面
ios和android出现后,后端不需要进行任何处理,依然使用之前的一套api即可

4、前端渲染
浏览器中显示的网页中的大部分内容,都是由前端写的js代码在浏览器中执行,最终渲染出来的网页。

5、单页面富(SPA)应用阶段
在前后端分离的基础上加了一层前端路由
也就是前端来维护一套路由规则
整个网站只有一个html页面

三、url的hash和html的history

前端路由的核心:改变url,但是页面不进行整体的刷新

1、依靠改变url的hash实现

​ URL的hash也就是锚点(#), 本质上是改变window.location的href属性.
​ 我们可以通过直接赋值location.hash来改变href, 但是页面不发生刷新

2、Html5的history.pushState()实现

 history.pushState({},'','home')

3、Html5的history.replaceState()实现

由于是替换,所以,无法再浏览器中返回

4、Html5的history.go()实现

此外还有
history.go(n):
history.back():等价于history.go(-1)
history.forward():等价于history.go(1)

路由的基本配置

路由的安装

npm install vue-router --save

使用步骤

1.创建路由组件
在组件文件夹中创建Home.vue和About.vue组件模板
Home.vue

<template>
<div>
  <h2>我是首页</h2>
  <h4>我是首页内容,哈哈哈哈</h4>
</div>
</template>

<script>
export default{
  name:"Home"//模板名称
}
</script>

<style>
</style>

About.vue

<template>
<div>
<h2>我是关于</h2>
  <h4>我是关于页的内容,呵呵呵呵</h4>
</div>
</template>

<script>
export default{
  name:'About'//模板名称
}
</script>

<style>
</style>

2.配置组件和路径的映射关系

在router目录下的index.js中进行配置
要先导入home和about两个组件模板
创建router对象数组

import Vue from 'vue'
import Router from 'vue-router'
//导入home和about两个模板文件
import Home from '../components/Home'
import About from '../components/About'
//1、通过Vue.use(插件),安装插件
Vue.use(Router);

//2、创建Router对象
const routes = [
  //一个对象就是一个映射关系
  {
    path: '/home',//路径对应根/home
    component:Home
  },
  {
    path: '/about',//路径对应根/about
    component:About
  }
];

const router = new Router({
  routes
});

export default router;

3.使用路由

main.js引入

import Vue from 'vue'
import App from './App'
import router from './router'

Vue.config.productionTip = false

new Vue({
  el: '#app',
  router,
  render: h => h(App)
})

通过和
在App.vue模板文件中插入刚才创建并配置好的路由组件
router-link是vue默认的全局组件,可以只接拿来使用

和用来控制切换
同时添加to属性,指向各模板文件对应的路径
用于显示切换过来的自定义组件(home和about)

App.vue

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

  </div>
</template>

<script>
export default {
  name: 'App',
  components: {
      
  }
}
</script>

<style> 
</style>

细节处理

路由的默认路径和history

让路径默认跳转到首页,并且router-view渲染首页文件
只要多配置一个映射即可

 //设置默认首页
const routes ={
    path: '/',
    component:Home
  }
// 但更简洁的方式是使用重定向到/home映射上去
const routes = {
    path: '/',
    redirect:'/home'
  }

在index.js中直接修改路由的配置模式为history(不显示路径中的#)

const router = new Router({
  routes,
  //配置浏览器地址栏模式
  mode:'history'
});

export default router;
router-link补充

还有一些其他属性:
tag: tag可以指定之后渲染成什么组件, 比如上面的代码会被渲染成一个

  • 元素, 而不是
    replace: replace不会留下history记录, 所以指定replace的情况下, 后退键返回不能返回到上一个页面中
    active-class: 当对应的路由匹配成功时, 会自动给当前元素设置一个router-link-active的class, 设置active-class可以修改默认的名称.
  • <router-link to="/home" tag="button" replace active-class="active">首页</router-link>
    

    修改linkActiveClass的名称

    在index.js中修改

    const router = new VueRouter({
    
     *// 配置路由和组件之间的应用关系*
    
     routes,
    
     mode: 'history',
    
     linkActiveClass: 'active'
    
    })
    
    路由代码跳转
    <template>
      <div id="app">
        <router-link to="/home" tag="button">首页</router-link>
        <router-link to="/about" tag="button">关于</router-link>
        <router-view></router-view>
        <button @click="homeClick">首页</button>
        <button @click="aboutClick">关于</button>
    
      </div>
    </template>
    
    <script>
    export default {
      name: 'App',
      methods: {
        homeClick(){
          //通过代码的方式修改路径,最终要通过router-link来实现
          this.$router.push('/home').catch(err => err)
        },
        aboutClick(){
          if (this.$route.path != "/about") {
            this.$router.replace("/about");
          }
        }
      },
    }
    </script>
    
    <style>
    .myactive {color:red}
    </style>
    
    
    路由的懒加载
    • 由于打包后的JavaScript非常大,需要分割开来进行加载
    • 生产环境一个路由对应一个页面级组件,对应打包一个js文件
    • 这样可以需要使用的时候再加载
    • 懒加载在注册组件的时候在import进来
      即时加载的代码
    • 这样打包的时候就分开文件打包了
    // 配置路由相关的信息
    import VueRouter from 'vue-router'
    import Vue from 'vue'
    
    // import Home from '../components/Home'
    // import About from '../components/About'
    // import User from '../components/User'
    
    const Home = () => import('../components/Home')
    const About = () => import('../components/About')
    const User = () => import('../components/User')
    
    // 1.通过Vue.use(插件), 安装插件
    Vue.use(VueRouter)
    
    // 2.创建VueRouter对象
    const routes = [
      {
        path: '',
        // redirect重定向
        redirect: '/home'
      },
      {
        path: '/home',
        component: Home
      },
      {
        path: '/about',
        component: About,
      },
      {
        path: '/user/:id',
        component: User,
      }
    ]
    const router = new VueRouter({
      // 配置路由和组件之间的应用关系
      routes,
      mode: 'history',
      linkActiveClass: 'active'
    })
    // 3.将router对象传入到Vue实例
    export default router
    

    懒加载的方式

    方式一: 结合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’)

    动态路由

    实现组件页面动态绑定一个id页面

    创建一个模板页面user.vue
    <template>
      <div>
        <h2>我是用户页面</h2>
        <p>用户页面的内容</p>
      </div>
    </template>
    <script>
    export default {
      name:'User',
    }
    </script>
    <style>
    
    </style>
    
    修改主模板页面.vue

    数据部分:
    这里手动指定一个userid:‘zhangsan‘的对象数据

    <script>
    export default {
      name: 'App',
      data(){
        return {
          userid:'zhangsan'
        }
      },
      methods: {
        homeClick(){
          //通过代码的方式修改路径,最终要通过router-link来实现
          this.$router.push('/home')
        },
        aboutClick(){
          this.$router.replace('/about')
        }
      },
    }
    

    模板部分:

    需要绑定数据,注意绑定格式,/user/是原始字符串,要用单引号括住再连接data数据userid

     <router-link :to="'/user/'+userid" tag="button">用户</router-link>
    

    完整app.vue页面

    <template>
      <div id="app">
        <router-link to="/home" tag="button">首页</router-link>
        <router-link to="/about" tag="button">关于</router-link>
        <router-link :to="'/user/'+userid" tag="button">用户</router-link>
        <router-view></router-view>
        <button @click="homeClick">首页</button>
        <button @click="aboutClick">关于</button>
    
      </div>
    </template>
    
    <script>
    export default {
      name: 'App',
      data(){
        return {
          userid:'zhangsan'
        }
      },
      methods: {
        homeClick(){
          //通过代码的方式修改路径,最终要通过router-link来实现
          this.$router.push('/home')
        },
        aboutClick(){
          this.$router.replace('/about')
        }
      },
    }
    </script>
    
    <style>
    .myactive {color:red}
    </style>
    
    修改index.js添加映射关系

    在index中导入User组件在路径中需要连接userid,格式为:userid

    {
        path: '/user/:userid',//路径对应根/user
        component:User
      },
    

    index.js完整代码

    import Vue from 'vue'
    import Router from 'vue-router'
    //导入home和about两个模板文件
    import Home from '../components/Home'
    import About from '../components/About'
    import User from '../components/User'
    
    //1、通过Vue.use(插件),安装插件
    Vue.use(Router);
    
    //2、创建Router对象
    const routes = [
      //一个对象就是一个映射关系
      {
        path: '/home',//路径对应根/home
        component:Home
      },
      {
        path: '/about',//路径对应根/about
        component:About
      },
      {
        path: '/user/:userid',//路径对应根/user
        component:User
      },
      //设置默认首页
      {
        path: '/',
        redirect:'/home'
      }
    ];
    
    
    const router = new Router({
      routes,
      //配置浏览器地址栏模式
      mode: 'history',
      //设置active-class
      linkActiveClass:'myactive'
    });
    
    export default router;
    
    
    使用计算属性动态绑定页面数据

    user.vue页面,
    注意这里使用了this.$route.param来拿当前路由参数

    来那当前路由参数

    <template>
      <div>
        <h2>我是用户页面</h2>
        <p>用户页面的内容</p>
        <div>userid</div>
    	<div>$route.params.userid</div>
      </div>
    </template>
    <script>
    export default {
      name:'User',
      computed:{
        userid(){
          //$router拿到的是index.js页面中定义的routes对象数组
          //this.$router是当前活跃路由
          //注意这里使用的事$route不是之前使用的$router
          return this.$route.params.userid
        }
      },
    }
    </script>
    <style>
    
    </style>
    

    参数传递

    传递参数主要有两种类型: params和query
    params的类型:
    配置路由格式: /router/:id
    传递的方式: 在path后面跟上对应的值
    传递后形成的路径: /router/123, /router/abc
    query的类型:
    配置路由格式: /router, 也就是普通配置
    传递的方式: 对象中使用query的key作为传递方式

    <button @click=“profileClick”>档案

    profileClick() {
          this.$router.push({
            path: '/profile',
            query: {
              name: 'kobe',
              age: 19,
              height: 1.87
            }
          })
        }
    

    传递后形成的路径: /router?id=123, /router?id=abc

    r o u t e 和 route和 routerouter是有区别的
    r o u t e r 为 V u e R o u t e r 实 例 , 想 要 导 航 到 不 同 U R L , 则 使 用 router为VueRouter实例,想要导航到不同URL,则使用 routerVueRouterURL使router.push方法
    $route为当前router跳转对象里面可以获取name、path、query、params等

    路由嵌套

    类似于一个路径分成两个部分(频道/子频道)如/home/news和/home/message访问一些内容
    一个路径映射一个组件,访问这个两个路径分别渲染两个组件

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

    创建两个新的子路由模板HomeNews.vue及HomeMessage.vue

    HomeNews.vue

    <template>
      <div>
        <ul>
          <li>新的一条消息</li>
          <li>老的一条消息</li>
          <li>看过的消息</li>
          <li>没看过的消息</li>
        </ul>
      </div>
    </template>
    <script>
    export default {
      name:'HomeNews'
    }
    </script>
    <style>
    
    </style>
    

    *HomeMessage.vue

    <template>
      <div>
        <ul>
          <li>教育部新闻</li>
          <li>工信部新闻</li>
          <li>农业农村部新闻</li>
          <li>社会保障部新闻</li>
        </ul>
      </div>
    </template>
    <script>
    export default {
      name:'HomeMessage'
    }
    </script>
    <style>
    
    </style>
    
    在主路由index.jx中导入模板对象并在路由对象中添加子路由(嵌套添加)

    通过添加children数组的形式添加子路由

    • 同时可以设置默认子路由的显示
    const HomeNews = () => import('../components/HomeNews');
    const HomeMessage = () => import('../components/HomeMessage');
    
    const routes = [
      //一个对象就是一个映射关系
      {
        path: '/home',//路径对应根/home
        component: Home,
        //添加嵌套子路由
        children: [
          {
            path: 'news',//由于是子路由,不用再加斜杠/了
            component:HomeNews
          },
          {
            path: 'message',//由于是子路由,不用再加斜杠/了
            component:HomeMessage
          },
          //设置默认首页
          {
            path: '',
            redirect:'/home/news'
          }
          
        ]
      },
      {
        path: '/about',//路径对应根/about
        component:About
      },
      {
        path: '/user/:userid',//路径对应根/user
        component:User
      },
      //设置默认首页
      {
        path: '/',
        redirect:'/home'
      }
    ];
    
    在父路由组件内部使用标签

    由于子路由是在Home路由模板中应用,应当在Home路由模板上添加子和

    <template>
    <div>
      <h2>我是首页</h2>
      <h4>我是首页内容</h4>
      <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>
    
    <style>
    </style>
    

    导航守卫

    实际上就是个回调函数
    利用声明周期的钩子函数来修改组件的title
    使用beforeEach()监听路由跳转

    • 1、给每个路由添加一个meta对象,并设定一个title
    meta: {
          title:'用户'
        }
    

    2、使用beforeEach添加导航守卫
    beforeEach()需要三个参数,to,from,netxt:
    to.matched[0]是因为参数了路由嵌套,导致第一个链接拿不到meta元素
    因此要去拿上一级的matched标签数组,第一个元素包含多了meta元素。在进一步拿到title,最后去修改document的title
    导航钩子的三个参数解析:
    to: 即将要进入的目标的路由对象.
    from: 当前导航即将要离开的路由对象.

    • next: 调用该方法后, 才能进入下一个钩子.
    router.beforeEach(function (to, from, next) { 
      //使用目标(to)组件的meta.title修改当前文档的title标签
      document.title = to.matched[0].meta.title;
      console.log(to);
      //调用父级next()
      next();
    })
    

    后置钩子
    beforeEach是前置钩子,afterEach后置钩子,不需要主动调用next()进入到下一个钩子

    //后置钩子,不需要主动调用next()函数,只有连个参数
    router.afterEach((to,from) => { 
      console.log('------');
    })
    

    独享守卫和组件内的守卫(guard)

    keep-alive及其他问题

    keep-alive是vue的一个内置组件,在这个标签内的所有vue组件呈现保留状态(即不会被重新渲染)
    有两个非常重要的属性

    include:字符串或正则表达式,只有匹配的组件会被缓存
    exclude:字符串或正则表达式,任何匹配的组件都不会被缓存包含

    <keep-alive>
    	<router-view>
    	     //所有匹配的组件都会被缓存
    	</router-view>
    </keep-alive>
    

    排除(exclude中逗号后面不能空格)

    正则表达式中逗号后面也不要空格

    <keep-alive exclude='Profile,User'>
    	<router-view>
    	     //所有匹配的组件都会被缓存
    	</router-view>
    </keep-alive>
    

    router-view也是一个组件,如果被直接抱在keep-alive里面,所有路径匹配到的视图组件都会被缓存(不会被重新渲染)

    通过create生命周期函数(钩子函数)来验证

    home.vue

    <template>
      <div>
        <h2>我是首页</h2>
        <p>我是首页内容, 哈哈哈</p>
    
        <router-link to="/home/news">新闻</router-link>
        <router-link to="/home/message">消息</router-link>
    
        <router-view></router-view>
    
        <h2>{{message}}</h2>
      </div>
    </template>
    
    <script>
      export default {
        name: "Home",
        data() {
          return {
            message: '你好啊',
            path: '/home/news'
          }
        },
        created() {
          console.log('home created');
        },
        destroyed() {
          console.log('home destroyed');
        },
        // 这两个函数, 只有该组件被保持了状态使用了keep-alive时, 才是有效的
        activated() {
          this.$router.push(this.path);
          console.log('activated');
        },
        deactivated() {
          console.log('deactivated');
        },
        beforeRouteLeave (to, from, next) {
          console.log(this.$route.path);
          this.path = this.$route.path;
          next()
        }
      }
    </script>
    
    <style scoped>
    
    </style>
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值