【Vue.js】路由基础-动态路由、嵌套路由、编程式导航、重定向

原生实现路由

💡Tips:路由的原理就是通过url的改变, 将相应的内容放在容器里面
点击实现页面跳转切换, 但是这和以前的页面跳转不一样, 以前是多个.html之间切换, 现在之后一个html文件, 所以我们只能进行页面中部分内筒切换(单页面引用)。动态组件每次点击url不会改变, 不考虑这种方法实现。路由每次点击页面时url会改变, 根据url的不同在页面上显示不同的内容。

实现效果:
  • url改变
  • 部分内容改变
步骤:
  1. 需要改变url的按钮, a标签, 由于一个页面内部切换所以页面不能刷新, #锚点在页面跳转时不会刷新, 同时能改变url又不会刷新
<p>
  <a href="#hot">热映</a> | <a href="#cinema">影院</a> |
  <a href="#wait">待映</a> |
  <a href="#classic">经典电影</a>
</p>
  1. 需要一个存放切换内容的容器
<div id="box"></div>
  1. 需要一个路由表, 就是一个数组, 里面每一项是对象, path, template
const routes = [
  {
    path: "hot",
    template: "<div>这是热映页面</div>",
  },
  {
    path: "cinema",
    template: "<div>这是影院页面</div>",
  },
  {
    path: "wait",
    template: "<div>这是待映页面</div>",
  },
  {
    path: "classic",
    template: "<div>这是经典电影页面</div>",
  },
];
  1. 监听url的改变, 监听hash值的改变, 通过hash值的改变触发相应的事件, 然后使用hash变量存储, 然后将hash值拿到和path作比对, 比对成功哪一项则将哪一项的template放到div容器里面
  • 拿到哈希值的方法是location.hash, 但是拿到的东西开头是带一个#, 所以要将#号去掉, 使用slice(1)方法从第二个字符串截取到末尾就拿到了哈希值
  • 注意一定要监听到hash值改变才会触发事件, 如果一直点击同一个链接则没有改变hash则不触发事件
window.addEventListener("hashchange", () => {
  // console.log("hash改变了");
  const hash = location.hash.slice(1);

  routes.forEach((item) => {
    if (item.path === hash) {
      document.querySelector("#box").innerHTML = item.template;
    }
  });
});

上述代码可见原生实现路由很麻烦, 所以vue官方提供了一个路由库Vue Router

Vue Router

官网路由https://router.vuejs.org/zh/introduction.html
路由不在脚手架安装也可以直接使用
可以直接使用cdn的方式引入路由
这里的vue3是通过CDN方式引入, 由于地址在国外可能会比较慢, 可以将代码复制到本地去引入, 注意这个网站有的cdn使用不了(可以往下找使用旧一点版本)
注意这里的vue3的使用的router4版本, 而vue2使用的是router3版本
💡Tips:
BootCDN极兔云官网https://www.bootcdn.cn/这个网站里面有大量的国内镜像资源, cdn是内容分发网络, 可以进入网站直接复制链接浏览器打开将源码复制下来在本地使用, 和vue的本地引入是一样的道理
HTML部分

<script src="https://unpkg.com/vue@3"></script>
<script src="https://unpkg.com/vue-router@4"></script>

<div id="app">
  <h1>Hello App!</h1>
  <p>
    <!--使用 router-link 组件进行导航 -->
    <!--通过传递 `to` 来指定链接 -->
    <!--`<router-link>` 将呈现一个带有正确 `href` 属性的 `<a>` 标签-->
    <router-link to="/">Go to Home</router-link>
    <router-link to="/about">Go to About</router-link>
  </p>
  <!-- 路由出口 -->
  <!-- 路由匹配到的组件将渲染在这里 -->
  <router-view></router-view>
</div>
  • router-link标签, 只要项目引入了路由, 就可以直接使用这个标签, router-link标签最后在浏览器里还是会变成a标签,它呈现一个带有正确 href 属性的 <a> 标签,to属性用来指定链接
  • router-view标签, 就是用来存放内容的容器

JavaScript部分

// 1. 定义路由组件.
// 也可以从其他文件导入
const Home = { template: '<div>Home</div>' }
const About = { template: '<div>About</div>' }

// 2. 定义一些路由
// 每个路由都需要映射到一个组件。
// 我们后面再讨论嵌套路由。
const routes = [
  { path: '/', component: Home },
  { path: '/about', component: About },
]

// 3. 创建路由实例并传递 `routes` 配置
// 你可以在这里输入更多的配置,但我们在这里
// 暂时保持简单
const router = VueRouter.createRouter({
  // 4. 内部提供了 history 模式的实现。为了简单起见,我们在这里使用 hash 模式。
  history: VueRouter.createWebHashHistory(),
  routes, // `routes: routes` 的缩写
})

