html5怎么改为vue_[vue学习]徒手撸一个vue-router

9aed768e4a13a9a0f7185eb95a08a280.png

首先我们来谈谈前端路由和后端路由究竟有什么不同呢?

请耐心读完这部分,非常有利于各位同学的理解
  1. 后端路由:

通过用户输入的url,服务端将其解析并将对应的文件传回前端,前端得以根据这些文件渲染页面,完成后端路由的流程闭环.

2. 前端路由:

前端路由是指智能分析url的变化,并根据预先设置,为匹配到不同的url将前端页面指定区域的渲染改变,整个过程可以不知会服务端,常见于各种SPA的开发过程(也就是非常常用)

而前端路由根据实现方式的不同,又可以分为 hash路由 html5history路由.

下面,我们也分别介绍一下这两种前端路由的原理:

(耐心看完,不要觉得难,其实很好理解)

1.hash路由:

类似于http://www.shang.com/#/login

这类路由有个很重要的特点,就是 # 号,所有需要侦测变化的位置都必须在 # 之后, 原因是正常情况下,前端url发生变化,都会刷新页面,但是如果变化出现在 # 以后,则不会出现这种情况.

这也能顺利的达成我们的需求: 在刷新页面的前提下,根据url变化,更改前端的展示内容.

那么问题来了,我们要如何侦测到hash路由的变化呢?

这里有个很好的方案,就是通过监听hashchange这个事件来获取变化,并在事件体中编写我们需要的逻辑.

window

2.html5history路由:

随着2014年,html5规范推出之后,在路由方面喜提三个api,分别是pushState, popState, replaceState.

通过这三个api的使用,我们就可以在不添加 # 的前提下,完成同样的功能---url变化时,不刷新页面,智能变更指定区域的前端渲染.

那么,基础知识我们已经科普完了,后面就是....

本文的重头戏: 徒手编写vue-router

首先我们来看一下,vue的原生路由是什么感觉的?

import VueRouter from 'vue-router';
Vue.use(VueRouter); // 看起来有点中间件的感觉,对吧?

const router = new VueRouter({ // 这一步是用VueRouter包装一下我们的路由数据
   mode: 'history', // 模式: hash或者history
   routes: [...] // 路由配置
});

new Vue({
   router // 这一步,大家都懂得,挂载路由~
});

做完了这些操作,我们就可以使用<vue-router> <vue-view><vue-link>这些常用高阶组件,

其次我们还可以在嵌套子组件中使用诸如this.$router或者this.$route等api.

随后,我们使用vue数据驱动模型来实现类似vue-router的代码.

vue数据驱动模型:

首先我们写一个便于模型监听的route对象.

const currentRoute = {
   path: '/login',
   query: {}, // 形如 ?query1=''&query2=''这种感觉.
   params: {}, // 形如 /:id这种感觉.
   name: '' // 路由名
   fullPath: '/login', // 完整路径
   route: {} // 记录当前路有属性
}

由于route属性里面储存着关于该路由的所有信息,所以我们只需要监听currentRoute.route这个对象即可达成我们需要的效果了.

那么~~~,老规矩,先编写vue的监听器

class Obeserver {
   constructor(value) {
      this.observe(value);
   }

   observe(data) {
      if(!data && typeof data !== 'object' ) {
         return;
      }
      Object.keys(data).forEach(key=> {
          if(typeof data[key] === 'object') {
             this.observe(data[key]);
          }
          defineReactive(data, key, obj[key]);
      })
   }
}

然后就是编写我们的劫持函数defineReactive;

function defineReactive(data, key, value) {
   let dep = new Dep();
   Object.defineProperty(data, key, {
      get: function() {
         if(Dep.target) {
            dep.addsub(Dep.target);
         }
         return value;
      },
      
      set: function(newValue) {
         if(value !== newValue) {
             value = newValue;
             dep.notify(); // 通知视图
         }
      }
   })
}

随后,就需要编写我们的容器类(Dep)了,容器类里面包裹着订阅了数据的Watcher类.

class Dep {
   constructor() {
     this.subs = []; // 用于包裹订阅器的容器数组
   }

   addsub(sub) {
      this.subs.push(sub);
   }

   notify() {
      this.subs.forEach(sub => {
         sub.update();
      })
   }
}

Dep.target = null;

最后,我们需要编写我们的订阅器,也就是Watcher类:

class Watcher {
   constructor(vm, props, callback) {
      this.vm = vm;
      this.props = props;
      this.callback = [];
      this.callback.push(callback);
      this.value = this.getValue();
   }

   getValue() {
      Dep.target = this;
      const value = this.vm.data[this.props];
      Dep.target = null;
      return value;
   }

   update() {
      this.callback.forEach(callbackfn => callbackfn());
   }
}

下一步就是,用我们编写好的监听-订阅-视图更新器来控制我们的route.

new Observer(this.current);

new Wathcer(this.current, 'route', this.render.bind(this));

而我们传入的render函数就是负责视图更新的回调函数:

render() {
   let i;
   if((i = this.current) && (i = i.route) && (i = i.component)){
      document.querySelector(`#${this.container}`).innerHTML = i;
   }
}

同学们,编写到这里,一个建议的vue-router已经完成了,其实vue-router和vue双向数据绑定原理是非常类似的,主要的地方在于熟悉Object.defineProperty,以及 监听数据 - 储存容器 - 订阅数据 - 视图更新 这个 vue 数据模型.

本次编写的只是个简略版vue-router,但是对于理解原理足矣,后面时间充足的时候,我会将全部逻辑补充完整,各位同学们, 敬请期待吧
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值