vue3学习21、22路由

93 阅读3分钟

前端路由

当浏览器地址发生改变时,此时我们不希望地址一改变就去服务器请求静态资源。因此我们可以使用url的hash和history。

url的hash

url的hash也就是锚点(#)本质是改变window.location的href属性。hash的优势是兼容性更好,但是缺点有一个#,显得不像一个真实路径。 vue hash路由实现原理是监听hashchange事件,知道hash发生了哪些变化,根据hash变化实现更新部分页面的操作 简单hash实现原理

  <div id="app">
    <a href="#/home">home</a>
    <a href="#/about">about</a>
    <div class="content">default</div>
  </div>

  <script>
    const contentEl = document.querySelector('.content');
    window.addEventListener("hashchange", () => {
      switch(location.hash) {
        case '#/home':
          contentEl.innerHTML = "home";
          break;
        case '#/about':
          contentEl.innerHTML = "about";
          break;
        default: 
          contentEl.innerHTML = "Default";
      }
      // console.log(location.hash) 
    })
  </script>
html的history

history的接口是html5新增的,他有六种模式改变url而不刷新页面:

  • replaceState:替换原来的路径;
  • pushState:使用新的路径
  • popState:路径的回退
  • go:向前或向后改变路径
  • forword:向前改变路径
  • back:向后改变路径

histor路由的简单实现

  <div id="app">
    <a href="/home">home</a>
    <a href="/about">about</a>
    <div class="content">default</div>
  </div>

  <script>
    // 要在liveserve中打开,否则使用history方法会报错
    const contentEl = document.querySelector('.content');
    
    const aEls = document.getElementsByTagName("a");
    for(let aEl of aEls) {
      aEl.addEventListener("click", e => {
        e.preventDefault();  //阻止默认行为,不会跳转去请求新资源

        const href = aEl.getAttribute("href");
        history.replaceState({}, "", href);

        // console.log(location.pathname)
        switch(location.pathname) {
          case '/home': 
            contentEl.innerHTML = 'Home';
            break;
          case '/about':
          contentEl.innerHTML = 'About';
            break;
          default:
          contentEl.innerHTML = 'default';
        }
      })
    }
  </script>

pushState: 有历史记录,可以返回 replaceState: 无历史记录

vue-router使用

下载vue-router

npm install vue-router@4

创建一个js文件用于导出router对象

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

import Home from '../pages/Home.vue'
import About from '../pages/About.vue'

//配置映射对象
const routes = [
  {path: '/', redirect: '/home'},  //重定向
  {path: '/home', component: Home},
  {path: '/about', component: About},
]

//创建一个路由对象
const router = createRouter({
  routes,
  history: createWebHashHistory(),
})

export default router;

在main.js中引入导入

import { createApp } from 'vue'
import App from './App.vue'
import router from '@/router'

const app = createApp(App)
app.use(router)
app.mount('#app')

使用占位符表示路由所显示的位置

<template>
  <router-view/>
</template>

在浏览器中输入/home即可展示 可以通过router-link实现跳转

<router-link to="home">首页</router-link>

route还有name和meta属性

vue-router懒加载

/* webpackChunkName: "home-chunk" */指定打包的名字

//配置映射对象
const routes = [
  {path: '/', redirect: '/home'},
  {path: '/home', component: () => import(/* webpackChunkName: "home-chunk" */'../pages/Home.vue')},
  {path: '/about', component: () => import('../pages/About.vue')},
]

动态路由匹配

动态路由使得浏览器路劲不能写死,此时可以使用动态路由

const routes = [
  {path: '/user/:name/id/:id', component: () => import('../pages/User.vue')},
]

<div><router-link to="user/kobe/id/111">用户</router-link></div>

可以根据需要将值变为动态的 可以通过this.$route获得:name的值 如果在setup中使用,可以使用vue-router提供的函数

<script>
  import { useRoute } from 'vue-router'
  export default {
    setup() {
      const route = useRoute();
      console.log(route)
    }
  }
</script>
匹配不存在路劲

当用户输入不存在路劲时,页面不会发生变化,此时应在router中设置不存在路劲所匹配的路由

const routes = [
  {path: '/:pathMatch(.*)', component: () =>import('../components/HelloWorld.vue')},
]

路由嵌套

在需要嵌套的路由中

<template>
  <div>
    <h2>home</h2>

    <router-view/>
    <router-link to="home/message">消息</router-link>
  </div>
</template>

在route中设置

  {
    path: '/home',

    component: () => import(/* webpackChunkName: "home-chunk" */'../pages/Home.vue'),
    children: [
      {
        path: 'message',
        component: () => import('../pages/HomeMessage.vue')
      }]
  },

编程式导航

可以取到this的情况下使用:

this.$router.push('/about')

在setup中使用:

<script>
  import { useRoute } from 'vue-router'
  export default {
    setup() {
      const router = useRoute();
      const jump = () => {
          router.push('/about)
      }
      return {
        jump
      }
    }
  }
</script>

router.push中可以传入对象

router.push({
    query: {
        name: 'juju'
    }
})

query会显示在浏览器的url地址上 使用this.$router.query取到

router-link的内置插槽

  <router-link to="home">
    <button>首页</button>
  </router-link>

在router-link组件下写元素,则占据默认插槽。内部也可以写一个组件。 也可以通过v-slot取得router-link to的路劲

  <router-link to="home" v-slot="props">
    <a>{{props.href}}</a>
  </router-link>

props.href为"/home" props中也有route属性

  <router-link to="home" v-slot="props" custom>
    <button @click="props.navigate">我是v-slot跳转</button>
  </router-link>

自定义插槽通过navgate函数跳转

router-view的插槽

router-view一般是作为占位使用,但如果想要在页面切换直接使用过渡效果,可以在rouetr-view中使用transtion组件

  <router-view v-slot="props">
    <transition name="juju">
      <component :is="props.Component"></component>
    </transition>
  </router-view>
  
  
  <style>
  .juju-enter-from,
  .juju-leave-to {
    opacity: 0;
  }
  .juju-enter-active,
  .juju-leave-active {
    transition: opacity 1s ease;
  }
</style>

也可以使用keep-alive对组件进行缓存

  <router-view v-slot="props">
    <transition name="juju">
      <keep-alive>
          <component :is="props.Component"></component>
      <keep-alive>
    </transition>
  </router-view>

动态添加路由

const categoryRoute = {
  path: '/cate',
  component: () => import('../pages/Category.vue')
}

router.addRoute(categoryRoute);
动态添加二级路由
router.addRoute("home", {
  path: 'moment',
  component: () => import('../pages/moment.vue')
})

第一个参数对于的是route的name属性

动态删除路由

  • 通过removeRoute方法,传入路由名称.如removeRoute("home")
  • 通过daaRoute方法返回值回调
const remove = router.addRoute(categoryRoute);
remove();

路由导航守卫

beforeEach在路由跳转之前调用,可以用来在路由跳转时有无权限,如果登录信息过期跳转到登录页。

// to: route对象,即将跳转到的路由对象
// from: 从哪一个路由对象来到的
/**
 * 返回值:1.false不进行导航
 *        2.undefined或者不写:进行默认导航
 *        3.字符串:路劲,跳转到对应的路径中
 *        4.对象。类似于route.push({path: '/home', query})
 * */
router.beforeEach((to, from) => {

})