react-router设计原理

7 篇文章 0 订阅

react-router是配合react使用的路由控件,功能也很强大,而了解其设计原理开发者来说是有必要也是有帮助的。接下来探讨一下react-router的设计原理。

了解react-router原理,首先要知道几个概念:h5 history对象,js history库,react-router是基于它们实现的。

h5 history

可以很清楚的看到history对象的属性和方法:

其中使用 pushState(),replaceState()时,浏览器url改变,但是页面并不刷新

每次但我们触发history.back(), History.forward()或点击浏览器的前进后退按钮时,都会触发popstate事件。

每次触发history.back(), History.forward()或点击浏览器的前进后退按钮时,都会触发popstate事件。
所以如果使用history做为路由基础,就需要使用history.pushState和history.replaceState来改变url的值而不刷新页面,然后通过popstate事件执行页面的前进与后退

h5 demo  注意:该例子需要创建一个本地服务器启动应用

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>手动实现router</title>
</head>
<script>
  /**
   * create by lwz
   * 设计思路
   * 1,每个组件对应一个path
   * 2, 每个组件在渲染后有一个特定的class,方便在路由切换后去操作目标组件
   * 3,路由的嵌套,包装在children里
  */
</script>
<body>
  <button onClick = "testPushState('/component1')">到component1</button>
  <button onClick = "testPushState('/component2')">到component2</button>
  <button>点击测试replaceState</button>
  <a href="http://www.baidu.com">跳转页面</a>
</body>
<script class="components-define">
//放在这里定义,当执行移除后,component2变为未定义
// const component2 = document.createElement('div');
//         component2.innerHTML = `<div class="bar2-component">
//           我是bar2-component
//           <button onclick = "testPushState('/')">点击回首页</button>
//         </div>`
  const routes = [
    {
      path:'/component1',
      component:() => {
        const component1 = document.createElement('div');
         component1.innerHTML = `<div class="bar1-component">
          我是bar1-component
          <button onclick = "testPushState('/')">点击回首页</button>
          </div>`
          return component1
      }
    },
    {
      path:'/component2',
      component:() => {
        const component2 = document.createElement('div');
         component2.innerHTML = `<div class="bar2-component">
          我是bar2-component
          <button onclick = "testPushState('/')">点击回首页</button>
        </div>`
        return component2
      }
    }
  ]
  function setView(path){
    //...此处省略path判断和处理
    //...
    let component = null;
    routes.forEach( (item, index) => {
      let className = item.path.replace('/','');

      if(item.path == path){
        if(document.querySelector(`.${className}`)) return;
        component = item.component();
        console.log(component.innerHTML)
        component.className = className
        // component.innerHTML = component.innerHTML.replace(/class([\s]?|[\s]+})=("|')/i,function(match){
        //   return match.indexOf("'") > -1 ? "class = '" + className + " " : 'class = "' + className + ' '
        // })
        alert('添加')
        console.log(component)
        document.querySelector('body').append(component)
      } else {
        document.querySelector(`.${className}`) && document.querySelector(`.${className}`).remove()
      }
    })
  }
</script>
<script>
  function testPushState(path,component){
    let stateObj = {
      foo: "bar",
      component:component
    };

    /**
     * pushState() 需要三个参数:
     * 一个状态对象,
     * 一个标题 (目前被忽略),
     * (可选的) 一个URL.
    */
    history.pushState(stateObj, "page 2", path);
    this.setView(path)
    //document.querySelector('body').append(component1)

    let currentState = history.state;
    console.log(currentState)
  }
  window.addEventListener('popstate',(e)=>{
    console.log('11212')
    let pathname = window.location;
    console.log(window.location)
    //document.getElementById('body').innerHTML = window.location;
    document.querySelector('body').style.backgroundColor = 'red'
  })
  console.log(history.state)
</script>
</html>

history 库

history是一个第三方js库,借鉴HTML5 history对象的理念,在其基础上又扩展了一些功能,用来管理历史记录,可以兼容不同的浏览器和不同的环境,根据不同的环境提供了三种不同的API。

    HashHistory:针对老版本的浏览器,主要通过Hash实现。
    BrowserHistory:针对较高版本的浏览器,主要通过H5的History实现。
    MemoryHistory:主要通过内存中的历史记录实现。

History支持发布/订阅功能,当history发生改变的时候,可以自动触发订阅的函数,再对比一些两者api的异同。以下是history库的:
 

  const history = {
    length,        // 属性,history中记录的state的数量	
    action,        // 属性,当前导航的action类型
    location,      // 属性,location对象,封装了pathname、search和hash等属性
    push,          // 方法,导航到新的路由,并记录在history中
    replace,       // 方法,替换掉当前记录在history中的路由信息
    go,            // 方法,前进或后退n个记录
    goBack,        // 方法,后退
    goForward,     // 方法,前进
    canGo,         // 方法,是否能前进或后退n个记录
    block,         // 方法,跳转前让用户确定是否要跳转
    listen         // 方法,订阅history变更事件
  };

react-router实现

设计思想:对History进行了一次封装,使能够识别将url的变化与componet渲染进行匹配

  1. 根据BrowserRouter等不同的API针对H5的history的重构
  2. 结构的构建,同时对history属性进行注册。
  3. 在Router的componentWillMount中注册history的事件回调。
  4. 在Redirect中进行路径的计算,调用history.push/history.replace等更新history信息。
  5. Route中根据计算的匹配结果,进行页面首次渲染/页面更新渲染处理。

 

具体实现代码:参见github

参考:https://blog.csdn.net/qq_36223144/article/details/83247008

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值