vue3基础入门-p07-路由

单页应用程序与路由

SPA - 单页应用程序

  • SPA: Single Page Application 单页面应用程序
  • MPA : Multiple Page Application多页面应用程序

百度百科-SPA

单页应用-网易云音乐

单页面与多页面应用

单页面应用程序

优势

  • 传统的多页面应用程序,每次请求服务器返回的都是一整个完整的页面
  • 单页面应用程序只有第一次会加载完整的页面
  • 以后每次请求仅仅获取必要的数据,减少了请求体积,加快页面响应速度,降低了对服务器的压力
  • SPA更好的用户体验,运行更加流畅

缺点

  1. 开发成本高 (需要学习路由)
  2. 不利于 SEO 搜索引擎优化

ssr: server side rendering : 服务端渲染 大前端 nodejs

路由介绍

  • 路由 : 是浏览器 URL 中的哈希值( # hash) 与 展示视图内容(组件) 之间的对应规则
    • 简单来说,路由就是一套映射规则(一对一的对应规则), 由前端开发人员制定规则.-
    • 当 URL 中的哈希值( # hash) 发生改变后,路由会根据制定好的规则, 展示对应的视图内容(组件)
  • 为什么要学习路由?
    • 渐进式 =>vue => vuer-router (管理组件之间的跳转)
    • 在 web App 中, 经常会出现通过一个页面来展示和管理整个应用的功能.
    • SPA 往往是功能复杂的应用,为了有效管理所有视图内容,前端路由 应运而生.
  • vue 中的路由 : 是 hashcomponent 的对应关系, 一个哈希值对应一个组件

vue-router(官方提供)

官方文档: https://next.router.vuejs.org/zh/index.html

安装

npm install vue-router@4

具体步骤

实现vue的具体步骤

  • 步骤1:引入路由文件,引入vue-router一定要在vue.js后面,vue-router是vue的插件
<script src="./node_modules/vue/dist/vue.global.js"></script>
<script src="./node_modules/vue-router/dist/vue-router.global.js"></script>
  • 步骤2:准备路由规则中使用到的组件
const Index = {
    template: `
      <div>我是首页模块组件</div>
    `
}

const User = {
    template: `
      <div>这是用户模块组件</div>
    `
}
  • 步骤3: 配置路由的规则,每个路由都需要映射到一个组件
routes=[
        // path: 路径
        // component: 组件
        {path: '/index', component: Index},
        {path: '/user', component: User}
    ]
  • 步骤4:创建路由对象,并传递 routes 配置
const router = VueRouter.createRouter({
        history: VueRouter.createWebHashHistory(),
        routes // `routes: routes` 的缩写
    })
  • 步骤5: 指定vue实例的路由对象,使整个应用支持路由
app.use(router)
  • 步骤6: 设置路由的出口 匹配到的组件的显示的位置
<router-view></router-view>

参考示例:


<body>
<div id="app">
    <p>hello vue</p>
    <!-- 步骤6: 设置路由的出口  匹配到的组件的显示的位置 -->
    <router-view></router-view>
</div>

<!-- 步骤1:引入路由文件,引入vue-router一定要在vue.js后面,vue-router是vue的插件-->
<script src="./node_modules/vue/dist/vue.global.js"></script>
<script src="./node_modules/vue-router/dist/vue-router.global.js"></script>
<script>

    // 步骤2:准备路由规则中使用到的组件Index,User

    // 一个对象其实就可以是一个组件,这个组件默认是用不了
    // 注册组件的3种方式:
    // 方式1: 全局注册    app.component('index', Index) 组件'
    // 方式2: 局部注册    components: {index: Index}
    // 方式3: 配置到路由的规则中
    const Index = {
        template: `
          <div>我是首页模块组件</div>
        `
    }

    const User = {
        template: `
          <div>这是用户模块组件</div>
        `
    }

    // 步骤3: 配置路由的规则
    // 路由规则: 每个路由都需要映射到一个组件。
    routes = [
        // path: 路径
        // component: 组件
        // redirect: 路由的重定向
        {path: '/', redirect: '/index'},
        {path: '/index', component: Index},
        {path: '/user', component: User}
    ]

    // 步骤4:创建路由对象,并传递 `routes` 配置
    // 引入了vue-router.js,全局暴漏了VueRouter
    // router 是整个路由对象,一个项目就一个路由对象
    const router = VueRouter.createRouter({
        history: VueRouter.createWebHashHistory(),
        routes // `routes: routes` 的缩写
    })

    const app = Vue.createApp({})

    // 步骤5: 指定vue实例的路由对象,使整个应用支持路由
    app.use(router)

    const vm = app.mount('#app')
    window.vm = vm
</script>
</body>

路由导航

<!-- 使用 router-link 组件来导航. -->
<!-- 通过传入 `to` 属性指定链接. -->
<!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
<router-link to="/index">首页</router-link>
<router-link to="/user">用户页</router-link>

导航高亮

  • 点击导航 => 元素里添加了两个类 router-link-active,router-link-exact-active
<a href="#/index" class="router-link-active router-link-exact-active" aria-current="page">首页</a>
<a href="#/user" class="">用户页</a>
  • 高亮方式1 : 直接修改类的样式
.router-link-exact-active,
.router-link-active {
  color: red;
}
  • 高亮方式2 : 使用存在过的类样式 => 修改默认高亮类名
<style>
    .highlight {
        color: red;
        font-size: 30px;
    }
</style>
const router = VueRouter.createRouter({
    history: VueRouter.createWebHashHistory(),
    routes,
    // 修改默认高亮的a标签的类名
    // highlight 是已经存在过的样式
    linkActiveClass: 'highlight',
    linkExactActiveClass: 'highlight'
})

精确匹配和模糊匹配

  • 精确匹配 : router-link-exact-active 类名 : 只有当 浏览器地址栏中的哈希值 与 router-link 的 to 属性值,完全匹配对,才会添加该类
  • 模糊匹配: router-link-active 类名 : 只要 浏览器地址栏中的哈希值 包含 router-link 的 to 属性值,就会添加该类名
  • 一般同时使用两个类,特别是在路由嵌套时,需要同时匹配一级路由和二级路由。如果某个router-link不想模糊匹配,可以在该router-link上 加个 exact
<router-link to="/" exact>
  One
</router-link>
  • 注意 : 精确匹配和模糊匹配,只对添加类名这个机制有效,与路由的匹配规则无关!!!

router-link 导航高亮

路由重定向

  • 解释:将 / 重定向到 /index
{ path: '/', redirect: '/index' }

嵌套路由

实际生活中的应用界面,通常由多层嵌套的组件组合而成。同样的,URL中各段动态路径也按某种结构对应嵌套的各层组件。
例如,用户模块 /user 中,嵌套着“登录”,“注册” 模块。

  1. 我们可以在一级路由下,通过属性children 注册二级路由如下:
{
    path: '/user',
    component: User,
    // 配置二级路由,path前,主要不要'/'
    children: [
        // 匹配路由 /user/login
        {path: 'login', component: Login},
        // 匹配路由 /user/register
        {path: 'register', component: Register}
    ]
}
  1. 在组件中,添加路由出口
const User = {
    template: `
      <div>这是用户模块组件
      <h3> 二级路由:
      <router-link to="/user/login">登录</router-link>    |
      <router-link to="/user/register">注册</router-link>
      </h3>
      <hr>
      <router-view></router-view>
      </div>
    `
}

路由嵌套

参考代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>嵌套路由例子</title>
    <style>
        .router-link-active, .router-link-exact-active {
            color: red;
        }
    </style>
</head>
<body>
<div id="app">
    <h1>一级路由:
        <router-link to="/index">首页</router-link>
        |
        <router-link to="/user">用户页</router-link>
    </h1>
    <hr>

    <!-- 设置路由的出口 -->
    <router-view></router-view>
</div>

<!-- 引入路由文件 -->
<script src="./node_modules/vue/dist/vue.global.js"></script>
<script src="./node_modules/vue-router/dist/vue-router.global.js"></script>
<script>

    // 准备路由规则中使用到的组件Index,User,Login,Register
    const Index = {
        template: `
          <div>我是首页模块组件</div>
        `
    }

    const User = {
        template: `
          <div>这是用户模块组件
          <h3> 二级路由:
          <router-link to="/user/login">登录</router-link>    |
          <router-link to="/user/register">注册</router-link>
          </h3>
          <hr>
          <router-view></router-view>
          </div>
        `
    }

    const Login = {
        template: `
          <div>这是用户-登录组件</div>
        `
    }
    const Register = {
        template: `
          <div>这是用户-注册组件</div>
        `
    }

    // 配置路由的规则
    routes = [
        {path: '/', redirect: '/index'},
        {path: '/index', component: Index},
        {
            path: '/user',
            component: User,
            // 配置二级路由(某个路由的子路由),path前注意不要'/'
            children: [
                // 匹配路由 /user/login
                {path: 'login', component: Login},
                // 匹配路由 /user/register
                {path: 'register', component: Register}
            ]
        }
    ]

    // 创建路由对象
    const router = VueRouter.createRouter({
        history: VueRouter.createWebHashHistory(),
        routes // `routes: routes` 的缩写
    })

    const app = Vue.createApp({})

    // 指定vue实例的路由对象
    app.use(router)

    const vm = app.mount('#app')
    window.vm = vm
</script>
</body>
</html>

编程式导航

router-link 属于声明式导航,相当于a链接。

但是在使用场景中,有时候需要进行一些逻辑判断,如登录按钮,需动态导航到不同的组件中,这个时候就不适合使用router-link.

在 Vue 实例内部,你可以通过 $router 访问路由实例。因此你可以调用 this.$router.push

当你点击 <router-link> 时,这个方法会在内部调用$router.push,所以说,点击 <router-link :to="..."> 等同于调用 this.$router.push(...)

修改上方例子中的User组件内容如下:

const User = {
    template: `
      <div>这是用户模块组件
      <h3> 二级路由:
      <button @click="login">登录</button>    |
      <router-link to="/user/register">注册</router-link>
      </h3>
      <hr>
      <router-view></router-view>
      </div>
    `,
    methods:{
        login(){
            this.$router.push('/user/login')
        }
    }
}

编程式导航

动态路由匹配

我们经常需要把某种模式匹配到的所有路由,全都映射到同个组件。

比如:用户详情的展示,用户的id不同,展示的用户内容就不同,但是组件是同一个

/user/1 User

/user/2 User

/user/10086 User

  1. 动态路由参数的使用
// 创建路由对象,配置路由的规则
const router = VueRouter.createRouter({
    history: VueRouter.createWebHashHistory(),
    routes: [
        {path: '/', redirect: '/index'},
        {path: '/index', component: Index},
        // 动态路径参数 以冒号开头,冒号后面的名称可自定义,这里设置为id,将来在$route.params中对应的key就为id
        // 可以匹配: /user/1  /user/2  /user/xxx
        // 如果在动态的路由参数中使用了?,表示该路由参数可选,可以匹配 /user
        {path: '/user/:id?', component: User}
    ]
})
  1. 动态路由参数的获取
// 动态路由参数的获取
const User = {
    template: `
      <div>
      <p>当前用户id为:{{$route.params.id}}</p>
      </div>
    `,
    created() {
        // 动态路由参数的获取
        console.log('用户id:', this.$route.params.id)
        console.log('$route 完整信息:', this.$route)
    }
}

动态路由匹配

响应路由参数的变化

使用带有参数的路由时需要注意的是,当用户从 /user/1 导航到 /user/2 时,相同的组件实例将被重复使用

因为两个路由都渲染同个组件,比起销毁再创建,复用则显得更加高效。不过,这也意味着组件的生命周期钩子不会被调用

要对同一个组件中参数的变化做出响应的话,你可以简单地 watch $route 对象上的任意属性,如 $route.params

created() {
    // 动态路由参数的获取
    console.log('用户id:', this.$route.params.id)
    console.log('$route 完整信息:', this.$route)
    // 响应路由参数的变化
    this.$watch(
        () => this.$route.params,
        (newParams, oldParams) => {
            // 对路由变化做出响应...
            console.log('watch:当前用户id:', newParams.id)
            console.log("watch:newParams:", newParams)

        }
    )
}

响应路由参数的变化

今日学习总结

今日学习总结


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。
My Show My Code