21~vue-router的使用

vue-router的使用

基于vite安装和使用vue-router

vue-router是什么

vue-router是基于路由组件的, 路由是用来设定访问路径, 将路径组件映射起来。

vue-router基本使用

01~定义路由文件并导出

src文件夹下面创建一个router文件夹, 写一个index.js, 即src/router/index.js 放置路由文件, 对路由进行集中管理。

src/router/index.js

import { createRouter, createWebHashHistory } from 'vue-router'
/**
 * 为了规范管理,常用的目录结构
 * 1. src下面创建一个router文件夹, 写一个index.js
 * 即src/router/index.js 放置路由文件, 对路由进行集中管理
 * 
 * 
 * 2. src下面新建一个views的文件夹, 对应的路由组件都放在里面
 * 
 */

/**
 * 1. 定义路由组件, 也可以从其他文件导入
 * 
 * 导入组件, 组件后面的.vue可以要, 可以不要
 * 比如 import Home from '../views/Home' 也是可以的
 */
import Home from '../views/Home.vue'
import About from '../views/About.vue'

/**
 * 2. 定义一些路由
 *    每个路由都需要映射到一个组件
 *    点击哪一个路由, 就对应哪一个组件
 * 我们后面再套路嵌套路由
 * 
 * 路由表
 */
const routes = [
  { path: '/', component: Home },
  { path: '/about', component: About }
]
/**
 * 3. 创建路由实例并传递 上面的 'routers'配置
 *    你可以在这里输入更多的配置, 但我们在这里
 *    暂时保持简单
 *    
 *    官网示例中有VueRouter.createRouter, 是因为它是
 *    cdn引入的;  npm安装的, 可以直接使用它的方法 
 *     
 *    方法createRouter和createWebHashHistory都是VueRouter
 *    里面引入进来的
 * 
 */
const router = createRouter({
  /**
   *4. 内部提供了 history 模式的实现,\;
   *   为了简单起见, 我们在这里使用hash模式
   *   路由有两种模式, 一种是hash模式, 一种是history模式
   */
  history: createWebHashHistory(),
  routes, // 'routes:routes' 的简写  配置路由表
})

// 路由文件写好之后, 怎么使用呢? 需要导出, 然后去main.js里面配置
export default router

02~入口main.js中引入并使用路由文件

src/main.js

import './assets/main.css'

import { createApp } from 'vue'
import App from './App.vue'
// 引入了App组件

/**
 * 引入路由文件, 注意, 如果from后面是 './router',
 * 其实默认的是去找里面的index文件,就是'./router/index.js'
 */
import router from './router'

const app = createApp(App)
app.use(router)  // 使用路由要在挂载app前面
app.mount('#app')

03~src创建路由组件

src下面新建一个views的文件夹, 对应的路由组件都放在里面
在这里插入图片描述

04~模版中使用路由

  • 使用 router-link 组件进行导航, 通过传递 to 来指定链接
  • <router-view></router-view>渲染路由匹配到的组件内容
<script setup>
import Content from './components/Content.vue'

</script>
<template>
  <!-- 
    vue-router是基于`路由`和`组件`的, `路由`是用来设定访问路径,
              将`路径`和`组件`映射起来。   
   -->
    <Content />
    <!-- 
      使用 router-link 组件进行导航
      通过传递 to 来指定链接
      <router-link> 将呈现一个带有正确 href 属性的 a 标签
      
      使用一个自定义组件 router-link 来创建链接; 这使得Vue Router可以在不重新
      加载页面的情况下更改Url, 处理Url的生成及编码。

      to="路径"

     -->
    <p>
      <router-link to="/">Go to Home</router-link>
    </p>
    <p>
      <router-link to="/about">Go to About</router-link>
    </p>
    <!-- 路由出口,占位符 -->
    <!-- 路由匹配到的组件将渲染在这里, 组件内容展示的位置
      上面点击Home, 就展示Home的内, 点击About就展示About的内容 
    -->
    <router-view></router-view>
</template>
<style></style>

带参数的动态路由匹配

很多时候, 我们需要将给定匹配模式的路由映射到同一个组件,; 例如: 我们有一个user组件, 它显示用户的详情; 但用户ID不同, 显示的详情内容自然不同, 这个时候就需要动态传一个ID参数。
Vue Router 中, 我们在路径中使用一个动态字段来实现, 我们称之为路径参数

index.js路由文件中

const routes = [ 
  /**
   *  动态字段以冒号开始
   *  路径参数用冒号 `:` 表示, 当一个路由被匹配时, 它的 params的值将在每个组件中以 `this.$route.params` 
   *  的形式暴露出来
   */
  {
    // 多个参数动态路由
    path: '/user/:id/detail/:name',
    component: User
  },
  {
    // 动态路由
    path: '/member/:id',
    component: Member
  }
]

