VUE3-router4学习笔记-一篇就够!

1、安装

注意使用Vue3 对应安装4.X版本以上,VUE2 要使用3.X
vue-router@可以指定版本号

npm install vue-router -S

2、搭建Router

  • 在src目录下新建router文件夹,在文件夹新建index.ts
    index.ts
  • src/router/index.ts
import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";

const routes: Array<RouteRecordRaw> = [
  {
    path: "/",
    component: () => import("../components/login.vue"),
  },
  {
    path: "/reg",
    component: () => import("../components/reg.vue"),
  },
];
const router = createRouter({
  history: createWebHistory(),
  routes,
});
export default router;

3、三种路径跳转

  • App.vue
    第一种:
    必须加<router-view>,否则不显示
<template>
  <div>测试Router</div>
  <div>
    <router-link to="/">Login</router-link>
    <router-link style="margin-left: 10px;" to="/reg">Reg</router-link>

  </div>
  <hr>
  <router-view></router-view>
</template>
<script setup lang="ts">
</script>
<style></style>
  • 第二种方式,使用name
  • 把index.ts改成:
import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";

const routes: Array<RouteRecordRaw> = [
  {
    path: "/",
    name: "Login",
    component: () => import("../components/login.vue"),
  },
  {
    path: "/reg",
    name: "Reg",
    component: () => import("../components/reg.vue"),
  },
];
const router = createRouter({
  history: createWebHistory(),
  routes,
});
export default router;

App.vue 使用绑定方式:

<template>
  <div>测试Router</div>
  <div>
    <router-link :to="{ name: 'Login' }">Login</router-link>
    <router-link style="margin-left: 10px;" :to="{ name: 'Reg' }">Reg</router-link>

  </div>
  <hr>

  <router-view></router-view>
</template>
<script setup lang="ts">
</script>
<style></style>

第三种方式,通过push方式

<template>
  <div>测试Router</div>
  <div>
    <button @click="toPage('/')">Login</button>
    <button @click="toPage('/reg')">Reg</button>


  </div>
  <hr>

  <router-view></router-view>
</template>
<script setup lang="ts">
import { useRouter } from "vue-router";
const router = useRouter();
const toPage = (url: string) => {
  //字符串
  router.push(url)

}

</script>
<style></style>
  • 对象的形式
const toPage = (url: string) => {
  // //字符串
  // router.push(url)
  //对象形式
  router.push({
    path: url
  })

}
  • 命名方式
<template>
  <div>测试Router</div>
  <div>
    <!-- <button @click="toPage('/')">Login</button>
    <button @click="toPage('/reg')">Reg</button> -->
    <button @click="toPage('Login')">Login</button>
    <button @click="toPage('Reg')">Reg</button>


  </div>
  <hr>

  <router-view></router-view>
</template>
<script setup lang="ts">
import { useRouter } from "vue-router";
const router = useRouter();
const toPage = (url: string) => {
  // //字符串
  // router.push(url)
  //对象形式
  // router.push({
  //   path: url
  // })

  //命名方式
  router.push({
    name: url
  })

}

</script>
<style></style>

4、历史记录处理

历史记录用在自己vue控制前进和后台,便于切换页面内容

  • router-link replace 是没有历史记录的
  • router.replace 也是没有历史记录的
<template>
 <div>测试Router</div>
 <div>
   <!-- <button @click="toPage('/')">Login</button>
   <button @click="toPage('/reg')">Reg</button> -->
   <button style="margin-left: 10px;" @click="toPage('Login')">Login</button>
   <button style="margin-left: 10px;" @click="toPage('Reg')">Reg</button>
   <button style="margin-left: 10px;" @click="next()">next</button>
   <button style="margin-left: 10px;" @click="prev()">prev</button>
 </div>
 <hr>
 <router-view></router-view>
</template>
<script setup lang="ts">
import { useRouter } from "vue-router";
const router = useRouter();
const toPage = (url: string) => {
 // //字符串
 // router.push(url)
 //对象形式
 // router.push({
 //   path: url
 // })
 //命名方式
 router.push({
   name: url
 })
}
const next = () => {
 router.go(1);
}
const prev = () => {
 router.back()
}
</script>
<style></style>

5、路由传参

1)Query路由传参方式

前置数据准备:list.json

{
   "data":[
       {
           "name":"(黑丝)脚踩老坛酸菜",
           "price":500,
           "id":1
       },
       {
          "name":"伤肺火腿肠",
           "price":800,
           "id":1  
       },
       {
          "name":"(假)翡翠玉石",
           "price":80000,
           "id":3  
       }
   ]
}
  • 传参入口:login.vue
