路由 vue-router

231 阅读4分钟

简单使用

下载路由模块

npm i vue-router@4

使用

  1. 在src下面创建router文件夹
  2. 在文件夹中创建index.js
  3. 在main.js中引入路由,并全局注册

main.js

import { createApp } from "vue";
import App from "./App.vue";
import router from "./router"; // 导入路由

createApp(App)
  .use(router) //注册路由(全局的组件,指令,)
  .mount("#app");

路由配置文件

import {
  createRouter,
  createWebHashHistory,
  createWebHistory,
} from "vue-router";
import Film from '../views/Film.vue'
import Cinema from '../views/Cinema.vue'
import Center from '../views/Center.vue'

const routes = [
    { path: '/film', component: Film },
    { path: '/cinema', component: Cinema },
    { path: '/center', component: Center },
]

const router = createRouter({
  history: createWebHashHistory(), // hash模式 带有 # 号的路由形式
  // history:createWebHistory(),   // 不带 # 号的形式

  routes, // routes:routes 的简写
});

export default router;

重定向

  • redirect : " 要重定向到哪去 "
{
    // 重定向
    path: "/",  
    redirect: "/films",  // 重定向到路径为 /films 的页面
},

懒加载

  • 方案一(常用):使用箭头函数+ import动态加载
{
  path: "/mine",
  component: () => import("../views/Mine.vue"), // 懒加载
}
  • 方案二:使用箭头函数+ require动态加载
{
    path:"/mine",
    componenty:resolve => require(['@/componnets/list'],resolve) // @是src的别名
}

别名和嵌套路由

  • alias:别名
  • children:嵌套路由
{
    path: "/films", // url路径
    component: Films, // 路径加载组件
    alias: "/dianying", // alias 别名
    redirect: "/films/nowPlaying", // 重定向到:正在热映
    // 嵌套路由
    children: [
      {
        // 写法 1
        path: "/films/nowPlaying",  // 使用:/films/nowPlaying
        component: nowPlaying,
      },
      {
        // 写法 2
        path: "comingSoon", // 使用:/films/comingSoon
        component: comimgSoon,
      },
    ],
  },

声明式导航 和 编程式导航

image.png

声明式导航

1. 默认的 router-link 写法:

  • router-link默认是转换为 a 标签,
  • 属性:
    • to 代表跳转的路径
    • active-class 表示被选中的样式
<ul>
    <li><router-link to="/film" active-class="active">film</router-link></li>
    <li><router-link to="/cinema" active-class="active">cinema</router-link></li>
    <li><router-link to="/center" active-class="active">center</router-link></li>
</ul>

2. 自定义 router-link 写法

  • 自定义router-link的标签中的属性:
    • to 代表跳转的路径
    • custom 代表自定义router-link的标签,
    • v-slot 作用域插槽,用来取router-lik中提供的属性或方法
    • navigate 用来跳转的函数,
    • isActive 用来判断当前的标签是否被选中,返回值为true和false
<ul>
  <router-link to="/film" customv-slot="{ navigate, isActive }">
    <li @click="navigate" :class="isActive ? 'active' : ''">
        films
    </li>
  </router-link>
  <router-link to="/cinema" customv-slot="{ navigate, isActive }">
    <li @click="navigate" :class="isActive ? 'active' : ''">
        cinema
    </li>
  </router-link>
</ul>

编程式导航

  • 关键字:router.push()
// 字符串路径
router.push('/users/eduardo')

// 带有路径的对象
router.push({ path: '/users/eduardo' })

// 命名的路由,并加上参数,让路由建立 url
router.push({ name: 'user', params: { username: 'eduardo' } })

// 带查询参数,结果是 /register?plan=private
router.push({ path: '/register', query: { plan: 'private' } })

动态路由 + 组件内守卫

动态路由

  • 通过 传递参数 来加载展示:结构相同内容不同的数据
const routes = [
  {
    // query传参 ?id=123
    // path: "/film",
    // 通过 /id 的方式传参
    path: "/film/:myid",
    component: Film,
  },
]

组件内守卫

  • 在组件内部写 钩子函数
beforeRouteEnter(to, from) {
    // 在渲染该组件的对应路由被验证前调用
    // 不能获取组件实例 `this` !
    // 因为当守卫执行时,组件实例还没被创建!
  },
  beforeRouteUpdate(to, from) {
    // 在当前路由改变,并且该组件被复用时调用
    // 举例来说,对于一个带有动态参数的路径 `/users/:id`,在 `/users/1` 和 `/users/2` 之间跳转的时候,
    // 由于会渲染同样的 `UserDetails` 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
    // 因为在这种情况发生的时候,组件已经挂载好了,导航守卫可以访问组件实例 `this`
  },
  beforeRouteLeave(to, from) {
    // 在导航离开渲染该组件的对应路由时调用
    // 与 `beforeRouteUpdate` 一样,它可以访问组件实例 `this`
  },

使用

import {useRouter} from 'vue-router'
const router = useRouter()

// 猜你喜欢点击跳转到对应详情页
const detailsPage = (id) => {
  router.push(`/film/${id}`);
  // 在 onBeforeRouteUpdate 钩子中,发起ajax请求,重新请求数据
};
// 组件内部守卫
// 场景设定:猜你喜欢,点击对应按钮后跳转到对应电影的详情页
//  可以看到 mounted 生命周期函数只会执行一次,
//  即使再次点击喜欢的电影,页面也不会再次发起ajax请求新的数据
//  这事就需要利用router中的生命周期函数,当路由变化时,重新发起ajax请求
onBeforeRouteUpdate(async (newRoute) => {
  let { myid } = newRoute.params; // 通过 /id 的方式传值
  let {
    data: {
      data: { film },
    },
  } = await axios({
    url: `https://m.maizuo.com/gateway?filmId=${myid}&k=7819881`,
    headers: {
      "X-Host": "mall.film-ticket.film.info",
    },
  });
  // 页面显示数据
  filmInfo.value = film;
  // 回到页面顶部
  window.scrollTo(0, 0);
});

全局路由拦截

  • 在路由文件中写
const routes = [
  {
    path: "/mine",
    component: () => import("../views/Mine.vue"), // 懒加载
    meta: {
      myrequiresAuth: true, // 使用拦截
    },
  },
]

//  全局路由拦截
// 场景设定:需要登录成功之后才能查看我的页面
router.beforeEach((to, from, next) => {
  // 在routes数组,要拦截的对象中添加 meta
  let token = localStorage.getItem("token");
  if (to.path != "/login" && !token && to.meta.myrequiresAuth) {
    next("/login");
  } else {
    next();
  }
}); 

路由模式

  • 分为两种:
    1. createWebHashHistory() 创建的 hash 模式
    2. createWebHistory() 创建的 HTML5 模式

createWebHashHistory -- hash 模式

  • 它在内部传递的实际 URL 之前使用了一个哈希字符(#
  • 这里的实际路径为 #/films
import {createRouter , createWebHashHistory} from "vue-router";
import Film from '../views/Film.vue'

const routes = [{ path: '/film', component: Film }]

const router = createRouter({
  history: createWebHashHistory(), // hash模式 带有 # 号的路由形式
  routes, // routes:routes 的简写
});

export default router;

createWebHistory -- HTML5 模式

  • 路径中不带 #
import {createRouter , createWebHistory} from "vue-router";
import Film from '../views/Film.vue'

const routes = [{ path: '/film', component: Film }]

const router = createRouter({
  history: createWebHistory(), // HTML5模式
  routes, // routes:routes 的简写
});

export default router;