概述
react router(react-router-dom) 和 vue router 都提供了一套 路由管理机制 帮助我们在 单页面应用 中管理 页面跳转。 尽管它们两个的 应用场景 不同,但是我们还是可以对它们做一些分析比较。
相同
首先我们来分析一下它们的 相同之处,整理如下:
-
router 工作原理都相同
不管是 vue router 还是 react router, 他们的 工作原理 都相同, 都是基于 window.history 实现的。
当需要 跳转页面 时,通过 window.history.pushState(window.history.replaceState、window.location.hash、 window.location.replace) 方法在浏览器中 添加或修改历史记录, 然后 重新渲染页面。 当通过 浏览器的前进、回退按钮 或者 go、back、forward 等方法 激活某个历史记录时, 触发注册的 popstate(hashchange) 事件, 然后 重新渲染页面。
在 整个应用过程 中,会构建一个 location 对象 来保存 页面的 url 信息。 这个 location 对象 是 响应式 的,当发生 页面跳转 时,更新 location 对象, 然后 触发页面重新渲染。
-
都有 hash 模式和 history 模式
react router 和 vue router 都有两种工作模式: hash 模式 和 history 模式。
history 模式,页面 url 的格式为 protocol://hostname: port/xxx/xxx, 更加美观。切换页面 的时候,会修改 window.location.pathname。
hash 模式,页面 url 的格式为: protocol://hostname: port/xxx/xxx/#/xxx。切换页面 的时候,只修改 window.location.hash。
使用 history 模式 需要 服务端支持,要在服务端增加一个 覆盖所有情况的候选资源。
-
都支持编程式导航
在 vue router 中,我们可以在 页面组件 中访问 router 实例 (this.$router) 的 push、replace、back、go、forward 方法实现 编程式导航。
在 react router 中, 我们可以在 页面组件 中通过 props.history 或者 hooks 获取 history 对象, 然后通过 history 对象 提供的 push、replace、back、go、forward 方法实现 编程式导航。
-
都可以在页面组件中访问当前 url 信息
在 vue router 中,我们可以在 页面组件 中通过 组件实例的 $route 属性 访问 当前页面的 url 信息。$route.path、$route.hash、$route.query、 $route.params 分别对应 当前 url 的 路径、hash值、查询部分、路由参数。
在 react router 中, 我们可以在 页面组件 中通过 props.location 或者 hooks 获取 location 对象,然后通过 location 对象 访问 当前页面 的 url 信息。location.path、location.hash、location.query、 location.state 分别对应 当前 url 的 路径、hash值、查询部分、路由参数。
刷新页面时, 页面跳转时用户传递的参数会丢失。
-
都支持动态路由匹配
在 vue router 中,我们可以通过 $route.params 访问 动态路由参数。
在 react router 中,我们在 页面组件 中通过 props.match.params 或者 hooks 获取 params 对象 来访问 动态路由参数。
-
都支持嵌套路由
-
都支持路由懒加载
vue router 和 react router 实现 路由懒加载 都需要 webpack 等工具的配合,且都是 基于动态构建 script 元素加载js文件的方式 实现的。
未完待续...
不同
两者的 不同之处, 整理如下:
-
页面跳转(渲染) 触发机制不同
两者 页面渲染触发机制的不同,主要是由于 vue 和 react 两者 响应式实现的原理 不同。
使用 vue router 时,在 应用启动过程 中,会给 根 vue 实例 构建一个响应式属性 - $route 来保存 页面 url 信息。 $route 属性 会维护一个 依赖列表 - deps,使用 router-view 的组件都会添加到 deps 中。当我们通过 push(replace) 跳转页面 或者 激活历史记录 时, 都会修改 $route, 然后通知 deps 中的 组件 更新, 重新渲染页面。
使用 react router 时, Router 组件 在渲染时会构建一个 组件实例 并初始化。 初始化过程中, 会定义 state.location 来保存 页面 url 信息。当我们通过 push(replace) 跳转页面 或者 激活历史记录 时, 会通过 setState 方法更新 state.location,然后 触发更新,重新渲染页面。
-
hash 模式的实现不同
react router 的 hash 模式,是基于 window.location.hash(window.location.replace) 和 hashchange 实现的。当通过 push 方式 跳转页面时,直接修改 window.location.hash,然后渲染页面; 当通过 replace 方式 跳转页面时,会先构建一个 修改 hash 以后的临时 url,然后使用这个 临时 url 通过 window.location.replace 的方式 替换当前 url,然后渲染页面;当 激活历史记录导致 hash 发生变化时,触发 hashchange 事件,重新 渲染页面。
和 react router 不同,vue router 的 hash 模式,是先通过 pushState(replaceState) 在浏览器中 新增(修改)历史记录,然后渲染页面。 当 激活某个历史记录 时, 触发 popstate 事件,重新 渲染页面。 如果 浏览器不支持 pushState,才会使用 window.location.hash(window.location.replace) 和 hashchange 实现。
-
history 模式不支持 pushState 的处理方式不同
使用 react router 时,如果 history 模式 下 不支持 pushState, 会通过 重新加载页面(window.location.href = href)的方式实现页面跳转。
使用 vue router 时,如果 history 模式 下 不支持 pushState,会根据 fallback 配置项 来进行下一步处理。 如果 fallback 为 true, 回退到 hash 模式;如果 fallback 为 false, 通过 重新加载页面的方式实现页面跳转。
-
路由拦截的实现不同
vue router 提供了 全局守卫、路由守卫、组件守卫 供我们实现 路由拦截。
react router 没有提供类似 vue router 的 守卫 供我们使用,不过我们可以 在组件渲染过程中自己实现路由拦截。 如果是 类组件, 我们可以在 componentWillMount 或者 getDerivedStateFromProps 中通过 props.history 实现 路由拦截; 如果是 函数式组件,在函数方法中通过 props.history 或者 useHistory 返回的 history 对象 实现 路由拦截。
-
懒加载实现过程不同
vue router 在 路由懒加载 过程中,会 先去获取懒加载页面对应的js文件。等 懒加载页面对应的js文件加载并执行完毕,才会开始 渲染懒加载页面。
react router 在 路由懒加载 过程中, 会 先去获取懒加载页面对应的js文件,然后 渲染 loading 页面。 等 懒加载页面对应的js文件加载并执行完毕,触发更新,渲染懒加载页面。
-
静态路由配置
vue router 使用的时候,会先通过 VueRouter 构建一个 router 实例。构建 router 实例的时候, 需要传入一个 静态路由配置 - routes,用于建立 path 和 component、name 和 component 以及 父子页面 之间的 映射关系。 当我们跳转页面时, 会先根据提供的 path(name) 找到匹配的页面组件(及子页面组件),然后确定页面的 url,再将 router-view 组件渲染为相应的页面。
vue-router 的这种机制,导致 同级路由, 一般只需要一个 router-view 组件 即可。
react router 不同,它 没有使用静态路由配置。当我们跳转页面时,由于没有静态路由配置,无法立即根据跳转提供的 pathname 立即找到匹配的页面,只能在渲染过程中,遍历 Route 组件,一个个做匹配,然后渲染 匹配的 Route 组件及页面组件。
react-router 的这种机制,导致 有多少个同级路由, 一般就需要多少个 Route 组件。
未完待续...