6

万字血书Vue—路由 - 辜负寒彻骨

 1 year ago
source link: https://www.cnblogs.com/gfhcg/p/17232523.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

万字血书Vue—路由

image


多个路由通过路由器进行管理。

前端路由的概念和原理#

(编程中的)路由(router)就是一组key-value对应关系,分为:后端路由和前端路由

后端路由指的是:请求方式、请求地址function处理函数之间的对应关系

在SPA程序中,所有组件的展示和切换都在这唯一的一个页面内完成,此时,不同组件之间的切换需要通过前端路由来实现

通俗易懂的来说,前端路由是:Hash地址(url中#的部分)与组件之间的对应关系

前端路由的工作方式#

  • 用户点击了页面上的路由链接
  • 导致了URL地址栏中的Hash值发生了变化
  • 前端路由监听到了Hash地址的变化
  • 前端路由把当前Hash地址对应的组件渲染到浏览器中

image

实现简易的前端路由(底层实现原理)#

App.vue根组件

<template>
  <div>
    <h1>这是App根组件</h1>
    <a href="#/Home">Home</a> 
    <a href="#/Movie">Movie</a> 
    <a href="#/About">About</a> 
    <hr>

    <component :is="comName"></component>
  </div>
  
</template>

<script>
import MyHome from './MyHome.vue'
import Mymovie from './MyMovie.vue'
import MyAbout from './MyAbout.vue'
import { walkFunctionParams } from '@vue/compiler-core'

export default {
    name:'App',
    components:{
        MyHome,
        MyAbout,
        Mymovie,
    },
    data(){
        return{
            comName:'MyHome'
        }
    },
    created(){
        window.onhashchange=()=>{
            switch(location.hash){
                case '#/Home':
                    this.comName='MyHome'
                    break
                 case '#/Movie':
                    this.comName='MyMovie'
                    break
                 case '#/About':
                    this.comName='MyAbout'
                    break
            }
        }
    }

}
</script>

<style lang="less" scoped>

</style>

vue-router的基本使用#

vue-router是vue.js官方给出的路由解决方案,它只能结合vue项目进行使用,能够轻松的管理SPA项目中的组件切换。

二者差异主要是在声明router配置文件上。

vue-router 3.x的基本使用步骤#

  • 在项目中安装vue-router
npm install [email protected] -S
  • src源代码目录下,新建router/index.js路由模块
//导入包
import Vue from 'vue'
import VueRouter from 'vue-router'
//插件引入
Vue.use(VueRouter)
//创建路由的实例对象
const router = new VueRouter
//向外共享
export default router
  • 在入口文件main.js中引入
import router from '@/router/index.js'
......
new Vue({
    ...
    router:router
    ...
}).$mount('#app')

vue-router 4.x的基本使用步骤#

  • 在项目中安装vue-router
npm install vue-router@next -S
  • 定义路由组件

MyHome.vue、MyMovie.vue、MyAbout.vue

  • 声明路由链接占位符

可以使用<router-link>标签(会被渲染成a链接)来声明路由链接,并使用<router-view>标签来声明路由占位符

<template>
  <div>
    <h1>这是App根组件</h1>
   <!--  <a href="#/Home">Home</a> 
    <a href="#/Movie">Movie</a> 
    <a href="#/About">About</a>  -->
      
   <!-- 声明路由链接 -->
    <router-link to="/home">首页</router-link>
     <router-link to="/movie">电影</router-link>
      <router-link to="/about">我的</router-link>
    <hr>
   <!-- 路由占位符 -->
   <router-view></router-view>
    <component :is="comName"></component>
  </div>
  
</template>
  • 创建路由模块

从项目中创建router.js路由模块,按照以下四步:

从vue-router中按需导入两个方法

import { createRouter, createWebHashHistory } from 'vue-router'
//createRouter方法用于创建路由的实例对象
//createWebHashHistory用于指定路由的工作方式(hash模式)

导入需要使用路由控制的组件

import MyHome from './MyHome.vue'
import MyMovie from './MyMovie.vue'
import MyAbout from './MyAbout.vue'

创建路由实例对象

const router = createRouter({
history: createWebHashHistory(),
routes: [
  {
      path: '/home', component: MyHome
  },
  {
      path: '/movie', component: MyMovie
  },
  {
      path: '/about', component: MyAbout
  },

]
})

向外共享路由实例对象

export default router

在main.js中导入并挂载路由模块

import { createApp } from 'vue'
import App from './App.vue'
import './index.css'

import router from './components/router'

const app = createApp(App)
//挂载路由写法
app.use(router)
app.mount('#app')

  • 导入并挂载路由模块

vue-router的高级用法#

路由重定向

指的是:用户在访问地址A的时候,强制用户跳转到地址C,从而展示特点的组件页面

通过路由规则的redirect属性,指定新的路由地址

const router = createRouter({
    history: createWebHashHistory(),
    routes: [
        {
            path: '/home', component: MyHome
        },
        {
            path: '/',redirect:'/home' //访问根路径会重定向到home组件
        },
        {
            path: '/movie', component: MyMovie
        },
        {
            path: '/about', component: MyAbout
        },

    ]
})

query参数

<router-link :to="/about/home/message?id=123&title='abc'">我的</router-link>

<router-link :to="{
                 path:'/about/home/message',
                 query:{
                 	id:123,
                 	title:'abc'
                 }
               }">
    我的