<template>
   <!-- <div class="login">
       Login
   </div> -->
   <div>嗨,我是列表页面</div>
   <table cellspacing="0" class="table" border="1">
       <thead>
           <tr>
               <th>品牌</th>
               <th>价格</th>
               <th>操作</th>
           </tr>
       </thead>
       <tbody>
           <tr :key="item.id" v-for="item in data">
               <th>{{ item.name }}</th>
               <th>{{ item.price }} </th>
               <th>
                   <button @click="toDetail(item)">详情</button>
               </th>
           </tr>
       </tbody>
   </table>
</template>

<script setup lang='ts'>
import { data } from "./list.json";
import { useRouter } from "vue-router";
const router = useRouter();
type Item = {//自定义数据类型,对象形式
   name: string;
   price: number;
   id: number;
}
const toDetail = (item: Item) => {
   router.push({
       path: '/reg',
       query: item    //使用对象传参
   })

}


</script>
<style scoped>
.login {
   background: green;
   height: 400px;
   width: 400px;
   font-size: 20px;
   color: white;
}
</style>
  • 如何接受呢?reg.vue来接收
<template>
   <div>
       <button @click="router.back()">返回</button>
       <h3>喝喝!我是详情页面</h3>
   </div>
   <div>品牌:{{ route.query.name }}</div>
   <div>价格:{{ route.query.price }}</div>
   <div>品牌:{{ route.query.id }}</div>
</template>

<script setup lang='ts'>
import { data } from "./list.json";
import { useRoute, useRouter } from "vue-router";
const route = useRoute();
const router = useRouter();
</script>
<style scoped>
.reg {
   background: red;
   height: 400px;
   width: 400px;
   font-size: 20px;
   color: white;
}
</style>

效果:
在这里插入图片描述
传参结果

2) name+params方式传参–4.14版本后已经不能用

3)动态路由传参

  {
    path: "/reg/:id",//定义id
    name: "Reg",
    component: () => import("../components/reg.vue"),
  },

    router.push({
        name: 'Reg',
        params: {
            id: item.id
        }
    })
  • 使用地方
<template>
    <div>
        <button @click="router.back()">返回</button>
        <h3>喝喝!我是详情页面</h3>
    </div>
    <div>品牌:{{ item?.name }}</div>
    <div>价格:{{ item?.price }}</div>
    <div>品牌:{{ item?.id }}</div>
</template>

<script setup lang='ts'>
import { data } from "./list.json";
import { useRoute, useRouter } from "vue-router";
const route = useRoute();
const router = useRouter();

const item = data.find(v => v.id === Number(route.params.id))
</script>
<style scoped>
.reg {
    background: red;
    height: 400px;
    width: 400px;
    font-size: 20px;
    color: white;
}
</style>

query 和params区别

  • query 传参配置的是 path,而 params 传参配置的是name,在 params中配置 path 无效

  • query 在路由配置不需要设置参数,而 params 必须设置

  • query 传递的参数会显示在地址栏中

  • params传参刷新会无效,但是 query 会保存传递过来的值,刷新不变 ;

6、嵌套路由

  • 父路由
<template>
  <div>
      <RouterView></RouterView>
      <hr>
      <h1>我是父路由</h1>
      <div>
          <router-link to="/user">Login</router-link>
          <router-link style="margin-left: 10px;" to="/user/reg">Reg</router-link>

      </div>

  </div>
</template>

<script setup lang='ts'>


</script>
<style scoped></style>

路由也要改成:

import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";

const routes: Array<RouteRecordRaw> = [
  {
    path: "/user",
    component: () => import("../components/footer.vue"),
    children: [
      {
        path: "",
        name: "Login",
        component: () => import("../components/login.vue"),
      },
      {
        path: "reg",
        name: "Reg",
        component: () => import("../components/reg.vue"),
      },
    ],
  },
];
const router = createRouter({
  history: createWebHistory(),
  routes,
});
export default router;

在这里插入图片描述

7、命名视图

通过命名视图可以定义tab标签
App.vue

<template>
  <router-view></router-view>
</template>
<script setup lang="ts">
</script>
<style></style>

index.ts --路由编写

import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";
const routes: Array<RouteRecordRaw> = [
  {
    path: "/",
    component: () => import("../components/root.vue"),
    children: [
      {
        path: "/user1",
        components: {
          default: () => import("../components/A.vue"),
        },
      },
      {
        path: "/user2",
        components: {
          bbb: () => import("../components/B.vue"),
          ccc: () => import("../components/C.vue"),
        },
      },
    ],
  },
];

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

在root.vue路径使用

