学习vue Router 二 嵌套路由,命名视图,重定向,导航守卫(登录案例,loadingBar案例)

嵌套路由

一些应用程序的 UI 由多层嵌套的组件组成。在这种情况下,URL 的片段通常对应于特定的嵌套组件结构,例如:

TypeScript 复制代码
import {createRouter,createWebHistory,RouteRecordRaw} from "vue-router";

const routes:Array<RouteRecordRaw> = [
    {
        path: "/foo",
        name: "footer",
        component: () => import("../view/footer.vue"),
        children: [
            {
                path: "",
                component: () => import("../components/A.vue")
            },
            {
                path: "user",
                component: () => import("../components/B.vue")
            }
        ]
    }
]

const router = createRouter({
    history: createWebHistory(),
    routes
})

export default router

使用:

TypeScript 复制代码
<script setup lang="ts">
import {useRouter} from "vue-router";
const router = useRouter()
</script>

<template>
  <router-view></router-view>
  <button @click="router.push('/foo')">去A组件</button>
  <button @click="router.push('/foo/user')">去B组件</button>
  <div>我是footer组件</div>
</template>

<style scoped>

</style>

命名视图

命名视图可以在同一级(同一个组件)中展示更多的路由视图,而不是嵌套显示。 命名视图可以让一个组件中具有多个路由渲染出口,这对于一些特定的布局组件非常有用。 命名视图的概念非常类似于"具名插槽",并且视图的默认名称也是 default。

一个视图使用一个组件渲染,因此对于同个路由,多个视图就需要多个组件。确保正确使用 components 配置 (带上 s)

TypeScript 复制代码
import {createRouter,createWebHistory,RouteRecordRaw} from "vue-router";

const routes:Array<RouteRecordRaw> = [
    {
        path: "/",
        name: "footer",
        components: {
            default: () => import("../view/footer.vue"),
            showB: () => import('../components/B.vue'),
            showA: () => import("../components/A.vue")
        }
    }
]

const router = createRouter({
    history: createWebHistory(),
    routes
})

export default router
TypeScript 复制代码
<script setup lang='ts'>

</script>

<template>
  <router-view></router-view>
  <router-view name="showB"></router-view>
  <router-view name="showA"></router-view>
</template>

<style scoped>

</style>

重定向-别名

1. 重定向 redirect

  1. 字符串形式配置,访问/ 重定向到 /user (地址栏显示/,内容为/user路由的内容)
TypeScript 复制代码
const routes:Array<RouteRecordRaw> = [
    {
        path: "/",
        name: "footer",
        component: () => import("../view/footer.vue"),
        redirect: "/user1",
        children: [
            {
                path: '/user1',
                component: () => import("../components/A.vue")
            }
        ]
    }
]

2.对象形式配置

复制代码
redirect: {path: "/user1"},

3.函数模式(可以传参)

复制代码
redirect(to) {
    return {
        path: "/user1",
        query: {
            name: 'jjs'
        }
    }
}

2. 别名-alias

当路径为/root时,就会访问/的内容

TypeScript 复制代码
const routes:Array<RouteRecordRaw> = [
    {
        path: "/",
        name: "footer",
        component: () => import("../view/footer.vue"),
        alias: ['/root'],
        children: [
            {
                path: '',
                component: () => import("../components/A.vue")
            }
        ]
    }
]

导航守卫

1. 全局前置导航守卫

router.beforeEach

TypeScript 复制代码
router.beforeEach((to, form, next) => {
    console.log(to, form);
    next()
})

每个导航方法接受三个参数