// 5. 创建并挂载根实例
const app = Vue.createApp({})
//确保 _use_ 路由实例使
//整个应用支持路由。
app.use(router)

app.mount('#app')

// 现在,应用已经启动了!
  1. 上述代码定义了路由组件Home和About, 其中template里面的值放到容器
  2. 定义路由表routes
  3. 创建一个router实例, 这里原生的写法是使用addEventListener监听hashchange
  4. 这里是将路由表routes当做一个参数(变量)放到了路由实例里面, 实例里的routes是routes: routes的缩写, 左边的routes相当于一个选项, 不能随便更改。(由于是简写, 注意这里不能直接改routes, 如果要修改则改成routes: routes1)。这种创建实例的方法虽然没有使用addEventListener, 但是内部原理是一样的都是要监听
  5. 最后创建挂载实例多了一个app.use()方法, 这个方法在使用插件的方法一样, 意思就是把创建出来的实例router当做插件来使用

脚手架安装路由

  1. 安装脚手架,命令npm init vue@latest,记得安装router√
  2. 安装依赖, npm i 就能运行项目了

image.png

  • 安装完可以看到入口文件main.js多了两句话, 引入了router, 以及在使用路由之前app.use一下

image.png

  • 多了一个router文件和下面的index.js文件, 文件里面使用vue-router包里面解构createRouter方法创建了一个路由实例router, 创建出来之后就暴露给main.js

image.png
路由流程梳理:
在App里面加router-link和router-view标签,创建组件,这里的组件不再引入App.vue里面,而是引到路由表里面,通过每一个path去对应每一个组件。当我们点击router-link的时候路由就发生改变了,然后就会去路由表里面找对映的是哪个path,找到对应的path就去找对应的组件,将对应的组件放入router-view里面。

动态路由

动态路由匹配⭐

当我们做一个详情页面时(以猫眼电影为例子), 是根据详情页面的id去请求数据, 然后再渲染出来。
image.png
首先我们要知道如何获取到id。这是猫眼电影详情页的地址,可以看到地址栏url上有详情页的id,我们将这个id获取到,再拿这个 id做数据请求。
image.png
注意vue的路由默认是精准匹配,意思是说如果地址/后面还有东西就不能匹配到了。这里我们新建一个详情页path: “/detail/:id”,详情地址后面加上一个:id表示就是动态路由。这样我们在地址栏上写上其他东西页面也可以出来。

const router = createRouter({
  history: createWebHashHistory(import.meta.env.BASE_URL),
  // 精准匹配
  routes: [
    {
      path:"/",
      redirect:'/host'
    },
    {
      path: "/host",
      component: host,
    },
    {
      path: "/detail/:id",
      component: detail,
    },
  ],
});

获取动态路由参数, 通过this.$route.params.id获取动态路由, 这里的params.id就是路由表中的 :id

export default {
  created() {
    console.log(this.$route);
    this.id = this.$route.params.id;
  },
  watch: {
    $route(val, oldVal) {
      this.id = val.params.id;
    },
  },
};

这里的this. r o u t e 是一个对象 , 打印出来如下 , 可以看到对象里面有当前路径还有参数 i d , 我们把 t h i s . route是一个对象, 打印出来如下, 可以看到对象里面有当前路径还有参数id, 我们把this. route是一个对象,打印出来如下,可以看到对象里面有当前路径还有参数id,我们把this.route称之为当前页面的路由信息
image.png

响应路由参数的变化

💡Tips:这里我们添加了一个详情页2导航, 但我们在同一个路由不同参数的情况下跳转(也就是详情页跳转详情页), 这时候就无法监听到路由的改变触发相应的事件(created没有执行), 所以再次切换则不会打印。我们的需求还是一样只要地址改变就要做数据请求, 然后重新渲染。

  • 问题原因: 使用带有参数的路由时, 从/detail/23425导航到/detail/222222, 相同的组件实例将被重复使用, 因为两个路由都是同一个组件, 比起销毁在创建, 复用显得更高效。不过这也意味着生命周期钩子函数不会被调用
  • 解决问题:
    • 方法一: 我们使用watch去监听url的改变, 也就是监听$route的改变。这里需要注意watch里面的函数都可以拿到新值和旧值。再将拿到的新值给data。
    • 方法二: 使用导航守卫
<router-link to="/detail/23425">详情页|</router-link>
<router-link to="/detail/222222">详情页2|</router-link>
<template>
  <h2>详情-{{ $route.params.id }}</h2>
