前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >写给vue转react的同志们(6)

写给vue转react的同志们(6)

作者头像
饼干_
发布于 2022-09-19 07:19:22
发布于 2022-09-19 07:19:22
53700
代码可运行
举报
运行总次数:0
代码可运行

theme: channing-cyan

本系列文章将由浅慢慢深入,一步步带你领略react和vue的同工异曲之处,让你左手react,右手vue无忧。

前提要顾: 点击查看该系列专栏

Vue 与 React 的路由

路由的实现原理

众所周知,路由是前端必不可少的一部分,在实际业务中也是我们接触最多的一个模块。那其实不论 Vue 还是 React,他们实现路由的原理都大同小异,既通过 hash 和 history 这两种方式实现。

那我们简单了解一下他的实现原理吧。

hash 模式

hash 模式的原理主要是基于 onhashchange 事件去做文章:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
window.onhashchange = () => {
    let hash = location.hash
    console.log(hash)
}

上图的 hash 打印出来的是 # 后面的路径(包括#)。

由于 hash 的变化都会被浏览器记录下来,使得浏览器的前进后退都可以使用,将页面状态和 url 关联起来,尽管没有请求服务器,这就是路由的最初模样。SPA(单页面应用) 的标配。

hash 模式下,发起的请求也不会被 hash 值影响(http请求中),不会重新加载页面。

history 模式

history 模式下的 url 就是正常的 url 比 hash 模式下的好看,但这也需要后台配置支持。

在 history 模式下用到了 onpopstate 这个事件:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
window.onpopstate = function(event) {
  alert("location: " + document.location + ", state: " + JSON.stringify(event.state))
}

通过浏览器提供的 history api,url 更加好看了,但是取而代之的是刷新时,如果服务器中没有相应的资源就可能会报 404,这是因为刷新了又去请求了服务器。

Vue router

对原理有了简单的了解之后,我们来简单的看看 Vue router 吧。

作为当前国内最火热的框架 Vue,大家当然再熟悉不过了,他的基本使用我就不做过多叙述了。

在上面我们了解了路由的基本原理,我们可以通过这个原理来实现一个简单的 Vue 路由,所以我们简单梳理一下我们要做的功能点:

  • 作为插件,需要有 install 方法。
  • 监听 url 变化,这里只做 hash 模式下的监听。
  • router-view 和 router-link 简单实现

明确目标后,我们先新建一个路由类,并且将传进来的 options (路由配置)保存起来然后初始化:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class vueRouter {
    constructor(options) {
        // 配置选项
        this.$options = options
        // 路由映射关系
        this.routeMap = {}
        // 将 Vue 实例储存起来用于响应式
        this.app = new Vue({
            data() {
                return {
                    current: '/'
                }
            }
        })
    }
}

vueRouter.install = (_Vue) => {
    // 将 Vue 类存起来
    Vue = _Vue
    // 注册全局混入将该生命周期混入到全局用于初始化
    Vue.mixin({
        created() {
            if(this.$options.router) {
                this.$router = this.$options.router
                // init 初始化路由 
                // this.$options 是 new Vue() 时传入的参数
                this.$options.router.init()
            }
        }
    })
}

初始化做完后,需要监听对应的回调事件用于响应我们的路由,并且注册对应的组件。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
initEvent() {
    // 监听浏览器的hashchange和load事件,使用bind改变this指向
    window.addEventListener('hashchange', this.handleHashChange.bind(this))
    window.addEventListener('load', this.handleHashChange.bind(this))
}

handleHashChange() {
    // 获取#后面的部分赋值给app的current
    this.app.current = location.hash.slice(1)
}

initRouteMap() {
    // 路由映射关系对应
    this.$options.routes.forEach(item => {
      this.routeMap[item.path] = item
    })
}

registerComponents() {
    // router-link 用于点击跳转
    Vue.component('v-router-link', {
      props: {
        to: String
      },
      render: function (h) {
        return h('a', { attrs: { href: `#${this.to}` } }, this.$slots.default)
      }
    })

    // router-view 展示当前路由对应组件即可
    Vue.component('v-router-view', {
        render: h => {
            const com = this.routeMap[this.app.current].component

            return h(com)
          }
    })
}