组件中导航路由并传参

<p>
   <router-link to="/user/123/detail/张三">Go to User</router-link>
</p>
<p>
  <router-link to="/member/666">Go to Member</router-link>
</p>

路由组件中获取参数id

  • vue2获取, this.$route.params
<template>
  <!-- vue2的方法获取路由传递过来的参数
       this.$route.params 获取所有参数
  -->
   <div>用户: {{ this.$route.params }}
   ----{{this.$route.params.id  }}
   ---{{this.$route.params.name  }}
   </div>
</template>
  • vue3 setup中获取路由参数
<template>
  <div>用户id: {{ userId }}</div>
</template>
<script setup>
/**
 * vue3 ##serup中获取路由传递过来的参数 
 */
import { useRoute } from 'vue-router';
// 获取所有路由参数
console.log(useRoute().params)
// 获取用户传过来的id
const userId = useRoute().params.id
  
</script>

vue-router的404页面

当前端路径不存在的时候, 我们要默认访问一个404页面, 体验更加友好

在路由组件中定义一个404页面

src/views/NotFound.vue

<template>
  <h2>找不到页面</h2>
</template>

在路由文件的路由表中,添加404组件路由

使用正则的方式,匹配没有路由的404页面

import NotFound from '../views/NotFound.vue'

const routes = [  
  {
    /**
     * 404 路由
     * 使用正则的方式,匹配没有路由的404页面
     * 路由会现在上面找, 如果都没有匹配到, 会配置到下面的404路由
     * (.*) 任意的;    :path(.*) 任意动态的路由都会展示这个页面
     */
    path: '/:path(.*)',
    component: NotFound
  }
]

动态路由参数的正则限制

  • 动态路由的参数必须是数字,当不是数字的时候就会到404页面
{
   // 动态路由的参数必须是数字,当不是数字的时候就会到404页面
   path: '/news/:id(\\d+)',
   component: News
},
  • 动态路由参数可以有多个
{
  // 表示参数可以有多个
  path: '/news/:id+',
  component: News
},
  • 动态路由参数可有可无,但后面可以有多个参数
{
   // 表示参数可有可无,但后面可以有多个参数
   path: '/news/:id*',
   component: News
},
  • 表示参数可有可无,但后面只能有一个参数, 不可以重复叠加,否则404
 {
    // 表示参数可有可无,但后面只能有一个参数, 不可以重复叠加,否则404
    path: '/news/:id?',
    component: News
  },

嵌套路由

嵌套路由就是在一个被路由过来的页面下可以继续使用路由,嵌套也就是路由中路由的意思。
在这里插入图片描述

路由文件的写法

index.js

import StyleOne from '../views/StyleOne.vue'
import StyleTwo from '../views/StyleTwo.vue'

const routes = [  
  {
    path: '/parent',
    component: Parent,
    children: [
      {
        // 这里面的路由不需要再加斜杠了, 访问的时候, 会自动加上
        path: "styleone",
        component: StyleOne
      },
      {
        path: "styletwo",
        component: StyleTwo
      }
    ]
  },  
]

路由组件里面再次写路由

<template>
  <h2>父组件</h2>
  <p>
    <router-link to="/parent/styleone">样式一</router-link>
  </p>
  <p>
    <router-link to="/parent/styletwo">样式二</router-link>
  </p>
  <!--  router-view 这个不要遗漏, 不然再次嵌套的路由不知道把页面渲染在哪-->
  <router-view></router-view>
</template>

路由跳转

路由跳转, 就是点击路由之后, 跳转新内容, 路由跳转包括声明式路由编程式路由

声明式路由

前面用的的, 都是声明式路由

<router-link to="路由地址">点我去首页</router-link>

声明式路由: 路由跳转组件<router-link to='路由地址'>路由跳转</router-link>,在最终编译的时候会编程成<a>路由跳转</a>标签。

使用<router-link>组件使我们的编程很不灵活

  • 用户必须点击触发<router-link>才能实现跳转。
  • 自由度不高,例如:等待1秒再进行路由跳转。
  • <router-link>最终转成<a>标签。如果你想再按钮上进行路由跳转,实现不了。

编程式导航(编程式路由)

编程式路由导航的实质,就是拿到路由器中的api,调用api实现路由的跳转或者其他操作
也叫js跳转页面, 可以记录各种跳转历史, 可以利用浏览器前进和后退页面

问题来了我们怎样拿到路由器