</template>
<script>
export default {
   data() {
    return {
      id: 0,
    };
  },
  created() {
    // fetch()
    console.log(this.$route);
    this.id = this.$route.params.id;
  },
  watch: {
    $route(val, oldVal) {
      //   console.log(val);
      //   console.log(oldVal);
      this.id = val.params.id;
    },
  },
};
</script>

image.png

捕获所有路由或 404 Not found 路由

  • 我们可以新建一个NotFound文件夹, 在路由表里添加path: “:pathMath(.)”, 引入NotFound组件。在vue2版本的时候直接写一个就行,这里vue3的路由4版本需要:pathMath(.)*,:表示动态参数,是什么都允许。
  • vue的路由是排他性路由: 表示路由从上往下开始匹配, 只要匹配到一个就停止。在做404页面时要把路由匹配path放在最后面, 意思是前面都没有匹配到直到匹配404。
  • react的5版本路由是包容性路由: 表示所有的都匹配, 如果匹配到多个就显示多个。

image.png

路由的匹配语法(了解)

  • :id动态路由后面可以加正则表达式(使用较少, 了解一下就好)。

sensitive与strict路由配置(了解)

  • 路由默认情况在是精准匹配,加了sensitive:true变成模糊匹配。

可选参数(了解)

  • path: "/detail/:id"后面加一个?表示动态可选路由,问号表示可加可不加正则的0和1

嵌套路由⭐

  • 顾名思义在路由里面写路由,例如当前页面有一个二级组件导航,二级组件里面又有三级组件导航,那么就需要使用路由嵌套。
  • 这里的path: "/host/today"路径可以使写成path: “today”, 相当于直接拼到/host的后面, 但是today不能再加/, 加了/表示表示根目录, 会无视前面的host
routes: [
{
      path: "/host",
      component: host,
      children: [
        {
          path: "/host/today",
          component: today,
        },
        {
          path: "/host/yesterday",
          component: yesterday,
        },
        
      ],
},
]

编程式导航⭐

💡Tips: 编程式导航可以用于一个导航下一级组件跳转到另一个导航下

  • 编程式导航通过js方式做跳转(通过事件)
  • router-link的跳转是声明式跳转
  • 多事情况下, router-link声明式导航和编程式导航是可以换着用。router-link会在点击时自动加上一个类型, 这个特点写导航高亮很方便。
  • 注意区分this. r o u t e 和 t h i s . route和this. routethis.router
    • this.$route表示的是当前页面的路由信息, 在获取动态参数时使用
    • this.$router表示的是整个路由实例, 在做跳转时使用

this.$router.push()

  • push方法是可以在历史记录里面追加, 它是可以后退的, 目前大部网页分都是使用push方法
  • 也可以使用对象的语法this.$router.push({ path: “/wait” });, 还有命名路由, 并加上参数, 还可以带查询参数, 还有可以带hash
<template>
  <h2>影院</h2>
  <button @click="pump">跳转到待映</button>
</template>

<script>
export default {
  methods: {
    pump() {
      this.$router.push("/wait");
      // this.$router.push({ path: "/wait" });
    },
  },
};
</script>

GIF.gif

this.$router.repalce()

replace方法是特换当前的历史记录, 后退时会跳过当前页面, 这是它与push的不同之处, 一般在登录页, 登录成功后点击历史回退时使用达到跳转首页效果

<script>
export default {
  methods: {
    pump() {
      this.$router.replace("/wait");
    },
  },
};
</script>

this.$router.go()

go方法是用于前进或者后退, 里面写整数

export default {
  methods: {
    pump() {
      this.$router.go("-1");
    },
  },
};
</script>

命名路由(了解)

在路由表中加上name属性,作用就是在做编程式导航或者router-link的时候后面可以使用对象。

命名视图(了解)

正常来说一个url对应一个组件,当一个url对应两个组件时, 我们将命名路由component改成components,在页面里面需要给router-view添加name属性。

    {
      path: "/wait",
      // component:wait
      components: {
        a: wait,
        b: wait2,
      },
  },

重定向⭐

路由重定向指的是:用户在访问地址 A 的时候,强制用户跳转到地址 C ,从而展示特定的组件页面;通过路由规则的 redirect 属性,指定一个新的路由地址,可以很方便地设置路由的重定向

routes: [
    {
      path: "/",
      redirect: "/host",
    },
    {
      path: "/host",
      component: host,
      children: [
        {
          path: "/host",
          redirect: "/host/today",
        },
        ]
    }
  ]

别名

alias表示别名,给路由导航添加两个名字,可以通过别面跳转页面。

{
      path: "/classic",
      component: classic,
      alias: "/jindian",
    },

image.png

  • 11
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

芒果Cake

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值