路由vue-router(二)

  • Post author:
  • Post category:vue



目录


9.路由导航


10.编程式导航


11.动态路由


12. query传参


13.路由懒加载


14. 路由模式


15. 路由导航守卫


一、全局路由导航守卫


二、路由独享守卫


三、组件守卫


16. alias别名


17. 命名路由


18. 命名视图


19.路由元信息(常用)


vue中跳转页

有两种方式:

路由导航



编程式导航

9.路由导航

这种方式会多添加一层标签,相当于原生html中外面包了一个a标签,有可能导致样式不对

<li v-for="item in goodslist" :key="item.id">
    <router-link to="/detail">
        <img :src="item.img" :alt="item.name" />
        <div>
            <p>商品名称:{{ item.name }}</p>
            <p>商品价格:{{ item.price }}</p>
            <button>抢购</button>
        </div>
    </router-link>
</li>

10.编程式导航

编程式导航,就是在函数中,编写js逻辑,实现跳转

这里主要用的是

$router

这个对象原型上面的一些方法,如:push() replace() go() back()

  • push(url地址)

push() 往历史记录中添加一条记录 参照原生history API中的pushState()
  • replace(url地址)

replace() 替换当前这条历史记录 参照原生history API中的replaceState()
  • go(整数)

go(n) n是一个整数,代表页码 0代表当前页  -1代表上一页  1代表下一页
  • back()

回退一页
  • 视图

<li v-for="item in goodslist" :key="item.id" @click="goDetail">
    <img :src="item.img" :alt="item.name" />
    <div>
        <p>商品名称:{{ item.name }}</p>
        <p>商品价格:{{ item.price }}</p>
        <button>抢购</button>
    </div>
</li>
  • 逻辑代码

    goDetail() {
        this.$router.push("/detail");
        // this.$router.replace('/detail')
    }

11.动态路由

跳转页面并传值有两种方式,动态路由和query


首页的商品跳商品详情:用动态路由并传参

通过以下三步实现:改路由地址 -> 导航并传参 -> parmas中取值

导航分为两种方式:

路由导航



编程式导航

两种。但是取值都是用

parmas


一、将固定路由改成动态路由

router => index.js

{
    path:'/地址/:变量'
}
​
如:
{
    path: '/detail/:id',
    component: vDetail,
}


二、修改导航并携带参数

它有两种不同的方式

  • 方式1:路由导航跳转并携带参数

<router-link :to='"/地址/"+要传递的数据参数'>
    内容
</router-link>
  • 方式2:编程式导航跳转并携带参数

    视图部分

<li @click="goDetail(要传递的数据参数)">
    内容
</li>

逻辑部分

goDetail(形参) {
    this.$router.push("/地址/"+形参);
}

三、取值

this.$route.parmas.变量

12. query传参


分类跳转到分类列表,用 query 参数

注意点:不需要修改路由地址

也分为两种方式:

路由导航



编程式导航

两种。但是取值是一样的,用

query

  • 路由导航跳转并携带参数

<router-link :to='"/地址?参数名="+要传递的数据参数'>
</router-link>

如:

<li v-for="item in sortlist" :key="item.id">
    <router-link :to="'/list?id=' + item.id">
        {{ item.name }}
    </router-link>
</li>

  • 编程式导航跳转携带参数

    • 视图部分,如

    <li v-for="item in sortlist" :key="item.id" @click="goList(item.id)">
        {{ item.name }}
    </li>

    • 逻辑部分

    goList(形参) {
        // 方式一:直接拼接
        this.$router.push('"/地址?参数名="+形参');
    ​
        // 方式二:写成对象。如果要传多个参数,可以用以下这种写法
        this.$router.push({
            path:'/地址',
            query:{
                参数名1:形参1,
                参数名2:形参2
            }
        })
    }

    goList(id) {
        this.$router.push("/list?id=" + id);
    }

  • 取值

this.$route.query.参数名


总结


页面之间跳转有两种方式:路由导航和编程式导航

所谓的路由导航就是使用标签

<router-link to="地址">

所谓的编程式导航就是在方法中写js逻辑实现跳转

this.$router.push('地址')