通过组件实例对象,this.$router

  • 这里的this代表vuecomponent实例对象。
  • 这里是通过$router 访问路由实例,这个就是跳转页面(push),返回页面(forword),go方法等操作;
  • $route 少了一个r, 这个表示当前活跃的路由对象, 比如拿到path,params,query,name等。

路由器上的方法:
this.$router.push() //使用push模式跳转

比如, 跳转商品详情页面

this.$router.push('/goods/detail')
  • 字符串形式跳转首页
<template>
  <h2>page页面</h2>
  <div><button @click="goPage">跳转页面</button></div>
</template>
<script>
export default {
  methods:{
    goPage:function()
    {
      console.log('跳转页面处理一些逻辑逻辑, 然后再利用按钮调整',this.$router)  
      // 进行一些逻辑判断, 然后再做页面跳转
      this.$router.push('/')    // 字符串形式跳转首页路由      
    }
  }
}
</script>
  • 传入对象跳转首页路由
<template>
  <h2>page页面</h2>
  <div><button @click="goPage">跳转页面</button></div>
</template>
<script>
export default {
  methods:{
    goPage:function()
    {
      console.log('跳转页面处理一些逻辑逻辑, 然后再利用按钮调整',this.$router)  
      // 进行一些逻辑判断, 然后再做页面跳转    
      this.$router.push({path:'/'}) // 通过传入对象跳转首页路由     
    }
  }
}
</script>
  • 带参数跳转路由
<template>
  <h2>page页面</h2>
  <div><button @click="goPage">跳转页面</button></div>
</template>
<script>
export default {
  methods:{
    goPage:function()
    {
      console.log('跳转页面处理一些逻辑逻辑, 然后再利用按钮调整',this.$router)  
    
      // 带参数
      this.$router.push({path:'/member/123'})     
    }
  }
}
</script>
  • 路由文件里面定义一个name, 然后利用name跳转
{
    name: 'about', // 给路由取一个名字, 通过名字js跳转
    path: '/about',
    component: About
  },
<template>
  <h2>page页面</h2>
  <div><button @click="goPage">跳转页面</button></div>
</template>
<script>
export default {
  methods:{
    goPage:function()
    {
      console.log('跳转页面处理一些逻辑逻辑, 然后再利用按钮调整',this.$router)  
      // 进行一些逻辑判断, 然后再做页面跳转
   
      // 路由里面定义一个name, 然后利用name跳转
      this.$router.push({name:'about'})
    
    }
  }
}
</script>
  • 路由里面定义一个name,通过name带参数跳转
<template>
  <h2>page页面</h2>
  <div><button @click="goPage">跳转页面</button></div>
</template>
<script>
export default {
  methods:{
    goPage:function()
    {
      console.log('跳转页面处理一些逻辑逻辑, 然后再利用按钮调整',this.$router)  
      // 进行一些逻辑判断, 然后再做页面跳转
          
      // 路由里面定义一个name,通过name带参数跳转
      this.$router.push({name:'news',params:{id:123}})     
    }
  }
}
</script>
  • 通过问号(?)的方式传参数跳转
<template>
  <h2>page页面</h2>
  <div><button @click="goPage">跳转页面</button></div>
</template>
<script>
export default {
  methods:{
    goPage:function()
    {
      console.log('跳转页面处理一些逻辑逻辑, 然后再利用按钮调整',this.$router)  
      // 进行一些逻辑判断, 然后再做页面跳转

      // 通过问号(?)的方式传参数跳转
      this.$router.push({path:'news',query:{name:'张三'}})
    }
  }
}
</script>

利用this.$route获取路由传递过来的参数

$route$router少了一个r, 这个表示当前活跃的路由对象, 比如拿到path,params,query,name等。

<template>
  <p>新闻</p>
</template>
<script>
 export default{
  mounted(){
    // 打印当前活跃的路由对象
    console.log('news: ',this.$route)
    // 获取当前传过来的参数
    console.log('?传过来的参数: ',this.$route.query.name)
  }
 }
</script>

替换当前位置

它的作用类似router.push, 唯一不同的是, 它在导航时不会向history添加新纪录, 正如它的名字所暗示的那样—它取代了当前的条目(页面)。

两种写法

  • 声明式
<router-link to="/" replace>Go to Home</router-link>
  • 编程式
router.push({path:'/',replace:true})
//  或下面这种写法
router.replace({path:'/'})

也可以直接传递给router.pushroutelocation中增加一个属性replace:true

历史记录的前进或者后退

history 中进行前进或者后退