</router-link>

params参数

path:'/about/home/message/:id/:title'
<router-link :to="/about/home/message/123/abc">我的</router-link>

<router-link :to="{
                 name:'my',
                 params:{
                 	id:123,
                 	title:'abc'
                 }
               }">
    我的
</router-link>

this.$route 是路由的"参数对象"

this.$router 是路由的"导航对象"

  • 使用默认的高亮class类名

被激活的路由链接,默认会使用router-link-active的类名,开发者可以使用此类名选择器,为激活的路由链接设置高亮样式

  • 自定义路由高亮的class类

在创建路由的实例对象时,开发者可以基于linkActiveClass属性,自定义类名

const router = createRouter({
    history: createWebHashHistory(),
    linkActiveClass:'active-router',
    routes: [
        {
            path: '/home', component: MyHome
        },
        {
            path: '/',redirect:'/home' //访问根路径会重定向到home组件
        },
        {
            path: '/movie', component: MyMovie
        },
        {
            path: '/about', component: MyAbout
        },

    ]
})

通过路由来实现组件的嵌套展示

  • 声明子路由链接和子路由占位符
<template>
  <div>MyAbout组件</div>
  <hr>
  <router-link to="/about/tab1">tab1</router-link> 
  <router-link to="/about/tab2">tab2</router-link>

  <router-view></router-view>
</template>
  • 在父路由规则中,通过children属性嵌套声明子路由规则
const router = createRouter({
    history: createWebHashHistory(),
    routes: [
        {
            path: '/home', component: MyHome
        },
        {
            path: '/movie', component: MyMovie
        },
        {
            path: '/about', component: MyAbout,children:[
                {
                path:'tab1',component:Tab1
            },
            {
                path:'tab2',component:Tab2
            },
        ]
        },

    ]
})

子路由规则的path不要以/开头

在嵌套路由中实现路由的重定向

const router = createRouter({
    history: createWebHashHistory(),
    routes: [
        {
            path: '/home', component: MyHome
        },
        {
            path: '/movie', component: MyMovie
        },
        {
            path: '/about',
            component: MyAbout,
            redirect:'/about/tab1',
            children:[
                {
                path:'tab1',component:Tab1
            },
            {
                path:'tab2',component:Tab2
            },
        ]
        },

    ]
})
动态路由匹配

指的是:把Hash地址中可变的部分定义为参数项,从而提高路由规则的复用性,在vue-router中使用英文冒号:来定义路由的参数

  {   
      path: '/movie/:id', component: MyMovie
   },

获取动态路由参数值的方法:

  • $route.params参数对象