页面之间传值有两种方式:动态路由和query参数

动态路由就是在路由地址上加:/地址/:id 在parmas里面取

所谓query参数,就是在地址后面加 ?参数名=值 在query里面取

13.路由懒加载

单页应用有一个最大的缺点,首次加载过慢,因为第一次加载,要加载全部的css、js和HTML 从路由着手去优化,没有触发的路由,第一次不加载 ​

router=>index.js

// 方法1:
const userCenter = () => import('../views/usercenter');
{
    path: "/user",
    component: userCenter ,
},
    
    
// 方法2:建议使用
{
    path: "/user",
    component:()=> import('../views/usercenter')
},

检测:打开网络,每打开一个路由,就会有新的js加载,说明已经懒加载了

14. 路由模式

  • 设置

const router = new VueRouter({
  routes,
  // mode: 'hash' // 默认模式,地址上会有#号
  mode: 'history' // 历史模式,地址上没有#号
})
  • 路由两种模式(hash和history)的区别

在开发模式下:就只有带#号 和 不带# 美观的问题
​
但是在生产环境下:
hash打包的生产物在服务器上,前进后退刷新都没有问题。因为它是模拟完整的url地址,当地址发生变化,不会重新加载(#后面的不算url地址,#号后面的东西发生变化,不会请求服务器)
​
history的生产物在服务器上,前进后退都没有问题,但刷新出现了问题,因为它是完整的URL地址,当地址发生变化时,会请求服务器,这个时候,服务器就一定要有配置
history利用的就是原生window.history.pushState()方法


在服务器环境下,测试两种模式的区别

vue项目生产环境打包,放到express的服务器中,可以查看这两种的差异

1、分别打包两种生产物

npm run build

2、创建express服务器,hash和history创建的生产物分别放入static文件夹下

npm init -y
npm i express

创建app.js

const express = require('express');
const app = express();
app.listen(3000, () => {
  console.log('http://localhost:3000');
});
​
const path = require('path');
app.use(express.static(path.join(__dirname, './static'))); // 开启static文件夹静态资源

启动项目

nodemon app.js

访问

http://localhost:3000

以上,就可以看到history模式下,刷新会有问题,而hash模式下,都没有问题

解决history模式在node服务器出错的问题

对于 Node.js/Express,请考虑使用 [connect-history-api-fallback 中间件]


HTML5 History 模式 | Vue Router

npm上的中间件:

connect-history-api-fallback – npm

安装:
npm i connect-history-api-fallback
const express = require('express');
const app = express();
app.listen(3000, () => {
  console.log('http://localhost:3000');
});
​
// 引入中间件
// 解决history在服务器上刷新出错的问题,使用connect-history-api-fallback中间件
var history = require('connect-history-api-fallback');
app.use(history());
​
const path = require('path');
app.use(express.static(path.join(__dirname, './static'))); // 开启static文件夹静态资源

这样,在node的服务器下,history刷新就不会出错了

15. 路由导航守卫

其实就是访问路由不同阶段的拦截。它本质还是函数。


注意:路由导航守卫是做权限管理的,axios是管理请求头和过滤请求数据的

路由导航守卫分为三个阶段:

全局路由导航守卫(2个)

->

路由独享守卫(1个)

->

组件守卫(3个)

  • 全局路由导航守卫,写在路由器上

全局路由导航守卫-前置
    路由器.beforeEach((to,from,next)=>{})      常用
​
全局路由导航守卫-后置
    路由器.afterEach((to,from)=>{})            (很少用),它没有next
  • 路由独享守卫,写在某条路线上

    beforeEnter(to,from,next){}    常用
  • 组件守卫,写在某个组件内部的配置对象上(就类似于methods和生命周期样)

进入组件之前
    beforeRouteEnter(to,from,next){}        常用,它的函数中没有this,因为没有还没有进入组件
​
组件内部更新之前
    beforeRouteUpdate(to, from, next) {}    不常用,要在hash模式测试
​
离开组件之前
    beforeRouteLeave(to, from, next) {}     常用

一、全局路由导航守卫

分前置和后置,写在router=>index.js中的 router 路由器上,在默认导出之前

前置

  • 前置导航钩子函数,它接收一个回调函数,该函数有三个参数,to去哪里,from从哪来。to和from它们下面分别有一个path属性,next即执行下一步

路由器.beforeEach((to,from,next)=>{
​
})
​
​
// 前置导航钩子函数
router.beforeEach((to, from, next) => {
  console.log(to, '全局路由导航守卫-前置   到哪去');
  console.log(from, '全局路由导航守卫-前置   从哪来');
  next();
});

前置导航钩子函数的适用场景?

最常用的

登录拦截

,有一些项目一定要强制登录,不登录无法访问任何页面

方法步骤:

  • 一、创建登录页面并设置路由 login.vue (一级路由)

  • 二、设置登录状态(当登录成功之后,向本地存储中添加一个标识,并跳转到首页)

<template>
  <div>
    <h1>登录</h1>
    <div class="m20 p20">
      <p class="mb20">
        <input
          type="text"
          class="p10"
          placeholder="请输入用户名"
          v-model="user.username"
        />
      </p>
      <p class="mb20">
        <input
          type="text"
          class="p10"
          placeholder="请输入密码"
          v-model="user.password"
        />
      </p>
      <p>
        <button class="p10" @click="login">登录</button>
      </p>
    </div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      user: {
        username: "",
        password: "",
      },
    };
  },
  methods: {
    login() {
      // console.log(this.user);
      // 登录时的验证工作
      // 这里固定了用户名为admin 密码为123
      // 当登录成功了以后(跳到首页),并向本地会话中存一个状态,方便全局路由导航守卫使用
​
      // 非空的判断
      if (!this.user.username || !this.user.password) {
        alert("用户名和密码必须填写");
        return;
      }
​
      // 如果是admin和123,则登录成功
      if (this.user.username === "admin" && this.user.password === "123") {
        alert("登录成功");
        sessionStorage.setItem("isLogin", true);
        this.$router.push("/home");
      } else {
        alert("用户名和密码错误");
        return;
      }
    },
  },
};
</script>
<style scoped>
</style>

  • 三、根据登录状态进行拦截 router->index.js