// 前进,传入正值,  后退, 传入的值为负值
this.$router.go(1) // 前进一步
this.$router.go(-1) // 后退一步
this.$router.go(-2) // 后退两步,一般就是后推一步
this.$router.back() // 后退一步, 等于 this.$router.go(-1)
this.$router.forword()// 前进一步, 等于 this.$router.go(1)

命名路由

路由命名的有点:

  • 没有硬编码的URL
  • params 的自动编码和解码
  • 防止在url中出现打字错误
  • 绕过路径排序(如显示一个)

路由文件index.js

{
    // 表示参数可以有多个
    name: 'news', // 利用name对路由命名
    path: '/news/:id+',
    component: News
  },

声明式路由: 要链接到一个命名路由, 可以向router-link组件的to属性传递一个对象

 <p>
    <!-- 注意这里要用动态帮忙, 不然后面跟的, 会被识别为一个字符串 -->
    <router-link :to="{name:'news',params:{id:888}}">
       Go to 新闻
    </router-link>
  </p>

**导航式路由**的写法

 this.$router.push({path:'news',query:{name:'张三'}})

命名视图

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

  • 路由文件写法
{
    path: "/shop",
    // 一个路由显示多个视图, 需要用复数
    components: {
      default: About, // 访问这个路由时的默认组件
      /**
       * 名称:组件   这个名称与 `<router-view>` 上的 `name` 属性匹配,
       * 匹配到之后, 就会把对应的组件放到对应占位符的位置
       */
      User: User,
      News: News
    }
  }
  • 视图渲染的写法
<router-view name="User"></router-view>
<router-view name="News"></router-view>
 <!--没有名称的, 名称为name = "default" -->
<router-view></router-view> 

路由重定向

  • 重定向也是通过 routes 配置来完成, 下面例子就是从/重定向到/home:
const routes = [
  {
    path: '/',
    //访问'/'路由, 重定向到 `/home`
    redirect: '/home'
  },
  {
    path: '/home',
    component: Home
  }
]
  • 重定向的目标也可以是一个命名的路由
const routes = [
  {
    path: '/',
    //访问'/'路由, 重定向到 `/home`
    // 通过name来重定向
    redirect: { name: 'home' }

  },
  {
    name: 'home',
    path: '/home',
    component: Home
  }
]
  • 定义一个方法, 动态返回重定向目标
const routes = [
  {
    path: '/',
    //访问'/'路由, 重定向到 `/home`
    // 方法, 
    redirect: (to) => {
      console.log(to) // 利用这个对象, 可以做一个业务判断, 实现动态重定向
      // return { name: 'home' } // 函数这样返回可以
      return { path: '/home' } // 函数这样返回也可以
    }
  },
  {
    name: 'home',
    path: '/home',
    component: Home
  }
]

路由别名

除了通过path路径来访问组件, 有时候path比较复杂, 可以通过取别名(alias)的方式来访问

const routes = [
  {
    path: '/',
    //访问'/'路由, 重定向到 `/home`
    // 方法, 
    redirect: (to) => {
      console.log(to) // 利用这个对象, 可以做一个业务判断, 实现动态重定向
      // return { name: 'home' } // 函数这样返回可以
      return { path: '/homeAlias' } // 函数这样返回也可以
    }

  },
  {
    /**
     * 除了通过path路径来访问组件, 还可以通过取别名(alias)的方式来访问
     */
    name: 'home',
    // alias: '/homeAlias', // 取一个别名
    alias: ['/homeAlias', '/homeSon'], // 可以用数组的形式取多个别名
    path: '/home',
    component: Home
  }
]

路由组件传参接收问题

路由表传参

路由文件(index.js)

const routes = [
   {
    // 带参数的动态路由
    path: '/member/:id',
    component: Member,    
    props: true // 通过使用props: true的配置, 来传递路由参数
  },
]

选项式api接收参数(prop)

<script>
export default{
  props:['id'],
  mounted(){
    console.log('组件传过来的参数id: ',this.$route.params.id)
    console.log('组件传过来的参数id: ',this.id)
  }
}
</script>

组合式api接收路由参数(prop)

<script setup>
/**
 * vue3 ##serup中获取路由传递过来的参数 
 */

// 组合式api中, props的写法
const props = defineProps({
  id:String
})
console.log('vue3_props',props)
console.log('vue3_props',props.id)
  
</script>

命名视图的情况下传参

路由表中 index.js

const routes = [
  {
    // 命名视图, 需要为每个命名视图定义`props`配置,才能传参
    path: "/shop/:id",
    // 一个路由显示多个视图, 需要用复数
    components: {
      default: About, // 访问这个路由时的默认组件     
      User: User,
      News: News
    },
    props: {
      default: true, // 只在About中接受到这个id参数就可以
      User: false, // 不接收路由传过来的参数
      News: false  // 不接收路由传过来的参数
    }
  }
]

