路由进阶

 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'
}

posted on 2019-04-27 23:32  琪琪伤感  阅读(161)  评论(0编辑  收藏  举报