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

嵌套路由

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

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

使用:

<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)

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
<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路由的内容)

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时,就会访问/的内容

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

导航守卫

1. 全局前置导航守卫

router.beforeEach

router.beforeEach((to, form, next) => {
    console.log(to, form);
    next()
})

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

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

案例:

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

<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

<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

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

export default Vnode.component?.exposed;

router

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

router.afterEach(() => {
    exposed?.endLoading()
})

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值