// 初始化方法
init() {
    this.initEvent()
    this.initRouteMap()
    this.registerComponents()
}

使用

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// main.js
import Vue from 'vue'
import vueRouter from './vueRouter'
import xxx from './xxx'
import home from './home'

Vue.use(vueRouter)

export default new vueRouter({
    routes:[{
        path: '/home',
        component: home
    },
    {
        path: '/xxx',
        component: xxx
    }]
})

// home.vue
<template>
    <div id='app'>
        <v-router-link to='/xxx'>xxx</v-router-link>
        <v-router-view />
    </div>
</template>

React router

我们知道 React 做为一个开放式的框架(不像Vue那样 Vue Router、Vuex等捆绑在一起),自由度是比较高的,没有像 Vue 那样教科书一般的配置,需要我们自己选择插件。这其实不乏有优秀的插件(这里只说路由相关插件)如:React router、react-router-dom等等。

由于笔者使用 react-router-dom 比较多,这里拿他来做文章。

react-router-dom 是利用了 Context API,通过上下文对象将当前路由信息对象注入到<Router>组件,所以<Router>组件渲染的内容就是 Context API 提供的 Provider,然后接收<Router>组件中的当前路由信息对象。

与 Vue Router 相似我们同样需要监听 url 的变化在对应回调中拿到相应的数据。不同的是 react-router-dom 中需要创建上下文对象来供我们全局使用,通过 Context 来传递我们想要的数据,简单梳理一下:

  • 创建上下文,将当前路由注入。
  • 监听 url 变化。
  • 简单实现 Route 等相关组件。

创建一个上下文并导出。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//context.js
import React from "react"
export default React.createContext()

将当前路由注入上下文,并监听 url 控制渲染。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// hashRouter.js
import React, { Component } from "react"
import Context from "./context" // 引入上下文对象

export default class hashRouter extends Component {
    constructor(props) {
        super(props)
        // 将状态存入 state 中方便修改。
        this.state = {
            location: {
                // 获取浏览器地址栏中的hash值,如果不存在则默认为"/"
                pathname: window.location.hash.slice(1) || "/", 
                query: undefined
            }
            // 用于实现当前路由的切换
            history: {
                push: (to) => {
                    if (typeof to === "object") {
                        // 如果参数是对象的情况:
                        let { pathname, query } = to
                        window.location.hash = pathname // 更新浏览器hash值,触发浏览器hashchange事件
                        this.state.location.query = query // 更新query
                    } else {
                        // 如果参数是路径:
                        window.location.hash = to // 更新浏览器hash值
                    }
                }
            }
        }
     }
    componentDidMount() {
        window.addEventListener("hashchange", () => { // 监听浏览器地址栏hash值变化
            this.setState({ // 当hash值变化后更新当前路由信息, HashRouter组件内的子组件Route将会重新渲染
                location: {
                    ...this.state.location,
                    pathname: window.location.hash.slice(1) // 更新pathname
                }
            })
        })
    }
     render() {
        // 当前路由对象
        const currentRoute = {}
        return (
             // 使用 Provider 组件将当前路由信息对象注入上下文中,以便其 Route 等子组件能够获取到当前路由信息
            <Context.Provider value={currentRoute}>
                {this.props.children}
            </Context.Provider>
        )
    }
}

在上述代码完成之后,我们就可以开始封装 Route 组件了,通过 Context 获取当前路由信息,将匹配路径的对应组件渲染出来。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// Route.js
import React, { Component } from "react"
import context from "./context"

export default class Route extends Component {
    static contextType = context
    render() {
        const currentRoutePath = this.context.location.pathname // 从上下文中获取到当前路由的路径
        const { path, component:Component } = this.props // 获取给 Route 传递的 props 属性
        const props = {
            ...this.context
        }
        // 匹配路径
        if (currentRoutePath === path) {
            return (
                <Component {...props}></Component>
            )
        }
        return null
    }
}