<template>
    <div>
        <h1>root</h1>
        <router-link to="/user1">/user1</router-link>
        <router-link style="margin-left: 30px;" to="/user2">/user2</router-link>
        <hr>
        <router-view></router-view>
        <router-view name="bbb"></router-view>
        <router-view name="ccc"></router-view>
    </div>
</template>

<script setup lang='ts'>


</script>
<style scoped></style>

8、重定向 -别名

  • 重定向
  //第一种方式 字符串
  redirect: "/user1", //重定向
  //第二种方式 对象方式
    redirect: {
      path: "user1",
    },
       //第三种方式 to方式
    redirect: (to) => {
      console.log(to, "=>");
      return {
        path: "/user1",
        query: {
          name: "小满",
        },
      };
    },
  • 别名
alias: ["/root", "/root1", "/root2"],

9、导航守卫

使用element-plus 举例

9.1 全局前置守卫

先安装 element-plus

npm install element-plus -S
  • vite.config.ts 提醒使用npm init vue@latest 创建项目
  • 选择ts router pinia
import { fileURLToPath, URL } from 'node:url'

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    vueJsx(),
  ],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  }
})

作用:能够拦截登录以后路径

  • main.ts
import { createApp } from 'vue'
// import './style.css'
import App from './App.vue'
import router from './router'
import ElementUi from 'element-plus'
import 'element-plus/dist/index.css'

const app = createApp(App)

app.use(router)
app.use(ElementUi)

const whiteList = ['/']

//全局前置守卫
router.beforeEach((to, from, next) => {
  let token = localStorage.getItem('token')
  //白名单 有值 或者登陆过存储了token信息可以跳转 否则就去登录页面
  if (whiteList.includes(to.path) || token) {
    //token每次都要跟后端校验一下是否过期
    //另外说一下beforeEach可以定义不止一个,vue会收集你所有定义的路由钩子,所以next的作用不应该是跳转,而是使步骤进行到下一个你定义的钩子
    next()
  } else {
    //否则跳转登录界面
    next('/')
  }
})

app.mount('#app')

  • App.vue
<template>
  <router-view></router-view>
</template>

<script setup lang='ts'>
import { ref, reactive } from 'vue'

</script>

<style>
* {
  padding: 0;
  margin: 0;
}

html,
body,
#app {
  height: 100%;
  overflow: hidden;
}
</style>
  • index.ts —路由配置
import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: '/',
      component: () => import('@/views/Login.vue')
    },
    {
      path: '/index',
      component: () => import('@/views/Index.vue')
    }
  ]
})

export default router

  • login.vue
<template>
    <div class="login">
        <el-form ref="form" :rules="rules" :model="formInline" class="demo-form-inline">
            <el-form-item prop="user" label="账号:">
                <el-input v-model="formInline.user" placeholder="请输入账号" />
            </el-form-item>
            <el-form-item prop="password" label="密码:">
                <el-input v-model="formInline.password" placeholder="请输入密码" type="password" />
            </el-form-item>
            <el-form-item>
                <el-button type="primary" @click="onSubmit">登陆</el-button>
            </el-form-item>
        </el-form>
    </div>
</template>
<script lang="ts" setup>
import { reactive, ref } from 'vue'
import { useRouter } from 'vue-router'
import router from '../router';
import { ElMessage, FormRules, FormInstance } from 'element-plus'


const formInline = reactive({
    user: '',
    password: '',
})


const form = ref<FormInstance>()

const rules: FormRules = reactive({
    user: [{
        required: true,
        message: "请输入账号",
        type: "string"
    }],
    password: [{
        required: true,
        message: "请输入密码",
        type: "string"
    }]
})

const onSubmit = () => {
    console.log('submit!', form.value)
    form.value?.validate((validate) => {
        if (validate) {
            router.push('/index')
            localStorage.setItem('token', '1')
        } else {
            ElMessage.error('请输入完整')
        }
    })

}
</script>

<style lang='less' scoped>
.login {
    height: 100%;
    display: flex;
    justify-content: center; //居中
    align-items: center;
}
</style>
  • Index.vue -登录后的页面
<template>
    <div>
        哈哈,我进来了
    </div>late>
</template>
<script setup lang='ts'>
import { ref, reactive } from 'vue'
</script>
<style lang='less' scoped></style>

退出登陆时,把 localStorage.setItem(‘token’, ‘1’) 删除token这样就可以实现退出了

9.2 全局后置守卫

App.vue

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

<script setup lang='ts'>
import { ref, reactive } from 'vue'

</script>

<style>
* {
  padding: 0;
  margin: 0;
}

html,
body,
#app {
  height: 100%;
  overflow: hidden;
}
</style>
  • loadingBar.vue
