Vue进阶之Vue-Router

11 篇文章 0 订阅

Vue进阶之Vue-Router

Vue-Router的使用

1、动态路由:
  {
    path: '/home/:id', //配置id参数便可实现动态路由
    name: 'home',
    // 开启 props,会把 URL 中的参数传递给组件
    // 在组件中通过 props 来接收 URL 参数
    props: true,
    component: () => import('../views/Home.vue')
  }

组件接受id参数

<template>
  <div>
    <!-- 方式1: 通过当前路由规则,获取数据 -->
    通过当前路由规则获取:{{ $route.params.id }}
    <br>
    <!-- 方式2:路由规则中开启 props 传参 -->
    通过开启 props 获取:{{ id }}
  </div>
</template>

<script>
export default {
  name: 'Detail',
  props: ['id']
}
</script>

推荐使用第二种方式props方式获取参数,不强依赖router

2、Hash与History模式
Hash模式
  • Hash模式,是基于锚点,以及onhashchange事件,将锚点的值作为路由地址,当地址发生变化时触发onhashchange事件,然后根据路径决定页面内容;
  • History模式, 是基于HTML5中的History API实现的,
    • history.pushState() IE10以后才支持,有兼容问题
    • history.replaceState()
    • 其特点就是,改变地址栏中的url但是不会向服务端发送请求,并将其添加到历史记录中。利用其便可实现前端路由;
History模式

使用

  • History模式需要服务端支持;
  • 单页面应用中,服务端不存在http://www.abc.com/login 这样的地址,访问会返回找不到该页面404;
  • 在服务端应该除了静态资源外都返回单页面应用的index.html

在node服务中的处理

const path = require('path');
// 导入处理 history 模式的模块
const history = require('connect-history-api-fallback');
const express = require('express');
// 创建web服务器
const app = express();
// 注册处理 history 模式的中间件, 作用是当请求到服务器没有的地址时,都返回指定的index.html文件,再交给前端去判断路由
app.use(history());
// 加载制定地址的静态资源的中间件
app.use(express.static(path.join(__dirname, '../web')));
app.listen(8081, () => {
  console.log('服务器开启,8081');
})

在nginx服务器中

Mac中nginx信息存放
配置文件路径:/usr/local/etc/nginx/nginx.conf
安装路径:/usr/local/Cellar/nginx/1.10.7
服务器默认路径(根目录):/usr/local/var/www

在location中配置,try_files属性

		location / {
           root   html;
           index  index.html index.htm;
           try_files $uri $uri/ /index.html; 
           # vuerouter配置history模式当时请求地址不存在时,返回更目录的index.html文件
        }

Vue-Router的实现

原理

hash模式

  • 将URL中 # 后面的内容作为路劲地址;如果只改 # 后面的内容,浏览器不会向服务端请求这个地址,但是会将其放入浏览器的访问历史中;
  • 当hash改变后,要监听 onhashchange事件;
  • 当事件触发后,根据当前路由地址找到对应组件重新渲染;

history模式

  • 通过调用history.pushState()方法改变地址栏,pushState只是改变地址栏,并记录历史记录中,不会向服务端发送请求;
  • 监听popstate事件,找到改变后的地址(注意调用pushState或者replaceState时不会触发popstate事件,调用浏览器的back和forward,或者前进后退按钮时才会触发);
  • 根据当前路由地址找到对应组件重新渲染;
分析

通过使用分析vueRouter构成,绘制简单类图

VueRouter
-------------
+ options //传入的参数
+ data //VueRouter自身的响应数据
+ routeMap //记录路由地址的组件的关系
-------------
+ Constructor(Options): VueRouter //构造函数
_ install(Vue): void //静态方法注册VueRouter
+ init(): void // 入口方法
+ initEvent(): void // 组成事件监听变化
+ createRouteMap(): void // 创建routeMap对象
+ initComponents(Vue): void // 创建组件<router-link>和<router-view>

实现时,知识点,Vue的构建版本;

  • 运行时版:不支持template模板,需要打包的时候提前编译;打包时将template编译成render函数;
  • 完整版:包含运行时和编译器,体积比运行时版大10k左右,程序运行的时候把模板转换成render函数;所有其性能不如运行时版;

VueRouter的简单实现

/*
类图
VueRouter
-------------
+ options //传入的参数
+ data //VueRouter自身的响应数据
+ routeMap //记录路由地址的组件的关系
-------------
+ Constructor(Options): VueRouter //构造函数
_ install(Vue): void //静态方法注册VueRouter
+ init(): void // 入口方法
+ initEvent(): void // 组成事件监听变化
+ createRouteMap(): void // 创建routeMap对象
+ initComponents(Vue): void // 创建组件<router-link>和<router-view>
*/ 
let _Vue = null;

export default class VueRouter {
  static install(Vue) {
    // 1、判断插件是否安装;
    if(VueRouter.install.installed) return;
    VueRouter.install.installed = true;
    // 2、将vue的构造函数记得到全局变量中,将来在vuerouter的实例中还要使用这个vue的构造函数,比如在创建router-link这些组件时使用Vue.component方法;
    _Vue = Vue
    // 3、把创建的Vue实例时候的传入的router对象注入到所有的Vue实例上,创建$router
    Vue.mixin({
      beforeCreate() {
        if(this.$options.router){ //有这个选项才添加,除去组件
          Vue.prototype.$router = this.$options.router;
          this.$options.router.init();
        }
      }
    })
  }

  constructor(options) {
    this.options = options;
    this.routeMap = {};
    // data需要是响应式的对象,通过vue的
    this.data = _Vue.observable({
      current: '/' //当前路径默认根目录
    })
  }

  createRouteMap() {
    // 遍历所有的路由规则 把路由规则解析成键值对的形式存储到routeMap中
    this.options.routes.forEach(route => {
      this.routeMap[route.path] = route.component
    });
  }

  init() {
    this.createRouteMap();
    this.initComponents(_Vue);
    this.initEvent()
  }

  initComponents(Vue) {
    const _that = this;

    Vue.component('router-link', {
      props: {
        to: String
      },
      // 运行时版本Vue,需直接写render函数渲染
      render(h) {
        return h('a', {
          attrs: {
            href: this.to
          },
          on: {
            click: this.clickhandle
          }
        }, [this.$slots.default])
      },
      methods: {
        clickhandle(e){
          // 改变地址栏内容,第一个参数为,触发popstate事件时传入的对象
          history.pushState({}, 'haha', this.to);
          // _that.data.current = this.to; 

          this.$router.data.current = this.to; //记录跳转地址到当前router实例上的data.current属性上,存续当前地址,并且因为data是响应式的,它会自动更新我们的组件;
          e.preventDefault() //阻止默认行为
        }
      }

      // template 需要编译器用完整版Vue,在Vue.config.js中可配置
      // template: '<a :href="to"><slot></slot></a>'
    })

    Vue.component('router-view', {
      render(h) {
        let component = _that.routeMap[_that.data.current];
        return h(component); //直接渲染这个组件
      }
    })
  }

  initEvent() {
    // 这里为了监听点击后退按钮的问题
    window.addEventListener('popstate', () => {
      this.data.current = window.location.pathname;
    })
  }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值