使用

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// router.js
import Route from './Route.js'
const router = (
    <Route
        path='/'
        component = () => import('./home.jsx')
    />
    <Route
        path='/xxx'
        component = () => import('./xxx.jsx')
    />
)
export default router
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// main.js
import React from 'react'
import router from './router.js'
class App extends React.Component { 
  constructor(props) {
    super(props)
    this.state = {
        // init something ...
    }
  }
  render() {
      <div>
          {router}
      </div>
  }
}

最后

以上的 Vue 和 React 实现的 router 只是最基本的路由功能,如 Vue Router 中的 keepalive、路由守卫等一些不错的功能没有去叙说。如 react-router-dom 中的 Route 组件的 exact(精确匹配)、Link(类似a标签)、Redirect(重定向)等一些不错的辅助功能也没有叙说,且只说了 hash 模式(history 模式就是监听另一个事件,逻辑都差不多)

都看到这里了,不点个赞再走吗?

欢迎在下方给出你的建议和留言。

关注公众号:饼干前端,获取更多前端知识~

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-12-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
如何吃透 vue-router
vue-router 是vue的插件,是对 vue的前端路由管理器,使用中通常分为hash 与 history模式。
前端小tips
2021/11/27
4410
如何吃透 vue-router
React 进阶 - React Router
用 React 或者 Vue 构建的应用都是单页面应用,单页面应用是使用一个 HTML 前提下,一次性加载 JavaScript , CSS 等资源,所有页面都在一个容器页面下,页面切换实质是组件的切换。
Cellinlab
2023/05/17
2K0
React 进阶 - React Router
手写Vue-router核心原理,再也不怕面试官问我Vue-router原理
在 Web 前端单页应用 SPA(Single Page Application)中,路由描述的是 URL 与 UI 之间的映射关系,这种映射是单向的,即 URL 变化引起 UI 更新(无需刷新页面)。
秋风的笔记
2021/09/22
7.5K1
手写Vue-router核心原理,再也不怕面试官问我Vue-router原理
「源码解析 」这一次彻底弄懂react-router路由原理
个人理解,单页面应用是使用一个html下,一次性加载js, css等资源,所有页面都在一个容器页面下,页面切换实质是组件的切换。
用户6835371
2021/06/01
4.1K0
「源码解析 」这一次彻底弄懂react-router路由原理
Vue router原理
vue-router是vue项目的重要组成部分,用于构建单页应用。单页应用是基于路由和组件的,路由用于设定访问路径,并将路径和组件映射起来。路由的本质就是建立url和页面之间的映射关系
全栈程序员站长
2022/09/18
5120
手写React-Router源码,深入理解其原理
上一篇文章我们讲了React-Router的基本用法,并实现了常见的前端路由鉴权。本文会继续深入React-Router讲讲他的源码,套路还是一样的,我们先用官方的API实现一个简单的例子,然后自己手写这些API来替换官方的并且保持功能不变。
蒋鹏飞
2020/10/15
1.6K0
手写React-Router源码,深入理解其原理
经常被问到的react-router实现原理详解
而且还经常会被xxx面试官问到,什么是前端路由,它的原理的是什么,它是怎么实现,跳转不刷新页面的...
夏天的味道123
2022/10/17
5530
深入浅出解析React Router 源码
最近组里有同学做了 React Router 源码相关的分享,我感觉这是个不错的选题, React Router 源码简练好读,是个切入前端路由原理的好角度。在分享学习的过程中,自己对前端路由也产生了一些思考和见解,所以写就本文,和大家分享我对前端路由的理解。 本文会先用原生 JavaScript 实现一个基本的前端路由,再介绍 React Router 的源码实现,通过比较二者的实现方式,分析 React Router 实现的动机和优点。阅读完本文,读者们应该能了解: 前端路由的基本原理 React Ro
用户1097444
2022/06/29
3.1K0
深入浅出解析React Router 源码
Vue-Router 简易实现
# 需求分析 作为一个插件存在:实现VueRouter类和install方法 实现两个全局组件:router-view用于显示匹配组件内容,router-link用于跳转 监控url变化:监听hashchange或popstate事件 响应最新url:创建一个响应式的属性current,当它改变时获取对应组件并显示 # 实现 # 作为一个插件存在 // cvue-router.js let Vue; // 1. 实现一个插件:挂载$router class CVueRouter { constructo
Cellinlab
2023/05/17
2070
vue-router原理分析与实践
Vue Router 是Vue.js官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。关于Vue Router的使用就不做过多介绍了,大家可以前往Vue Router官网去学习哦~
程序员老鱼
2022/12/02
2430
react-router 的使用与优化
react-router 可以创建单页应用。可以将组件映射到路由上,将对应的组件渲染到想要渲染的位置(根据路径的变化渲染出组件)。
多云转晴
2020/03/11
3.3K0
Vue路由实现原理
其中pushState方法和replaceState方法可以分别增加和替换掉一条记录(必须同源),而不会重新加载页面。
愤怒的小鸟
2021/01/11
1.2K0
超燃|从0到1手把手带你实现一款Vue-Router
无论是日常业务还是面试过程中,相信大家对于前端路由这个话题或多或少都有自己的应用和理解。
19组清风
2022/02/28
2.2K0
超燃|从0到1手把手带你实现一款Vue-Router
vue-router原理分析与实践
Vue Router 是Vue.js官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。 关于Vue Router的使用就不做过多介绍了,大家可以前往Vue Router官网去学习哦~
程序员老鱼
2021/11/06
3760
vue-router原理分析与实践
跟着来,你也可以手写VueRouter
VueRouter,无疑是每个 Vue 开发者时时刻刻都在使用的东西了,但对于它的源码,你了解多少呢?
isboyjc
2022/03/28
1.6K0
跟着来,你也可以手写VueRouter
React Router V6详解
SAP全称是【single-page application】,中文译为单页面应用。它是网站应用的一种模型,可以动态重写当前的页面来与用户交互,而不需要重新加载整个页面。相对于传统的 Web 应用程序,单页应用做到了前后端分离,即后端只负责处理数据提供接口,而页面逻辑和页面渲染都交由前端处理。前端发展到现在,单页应用的使用已经很广泛,目前时兴的 React、Vue、Angular 等前端框架均采用了 SPA 原则。
xiangzhihong
2023/01/06
8K0
react-router4
react-router是一些封装好的组件用于前端路由,当我们点击的时候会出现一个虚拟的路由,并不会做页面的全刷新,实现不同组件之间的切换和跳转。(当然react-router里面把history.js这个库做了封装,history.js是基于window.history做的封装,所以react-router可以调用一些会话历史, history 知道如何去监听浏览器地址栏的变化, 并解析这个 URL 转化为 location 对象, 然后 router 使用它匹配到路由,最后正确地渲染对应的组件。)
_kyle
2020/08/24
1.5K0
react-router4
ReactRouter的实现
ReactRouter是React的核心组件,主要是作为React的路由管理器,保持UI与URL同步,其拥有简单的API与强大的功能例如代码缓冲加载、动态路由匹配、以及建立正确的位置过渡处理等。
WindRunnerMax
2021/01/29
1.4K0
深入分析Vue-Router原理,彻底看穿前端路由
如今大前端的趋势下,你停下学习的脚步了吗?Vue3.0 都 Beta 了,但是还是感觉有些知识点云里雾里的,小编研究了一下Vue-Router源码整理和总结了一些东西,看尤大大怎么设计的。希望能够对你们有所帮助,如果喜欢的话,可以帮忙点个赞。
小丑同学
2020/09/21
2K0
彻底理清前端单页面应用(SPA)的实现原理
传统的多页面应用构建方式: 纯服务端渲染,前后端不分离,使用jsp,jade,'ejs','tempalte'等技术在后台先拼接成对应的HTML结构,然后转换成字符串,在每个对应的路由返回对应的数据(文件)即可 Jade模版服务端渲染,代码实现: const express= require('express') const app =express() const jade = require('jade') const result = *** const url path = *** const
Peter谭金杰
2019/08/02
3.2K2
相关推荐
如何吃透 vue-router
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档