实现拦截的思路 1、如果它去的页面是登录页,我们就next 2、如果它去的是有

权限要求的



有了登录状态

,我们就next 3、如果以上都不符合,我们就强制它去登录

// router就是路由器,全局路由导航守卫就加在它上面
// 全局路由导航守卫-前置
router.beforeEach((to, from, next) => {
  console.log(to, '全局路由导航守卫-前置   到哪去');
  console.log(from, '全局路由导航守卫-前置   从哪来');
​
  // 1、如果它去的页面是登录 我们就next
  if (to.path === '/login') {
    next();
    return;
  }
  // 2、如果它有了登录状态 我们就next
  if (sessionStorage.getItem('isLogin')) {
    next();
    return;
  }
  // 3、如果以上都不符合 我们就强制它去登录
  next('/login');
});
​
// 全局路由导航守卫-后置 (用得少)
router.afterEach((to, from) => {
  console.log(to, '全局路由导航守卫-后置   到哪去');
  console.log(from, '全局路由导航守卫-后置   从哪来');
});

后置

  • 后置导航钩子函数(很少用),它没有next

路由器.afterEach((to,from)=>{
​
})
​
// 后置导航钩子函数
router.afterEach((to, from) => {
  console.log(to, '全局路由导航守卫-后置   到哪去');
  console.log(from, '全局路由导航守卫-后置   从哪来');
})

二、路由独享守卫

所谓的路由独享,就是每一条路由上面的单独的配置属性,它是一个函数。它要写在每一个 path 地址上面

在这里可以做一些拦截,如果符合,我就next,否则我可以让它跳转到某一个页去(如用户权限等)

beforeEnter(to,from,next){
​
}

这里以list页面为例,想进到list页面,如果你是从分类来的,我就让你进,否则到首页去

  {
    path: '/list',
    component: () => import('../pages/list'),
    beforeEnter(to, from, next) {
      console.log(to, '路由独享守卫 到哪去');
      console.log(from, '路由独享守卫 从哪来');
​
      /* 
        可以配置一些权限的控制
        比如:如果你是从分类来,就next  否则就回到首页
        比如:list这个页面只能从分类进,如果从其它的进,我们就让它到home
      */
      if (from.path === '/sort') {
        next();
      } else {
        next('/home');
      }
    },
  },