TypeScript 复制代码
to: Route, 即将要进入的目标 路由对象;
from: Route,当前导航正要离开的路由;
next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。
next(false): 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。
next('/') 或者 next({ path: '/' }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。
 

案例:

登录校验,如果登录了就可到index页面,没有登录那么就先登录

TypeScript 复制代码
<script setup lang="ts">
import { ref,reactive } from 'vue'
import type { FormInstance, FormRules } from 'element-plus'
import { useRouter } from 'vue-router'
const router = useRouter()

const ruleFormRef = ref<FormInstance>()

type User = {
  userName: string,
  password: string
}

const ruleForm = reactive<User>({
  userName: '',
  password: ''
})

const rules = reactive<FormRules>({
  userName: [
    { required: true, message: '请输入用户名', trigger: 'blur' },
  ],
  password: [
    { required: true, message: '请输入密码', trigger: 'blur' },
  ]
})

function submitForm(FromEl:FormInstance | undefined) {
  if(!FromEl) return
  FromEl.validate((valid) => {
    if (valid) {
      localStorage.setItem("token", "1234567890")
      router.push('/home')
    } else {
      console.log('error submit!')
    }
  })
}
</script>

<template>
  <div>
    <el-form
        ref="ruleFormRef"
        style="max-width: 600px"
        :model="ruleForm"
        status-icon
        :rules="rules"
        label-width="auto"
        class="demo-ruleForm"
    >
      <el-form-item label="userName" prop="userName">
        <el-input v-model="ruleForm.userName" type="text" autocomplete="off" />
      </el-form-item>
      <el-form-item label="password" prop="password">
        <el-input v-model="ruleForm.password" type="password" autocomplete="off" />
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="submitForm(ruleFormRef)">Submit</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>

<style scoped>

</style>

2. 全局后置守卫

使用场景一般可以用来做loadingBar

你也可以注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受 next 函数也不会改变导航本身:

案例

loadingBar

TypeScript 复制代码
<script setup lang="ts">
import { ref } from 'vue'
const speed = ref(0)
const bar = ref<HTMLDivElement>()
let timer = ref(0)
function startLoading() {
  let dom:HTMLElement = bar.value as HTMLElement
  timer.value = window.requestAnimationFrame(function fn() {
    speed.value += 1
    dom.style.width = speed.value + '%'
    if (speed.value >= 90) {
      speed.value = 0
      window.cancelAnimationFrame(timer.value)
    } else {
      timer.value = window.requestAnimationFrame(fn)
    }
  })
}

function endLoading() {
  speed.value = 100
  let dom = bar.value as HTMLElement
  dom.style.width = speed.value + '%'
  timer.value = setTimeout(() => {
    dom.style.height = 0 + 'px'
    clearTimeout(timer.value)
  },500)
}
defineExpose({
    startLoading,
    endLoading
})
</script>

<template>
<div class="loading-bar">
  <div ref="bar" class="bar"></div>
</div>
</template>

<style scoped>
.loading-bar {
  position: fixed;
  top: 0;
  width: 100%;
  height: 2px;
}
.loading-bar .bar {
  height: inherit;
  width: 0;
  background-color: skyblue;
}
</style>

bar.ts

TypeScript 复制代码
import LoadingBar from "./LoadingBar.vue";
import { createVNode,render } from "vue";
const Vnode = createVNode(LoadingBar);
render(Vnode,document.body);

export default Vnode.component?.exposed;

router

TypeScript 复制代码
router.beforeEach((to, _, next) => {
     // 路由拦截
    if (to.path === "/" || localStorage.getItem("token")) {
        next();
        exposed?.startLoading()
    } else {
        next("/");
    }
})

router.afterEach(() => {
    exposed?.endLoading()
})
相关推荐
Charles Ray16 分钟前
C++学习笔记 —— 内存分配 new
c++·笔记·学习
我要吐泡泡了哦1 小时前
GAMES104:15 游戏引擎的玩法系统基础-学习笔记
笔记·学习·游戏引擎
骑鱼过海的猫1231 小时前
【tomcat】tomcat学习笔记
笔记·学习·tomcat
贾saisai3 小时前
Xilinx系FPGA学习笔记(九)DDR3学习
笔记·学习·fpga开发
北岛寒沫3 小时前
JavaScript(JS)学习笔记 1(简单介绍 注释和输入输出语句 变量 数据类型 运算符 流程控制 数组)
javascript·笔记·学习
everyStudy3 小时前
JavaScript如何判断输入的是空格
开发语言·javascript·ecmascript
无心使然云中漫步5 小时前
GIS OGC之WMTS地图服务,通过Capabilities XML描述文档,获取matrixIds,origin,计算resolutions
前端·javascript
Bug缔造者5 小时前
Element-ui el-table 全局表格排序
前端·javascript·vue.js
铁匠匠匠5 小时前
从零开始学数据结构系列之第六章《排序简介》
c语言·数据结构·经验分享·笔记·学习·开源·课程设计
xnian_5 小时前
解决ruoyi-vue-pro-master框架引入报错,启动报错问题
前端·javascript·vue.js