<template>
    <div class="wraps">
        <div ref="bar" class="bar"></div>
    </div>
</template>

<script setup lang='ts'>
import { ref, reactive, onMounted } from 'vue'

let speed = ref<number>(1)
let bar = ref<HTMLElement>()
let timer = ref<number>(0) //设置id

const startLoading = () => {
    let dom = bar.value as HTMLElement
    speed.value = 1
    console.log(dom);
    timer.value = window.requestAnimationFrame(function fn() {//不用箭头函数的原因,递归
        if (speed.value < 90) {
            speed.value += 1;
            dom.style.width = speed.value + '%'
            timer.value = window.requestAnimationFrame(fn) //递归
        } else {
            speed.value = 1;
            window.cancelAnimationFrame(timer.value)
        }
    })

}
const endLoading = () => {
    let dom = bar.value as HTMLElement
    setTimeout(() => {
        window.requestAnimationFrame(() => {
            speed.value = 100;
            dom.style.width = speed.value + '%'
        })
    }, 500)


}
// 放到全局导航守卫-后置守卫 后不需要了
// //只有在 onMounted 之后才能获取 DOM
// onMounted(() => {
//   startLoading()
//   endLoading()
// })

defineExpose({
    startLoading,
    endLoading,
})

</script>

<style lang='less' scoped>
.wraps {
    position: fixed;
    top: 0;
    width: 100%;
    height: 2px;

    .bar {
        height: inherit;
        width: 0;
        background: blue;
    }
}
</style>

在这里插入图片描述

  • main.ts
import { createApp, createVNode, render } from 'vue'
// import './style.css'
import App from './App.vue'
import router from './router'
import ElementUi from 'element-plus'
import 'element-plus/dist/index.css'
import loadingBarVue from './components/loadingBar.vue'

console.log(loadingBarVue) //不能直接使用
const Vnode = createVNode(loadingBarVue) //转成虚拟Dom
render(Vnode, document.body) //挂载

const app = createApp(App)

app.use(router)
app.use(ElementUi)

const whiteList = ['/']

//全局前置守卫
router.beforeEach((to, from, next) => {
  Vnode.component?.exposed?.startLoading()
  let token = localStorage.getItem('token')
  //白名单 有值 或者登陆过存储了token信息可以跳转 否则就去登录页面
  if (whiteList.includes(to.path) || token) {
    //token每次都要跟后端校验一下是否过期
    //另外说一下beforeEach可以定义不止一个,vue会收集你所有定义的路由钩子,所以next的作用不应该是跳转,而是使步骤进行到下一个你定义的钩子
    next()
  } else {
    //否则跳转登录界面
    next('/')
  }
})

//全局后置守卫
router.afterEach((to, from) => {
  Vnode.component?.exposed?.endLoading()
})

app.mount('#app')

10、路由元信息

在上面例子index.ts
在这里插入图片描述
路由元信息

11、路由过度动效

想要在你的路径组件上使用转场,并对导航进行动画处理,你需要使用 v-slot API

使用 animate.css

main.ts

import 'animate.css'

src/App.vue

    <router-view #default="{route,Component}">
        <transition  :enter-active-class="`animate__animated ${route.meta.transition}`">
            <component :is="Component"></component>
        </transition>
    </router-view>

上面的用法会对所有的路由使用相同的过渡。如果你想让每个路由的组件有不同的过渡,你可以将元信息和动态的 name 结合在一起,放在<transition> 上:

declare module 'vue-router'{
     interface RouteMeta {
        title:string,
        transition:string,
     }
}
 
const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: '/',
      component: () => import('@/views/Login.vue'),
      meta:{
         title:"登录页面",
         transition:"animate__fadeInUp",
      }
    },
    {
      path: '/index',
      component: () => import('@/views/Index.vue'),
      meta:{
         title:"首页!!!",
         transition:"animate__bounceIn",
      }
    }
  ]
})

12、路由的滚动行为

使用前端路由,当切换到新路由时,想要页面滚到顶部,或者是保持原先的滚动位置,就像重新加载页面那样。vue-router 可以自定义路由切换时页面如何滚动。

当创建一个 Router 实例,你可以提供一个 scrollBehavior 方法

