1>路由组件传参
在组件中使用 $route
会使之与其对应路由形成高度耦合,从而使组件只能在某些特定的 URL 上使用,限制了其灵活性。
解决方法:
1.1若是动态匹配页面,只需要在路由参数中加入props:true即可。
import Home from "@/views/Home.vue";export default [{path: "/argu/:name",name:"argu",component: () => import("@/views/argu.vue"),props:true//可以进行路由组件传参 } ];
<template><div><!-- 拿到动态路由的参数 --><!-- {{$route.params.name}} --><!-- 尽量使用这种方法,不要使用this.$route.paramas,让组件和路由解耦尽量不要在组件中使用$routes,$router方法 -->{{name}}</div> </template><script> export default {// props:{name:{type:String,default:"caoqi"}} }; </script>
2.如果是普通的页面,则也可使用props对象格式传递:
import Home from "@/views/Home.vue";export default [{path: "/about",name: "about",// route level code-splitting// this generates a separate chunk (about.[hash].js) for this route// which is lazy-loaded when the route is visited.component: () => import(/* webpackChunkName: "about" */ "@/views/About.vue"),//如果是空对象则显示apple//props:{}, props: {food:'banaa'}},{path: "/argu/:name",name:"argu",component: () => import("@/views/argu.vue"),props:true//可以进行路由组件传参 } ];
<template><div class="about"><h1>This is an about page</h1><b>{{ food }}</b></div> </template> <script> export default {props:{food:{type:String,default:"apple"}} } </script>
3.如果是普通的页面,还可以使用props函数模式传递,这种情况适合于根据地址参数做一些逻辑:
import Home from "@/views/Home.vue";export default [{path: "/",alias:'/home_page',name: "home", //加上name属性 命名路由 component: Home,props: route => ({ food:route.query.food})} ];
<template><div class="home"><b>{{ food }}</b><button @click="handleClick('back')">返回上一页</button><button @click="handleClick('push')">跳转到parent</button><button @click="handleClick('replace')">替换到parent</button></div> </template><script> // @ is an alias to /src import HelloWorld from '@/components/HelloWorld.vue'export default {name: 'home',components: {HelloWorld},props:{food:{type:String,default:"apple"}},methods:{handleClick(type){if (type==="back") {//this.$router.back();this.$router.go(-1);}else if (type==="push") {const name="caoqi";//使用push会在浏览器中加入一个记录//使用路径跳转//this.$router.push("/parent");//还可以使用命名路由的方式:this.$router.push({// name: "parent",// //加入name参数,http://localhost:8080/#/parent?name=caoqi// query: {// name: 'caoqi'// }// name: "argu",// //加入name参数,http://localhost:8080/#/argu/caoqi// params: {// name: 'caoqi'// }//ES6写法: path:`/argu/${name}`,})}else if (type==="replace") {//使用replace不会在浏览历史中加入记录this.$router.replace({name: 'parent'})}}} } </script>
2>HTML histoty模式
import Vue from "vue"; import Router from "vue-router"; import routes from "./router";Vue.use(Router);export default new Router({//mode:'hash',//默认模式mode:'history',routes: routes });
3>导航守卫(路由守卫)
路由跳转前做一些验证,比如登录验证,是网站中的普遍需求。
官方api地址:https://router.vuejs.org/zh-cn/advanced/navigation-guards.html
3.1 全局守卫
3.1.1 全局前置守卫
import Vue from "vue"; import Router from "vue-router"; import routes from "./router";Vue.use(Router);const router = new Router({routes });const HAS_LOGINED = false; //全局前置守卫 /* to: Route: 即将要进入的目标 路由对象 from: Route: 当前导航正要离开的路由 next: Function: 一定要调用该方法来 resolve 这个钩子*/ //模拟登陆验证逻辑:当跳转页面为登陆页面且已经登陆时,直接跳转到home页面,如果跳转页面不为登录页且已经登陆,则继续执行,否则直接跳转到登录页 router.beforeEach((to, from, next) => {if (to.name !== "login") {if (HAS_LOGINED) next();else next({ name: "login" });} else {if (HAS_LOGINED) next({ name: "home" });else next();} });export default router;
3.1.2 全局后置钩子
3.2 路由独享的守卫
import Home from "@/views/Home.vue";export default [{path: "/",alias: "/home_page",name: "home", //加上name属性 命名路由 component: Home,props: route => ({food: route.query.food}),beforeEnter: (to, from, next) => {// if (from.name === "about") alert("这是从about来的");// else alert("这不是从about来的"); next();}} ];
3.3 组件内的守卫
<template><div class="home"><b>{{ food }}</b><button @click="handleClick('back')">返回上一页</button><button @click="handleClick('push')">跳转到parent</button><button @click="handleClick('replace')">替换到parent</button></div> </template><script> // @ is an alias to /src import HelloWorld from '@/components/HelloWorld.vue'export default {name: 'home',components: {HelloWorld},props:{food:{type:String,default:"apple"}},beforeRouteEnter (to, from, next) {// 在渲染该组件的对应路由被 confirm 前调用// 不!能!获取组件实例 `this`// 因为当守卫执行前,组件实例还没被创建next(vm => {//若想使用实例,可使用这种方法 console.log(vm)})},//这个离开守卫通常用来禁止用户在还未保存修改前突然离开。该导航可以通过 next(false) 来取消。 beforeRouteLeave (to, from, next) {// const leave = confirm('您确定要离开吗?')// if (leave) next()// else next(false) next()} } </script>
4>路由元信息
import Home from "@/views/Home.vue";export default [{path: "/",alias: "/home_page",name: "home", //加上name属性 命名路由 component: Home,props: route => ({food: route.query.food}),beforeEnter: (to, from, next) => {// if (from.name === "about") alert("这是从about来的");// else alert("这不是从about来的"); next();}},{path: "/about",name: "about",// route level code-splitting// this generates a separate chunk (about.[hash].js) for this route// which is lazy-loaded when the route is visited.component: () =>import(/* webpackChunkName: "about" */ "@/views/About.vue"),props: {food: "banaa"},meta: {title: '关于'}} ];
index.js
import Vue from "vue"; import Router from "vue-router"; import routes from "./router"; import { setTitle } from "@/lib/util";Vue.use(Router);const router = new Router({routes });const HAS_LOGINED = true; //全局前置守卫 /* to: Route: 即将要进入的目标 路由对象 from: Route: 当前导航正要离开的路由 next: Function: 一定要调用该方法来 resolve 这个钩子*/ //模拟登陆验证逻辑:当跳转页面为登陆页面且已经登陆时,直接跳转到home页面,如果跳转页面不为登录页且已经登陆,则继续执行,否则直接跳转到登录页 router.beforeEach((to, from, next) => {to.meta && setTitle(to.meta.title);if (to.name !== "login") {if (HAS_LOGINED) next();else next({ name: "login" });} else {if (HAS_LOGINED) next({ name: "home" });else next();} });export default router;
util.js
export const setTitle = (title) => {window.document.title = title || 'admin' }