三、组件守卫

所谓组件守卫,就是写在组件的配置对象上

以detail详情的组件为例

  • 进入组件之前

// 进入组件之前
  beforeRouteEnter(to, from, next) {
    // 注意点:这个函数中没有this,因为还没有进入组件,组件的实例还没有创建(还没有执行生命周期)
    console.log(this, "组件this"); // undefined
    console.log(to, "进入组件之前  到哪去");
    console.log(from, "进入组件之前  从哪来");
    // next();
​
    // 如果你是从home进到详情的,我就让你进,从其它的不让进
    if (from.path == "/home") {
      next();
    } else {
      next("/home");
    }
  },
  • 组件内部更新之前

什么是组件内部更新呢?就是当url地址改变的时候(如:/detail/1 –> /detail/2),组件重新渲染,就是更新

注意:如果是history模式,这里会不好用,必须用hash模式(使用比较少)

// 组件内部更新之前
  beforeRouteUpdate(to, from, next) {
    // 这个函数中有this
    console.log(to, "组件更新之前 到哪去");
    console.log(from, "组件更新之前 从哪来");
    next();
  },
  • 离开组件之前

// 离开组件之前
  beforeRouteLeave(to, from, next) {
    // 这个函数中有this
    console.log(to, "离开组件之前  到哪去");
    console.log(from, "离开组件之前  从哪来");
    next();
  },

总结:导航守卫,用在权限管理上

  • 全局路由导航守卫,可以用于全站的权限

  • 路由独享:可以控制某个页面的权限(超级管理员,有所有的权限,如果是客服,就只有客服的权限)

  • 组件守卫:可以更精细化到某一个小块的权限

16. alias别名

在某条路线的属性上加

作用:就是说原来要通过

/cart

访问这个路由,现在通过

/别名

也能访问这个路由

可以在url地址中输入

/别名

也可以访问

{
    path: "/cart",
    component: () => import("../views/cart"),
    alias: "/gouwuche", // 别名,就是说原来要通过/cart访问这个路由,现在通过/gouwuche也能访问这个路由
},

17. 命名路由

在某条路线的属性上加name属性

  • 路由文件

{
    path: "/user",
    component: () => import("../views/usercenter"),
    name: "个人中心", // 命名路由
},
  • 视图中to时使用

<!-- 路由导航:to属性,除了path地址之外,你也可以通过name属性进行跳转 -->
<!-- <router-link activeClass='active' to="/user">个人中心</router-link> -->
​
<!-- 我们也可以通过命名路由去访问 -->
<router-link activeClass='active' :to="{name:'个人中心'}">个人中心</router-link>

18. 命名视图

即访问一个路径,可以渲染多个视图。其中一个是默认视图,其它的都是命名视图

  • router=>index.js

{
    path: "/login", // 访问这一个路径
    // component: () => import("../pages/login.vue"),
    components: {
        // 设置多个视图
        default: () => import("../pages/login.vue"), // 默认视图
        view1: () => import("../pages/test.vue"), // 命名视图
    },
},
  • app.vue

<template>
  <div>
    <!-- 第一个出口: 默认视图出口 -->
    <router-view></router-view>
    <!-- 第二个出口:命名视图出口,name属性必须要和命名视图的key值一致 -->
    <router-view name="view1"></router-view>
  </div>
</template>
​
<script>
export default {
  data() {
    return {};
  },
};
</script>
​
<style scoped>
</style>

19.路由元信息(常用)

相当于给这条路线添加一些自定义属性,然后在视图中可以取得这些自定义属性(常用)

{
    path: "/user",
    component: () => import("../views/usercenter"),
    meta: {
        // 自定义。你可以在这里设置很多属性,然后在$route.meta对象中取
        title:'个人中心111'
    },
},
​
取值:$route.meta.变量名



版权声明:本文为weixin_64037609原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。