不同的历史记录模式

路由模式有两种,二者的区别, Hash模式#号, history模式没有#号。

Hash模式

hash 模式使用createWebHashHistory创建的; 它在内部传递的实际URL之前使用了一个哈希字符(#); 由于这部分URL从未被发送到服务器, 所以它不需要在服务器层面上进行任何特殊处理。不过, 它在SEO中确实有不好的影响。 如果考虑SEO这个问题, 可以使用HTML5模式。

import { createRouter, createWebHashHistory } from 'vue-router'

const router = createRouter({
  history: createWebHashHistory(),
  routes, // 'routes:routes' 的简写  配置路由表
})

HMTL5模式(history模式)

createWebHistory() 创建HTML5模式,推荐使用这个模式

import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory(),
  routes, // 'routes:routes' 的简写  配置路由表
})

使用这种历史模式时, URL会看起来很正常, 例如http://localhost:5173/news/456;

不过, 问题来了? 由于我们的应用是一个单页的客户端应用。 如果没有适当的服务器配置, 用户在浏览器中直接访问http://localhost:5173/news/456, 就会得到一个404错误; 这样就不友好了。

不用担心, 要解决这个问题, 需要做的就是在您的服务器上**添加一个简单的回退路由**。如果URL不匹配任何静态资源, 它应提供与您的应用程序中的index.html 相同的页面。

history的nginx配置

location / { 
    # 项目根目录 
    root      /data/www/web; 
    # 项目入口文件
    index      index.html; 
    #  try_files    是nginx的一个指令
    try_files    $uri $uri/ /index.html; 
}

路由守卫

本质就是权限判断

全局前置守卫

// 全局前置守卫,不管进入哪一个组件, 都会执行这个函数
router.beforeEach((to, from, next) => {
  console.log('to', to)
  console.log('from', from)
  next() // 表示一个通行证的意思, 通过验证之后, 页面才会往下走
})

路由独享守卫

{
    name: 'about', // 给路由取一个名字, 通过名字js跳转
    path: '/about',
    component: About,
    // 路由独享守卫
    beforeEnter: (to, from, next) => {
      console.log('to', to)
      console.log('from', from)
      if (123 == 1213) {
        // 比如, 登录判断, 如果登录了, 就方形
        next()// 表示一个通行证的意思, 通过验证之后, 页面才会往下走
      }
    }
  }

组件内的守卫

<template>
  <p>新闻</p>
</template>
<script>

 export default{  
  data(){
    return {
      age:18
    }
  },
  beforeRouteEnter(to, from,next) {
    console.log('路由进入组件之前')
    // 在渲染该组件的对应路由被验证前调用
    // 不能获取组件实例 `this` !
    // 因为当守卫执行时,组件实例还没被创建!
    // 但是可以通过回调函数拿到组件实例
    next((vm)=>{
      console.log('通过回调函数拿到组件实例, 获取到传入的数据',vm.age)
    })
  },
  beforeRouteUpdate(to, from) {
    console.log('路由更新组件之前')
    /**
     * 在当前路由改变,但是该组件被复用时调用
     * 举例来说,对于一个带有动态参数的路径 `/users/:id`,
     * 在 `/users/1` 和 `/users/2` 之间跳转的时候,由于会渲染同样的 `UserDetails`
     *  组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
     * 由于会渲染同样的 `UserDetails` 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
     * 因为在这种情况发生的时候,组件已经挂载好了,导航守卫可以访问组件实例 `this`
     */
    
  },
  beforeRouteLeave(to, from) {
    console.log('路由离开组件之前')
    // 在导航离开渲染该组件的对应路由时调用
    // 与 `beforeRouteUpdate` 一样,它可以访问组件实例 `this`
  },
 }

</script>

路由懒加载(以后都要这么用)

路由懒加载, 用到时再加载
因为如果组件太多, 一次加载完, 效率很低, 如果打开首页, 就只加载首页的路由, 打开详情页, 只加载详情页的路由, 这样就会更高效! 一般来说,对所有的路由都使用动态导入是个好主意。

语法:

const routes = [ 
  {
    path: '/page',
    // 使用路由懒加载后,上面就不需要再导入了
    component: () => import('../views/Page.vue')
  }
]

一般都会抽离一个变量出来, 方便管理和维护

语法:

const Home = ()=>import('../views/Page.vue')

const routes = [ 
  {
    path: '/page',
    // 使用路由懒加载后,上面就不需要再导入了
    component: Home
  }
]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值