const router = createRouter({
  history: createWebHistory(),
  scrollBehavior: (to, from, savePosition) => {
    console.log(to, '==============>', savePosition);
    return new Promise((r) => {
      setTimeout(() => {
        r({
          top: 10000
        })
      }, 2000);
    })
  },

scrollBehavior 方法接收 to 和 from 路由对象。第三个参数 savedPosition 当且仅当 popstate 导航 (通过浏览器的 前进/后退 按钮触发) 时才可用。

scrollBehavior 返回滚动位置的对象信息,长这样:

  • { left: number, top: number }
const router = createRouter({
  history: createWebHistory(),
  scrollBehavior: (to, from, savePosition) => {
    return {
       top:200
    }
  },

13、动态路由

我们一般使用动态路由都是后台会返回一个 路由表 )前端通过调接口拿到后处理(后端处理路由)

主要使用的方法就是 router.addRoute

13.1添加路由

动态路由主要通过两个函数实现。router.addRoute()router.removeRoute()

它们只注册一个新的路由,也就是说,如果新增加的路由与当前位置相匹配,就需要你用 router.push()router.replace() 来手动导航,才能显示该新路由

router.addRoute({ path: '/about', component: About })

13.2删除路由

有几个不同的方法来删除现有的路由:

  • 通过添加一个名称冲突的路由。如果添加与现有途径名称相同的途径,会先删除路由,再添加路由:
router.addRoute({ path: '/about', name: 'about', component: About })
// 这将会删除之前已经添加的路由,因为他们具有相同的名字且名字必须是唯一的
router.addRoute({ path: '/other', name: 'about', component: Other })
  • 通过调用 router.addRoute() 返回的回调:
const removeRoute = router.addRoute(routeRecord)
removeRoute() // 删除路由如果存在的话

当路由没有名称时,这很有用。

  • 通过使用 router.removeRoute() 按名称删除路由:
router.addRoute({ path: '/about', name: 'about', component: About })
// 删除路由
router.removeRoute('about')

需要注意的是,如果你想使用这个功能,但又想避免名字的冲突,可以在路由中使用 Symbol 作为名字。

当路由被删除时,所有的别名和子路由也会被同时删除

13.3查看现有路由

Vue Router 提供了两个功能来查看现有的路由:

13.4前端代码

注意一个事项 vite 在使用动态路由的时候无法使用别名@ 必须使用相对路径

const initRouter = async () => {
    const result = await axios.get('http://localhost:9999/login', { params: formInline });
    result.data.route.forEach((v: any) => {
        router.addRoute({
            path: v.path,
            name: v.name,
                                    //这儿不能使用@
            component: () => import(`../views/${v.component}`)
        })
        router.push('/index')
    })
    console.log(router.getRoutes());

}

13.5后端代码 nodejs express

import express, { Express, Request, Response } from 'express'

const app: Express = express()

app.get('/login', (req: Request, res: Response) => {
    res.header("Access-Control-Allow-Origin", "*");
    if (req.query.user == 'admin' && req.query.password == '123456') {
        res.json({
            route: [
                {
                    path: "/demo1",
                    name: "Demo1",
                    component: 'demo1.vue'
                },
                {
                    path: "/demo2",
                    name: "Demo2",
                    component: 'demo2.vue'
                },
                {
                    path: "/demo3",
                    name: "Demo3",
                    component: 'demo3.vue'
                }
            ]
        })
    }else{
        res.json({
            code:400,
            mesage:"账号密码错误"
        })
    }
})

app.listen(9999, () => {
    console.log('http://localhost:9999');

})
  • 39
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
`vue3-router`是Vue 3官方提供的路由管理器。它是Vue.js应用程序的插件,用于实现客户端路由。它通过拦截浏览器的URL请求并将其映射到Vue组件来实现单页应用程序(SPA)的导航。 `vue3-router`提供了一个简单而强大的API,可以让您轻松地定义和管理路由。您可以使用它来定义路由,处理URL参数,导航到不同的路由,以及处理路由事件等等。 以下是一个使用`vue3-router`的简单示例: ``` import { createRouter, createWebHistory } from 'vue-router' import Home from './views/Home.vue' import About from './views/About.vue' const routes = [ { path: '/', component: Home }, { path: '/about', component: About } ] const router = createRouter({ history: createWebHistory(), routes }) export default router ``` 在上面的示例中,我们定义了两个路由:`/`和`/about`。当用户访问这些路由时,它们将分别渲染`Home`和`About`组件。 要在Vue应用程序中使用`vue3-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') ``` 在上面的示例中,我们将`vue3-router`安装为Vue应用程序的插件,并将其传递给`createApp`函数。 一旦安装了`vue3-router`,您就可以在Vue组件中使用`$router`和`$route`对象来处理路由事件和URL参数。例如,以下代码可以将用户导航到`/about`路由: ``` export default { methods: { goToAbout() { this.$router.push('/about') } } } ``` 总之,`vue3-router`是Vue 3的一个强大而易于使用的插件,可以帮助您管理应用程序的路由。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值