<template>
  <div>Mymovie组件---{{$route.params.id}}</div>
  
</template>
  • 使用props接受路由参数
{
     path: '/movie/:id', component: MyMovie,
     props: true,
},

为了简化路由参数的获取形式,vue-router允许在路由规则开启props传参

编程式导航

通过调用API实现导航的方式,叫做编程式导航,与之对应的,通过点击链接实现导航的方式,叫做声明式导航

  • 普通网页中点击a链接,vue项目中点击<router-link>都属于声明式导航
  • 平台网页中调用location.herf跳转到新页面的方式,属于编程式导航

vue-router中编程式导航API

  • this.$router.push('hash地址') 跳转到指定Hash地址,并增加一条历史记录,从而展示对应的组件。
  • this.$router.replace('hash地址') 跳转到指定Hash地址,并替换当前的历史记录,从而展示对应的组件。
  • this.$router.go('数值n') 实现导航历史的前进、后退(-1),超过最大层数,则原地不动。

$router.back() 后退到上一层页面

$router.forward() 前进到下一层页面

通过name属性为路由规则定义名称,叫做命名路由,name值不能重复,具有唯一性

Hash地址特别长时体现出命名路由的优势

  • 使用命名路由实现声明式导航
<template>
	<h3>
        MyHome组件
    </h3>
    <router-link :to="{name:'mov',params:{id : 3}}">goToMovie</router-link>
</template>

<script>
	export default {
        name:'MyHome',
    }
</script>
  • 使用命名路由实现编程式导航
<template>
	<h3>
        MyHome组件
    </h3>
	<button @click="goToMovie(3)">
        goToMovie
    </button>
</template>

<script>
	export default {
        method: {
            goToMovie(id) {
                this.$router.push({name:'mov',params:{id : 3}})
            }
        }
    }
</script>

导航守卫可以控制路由的访问权限

image

如何声明全局的导航守卫

全局的导航守卫会拦截每个路由规则,从而对每个路由都进行访问权限的控制

const router = createRouter({
   ...
})
//调用路由实例对象的beforeEach函数,fn必须是一个函数吗,每次拦截后,都会调用fn进行处理
//声明全局的导航守卫,fn称为守卫方法
router.beforeEach(fn)
    
router.beforeEach(()=>{
    console.log('Ok')
})

守卫方法的三个形参(可选)

router.beforeEach((to,from,mext)=>{
    console.log('Ok')
    //to 目标路由对象(信息)
    //from当前导航正要离开的路由对象
    //next 是一个函数,表示放行
})

在守卫方法中不声明next形参,则默认允许用户访问每一个路由

在守卫方法中声明了next形参,则必须调用next()函数,否则不允许用户访问如何一个路由!

next函数的3种调用方式

//声明全局的导航守卫
router.beforeEach((to, from, next) => {
    if (to.path === '/main') {
        //证明用户要访问后台主页  
        next(false)//强制用户停留在之前所处的组件
        next('login')//强制用户调转到指定页面
    } else {
        //证明用户要访问的不是后台主页 
        next()
    }
})

结合token控制后台主页的访问权限

router.beforeEach((to, from, next) => {
    const tokenStr = localStorage.getItem('token') //读取token


    if (to.path === '/main' && !tokenStr) { //token不存在,需要登录
        //证明用户要访问后台主页  
       // next(false)//强制用户停留在之前所处的组件
        next('login')//强制用户调转到指定页面
    } else {
        //证明用户要访问的不是后台主页 
        next()
    }
})

Hash&History#

路由器的两种工作模式:hash&history

对于url来说:#及后面的内容就是hash值,hash值不会带给服务器。

hash模式:

  1. 地址中永远带着#号,不美观;
  2. 若地址校验严格,会被标记为不合法;
  3. 兼容性较好;

history模式:

  1. 地址干净,美观;
  2. 兼容性比hash模式较差;
  3. 应用部署上线需要后端支持,解决刷新页面服务端404问题;(node可以使用connect-history-api-fallback

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK