前言

工作中经常使用react,对于react中的一些虚拟DOM、生命周期、组件等概念知其然,不知其所以然。虽然知道这些怎么用的就足够应付大部分的工作,但是作为一个开发者,还是要有追求的。所以有了这个系列,一步一步实现一个简单的react出来。

语法糖JSX

我们平时在react中写的JSX,其实是一种语法糖,会被babel转换成React.createElement()。我们可以在babel官网上做个实验,看下JSX会被babel转换成什么。下面是个简单的例子。

我们可以看到,JSX会被转成React.createElement(tag, attrs, child1, child2, ...)这种形式。那我们只要装个babel插件,然后写个createElement方法就可以处理JSX代码了。

createElement方法和虚拟DOM

  • 准备

首先安装babel模块,babel.babelrc配置如下:

{"presets": ["env"],"plugins": [["transform-react-jsx",{"pragma": "React.createElement"}]]
}
复制代码

使用打包工具parcel,webpack也可以。比较懒,使用了parcel来打包代码。

  • 实现

上面我们已经提到了JSX会被babel转换为React.createElement(tag, attrs, child1, child2, ...)
第一个参数:是元素的标签名,可以是div、span等。
第二个参数:是元素的属性名,可以是classNameonClick等。
之后的参数,是元素的子节点。
所以我们实现一个函数createElement,接受上面的参数,然后将这些参数返回就可以了。

const createElement = (tag, attrs, ...childs) => {return { tag, attrs, childs }
}
复制代码

看下效果如何。

const React = {createElement
}const title = (<div className="title"><p>Hello, world!</p></div>
)
console.log(title)
复制代码

打开Chrome的控制台,我们可以看到差不多是我们想要的。

createElement方法返回的对象就是虚拟DOM,这个对象中记录了该DOM节点的所有信息,根据这些信息我们可以将虚拟DOM转化为真实的DOM

将虚拟DOM渲染成真实DOM

在react中,将vdom渲染成真实的DOM,我们使用的是ReactDOM.render,像这样。

ReactDOM.render(<div>Hello, world!</div>, // 这个会被转化为vdomdocument.getElementById('root') // 获取根节点
)
复制代码

我们可以看出,render实现的功能是将vdom转化为真实的dom,挂载到根节点上。明白这一点,代码就很好写了。

const ReactDom = {render
}
// 将 vdom 转换为真实 dom
const render = (vdom, root) => {if (typeof vdom === "string") {// 子元素如果是字符串,直接拼接字符串root.innerText += vdomreturn}const dom = document.createElement(vdom.tag)if (vdom.attrs) {for (let attr in vdom.attrs) {const value = vdom.attrs[attr]setAttribute(dom, attr, value)}}// 遍历子节点vdom.childs.forEach(child => render(child, dom))// 将子元素挂载到其真实 DOM 的父元素上root.appendChild(dom)
}
// 设置 dom 节点属性
const setAttribute = (dom, attr, value) => {if (attr === "className") {attr = "class"}// 处理事件if (/on\w+/.test(attr)) {attr = attr.toLowerCase()dom[attr] = value || ""} else if (attr === "style" && value) {// 处理 style 样式,可以是个字符串或者对象if (typeof value === "string") {dom.style.cssText = value} else if (typeof value === "object") {for (let styleName in value) {dom.style[styleName] =typeof value[styleName] === "number"? value[styleName] + "px": value[styleName]}}} else {// 其他属性dom.setAttribute(attr, value)}
}
复制代码

这样我们就将虚拟dom渲染成真实的dom,考虑到热更新,我们需要在render之前先清除下root节点下的内容。

const ReactDOM = {render: (vdom, root) => {root.innerText = ""render(vdom, root)}
}
复制代码

总结

react中,jsx会被babel转化为React.createElement(标签、属性、子元素1、子元素2、...)形式,该函数返回一个对象,即虚拟dom。然后ReactDOM.render(),会将虚拟dom转化为真实的dom
附上本文代码地址

实现一个react系列一:JSX和虚拟DOM相关推荐

  1. 从 0 到 1 实现 React 系列 —— 1.JSX 和 Virtual DOM

    看源码一个痛处是会陷进理不顺主干的困局中,本系列文章在实现一个 (x)react 的同时理顺 React 框架的主干内容(JSX/虚拟DOM/组件/生命周期/diff算法/setState/ref/. ...

  2. 前端React教程第六课 虚拟DOM

    09 真正理解虚拟 DOM:React 选它,真的是为了性能吗? 在过去的十年里,前端技术日新月异.从最早的纯静态页面,到 jQuery 一统江湖,再到近几年大火的 MVVM 框架--研发模式升级这件 ...

  3. 手把手教你React(一)JSX与虚拟DOM

    初衷 学习React有一段时间了, 一直想找个时间写一个React的系列文章.忙里抽闲,完成了第一篇.写这系列文章的初衷是总结这段时间的技术学习,以及给那些想学习React的同学们一点帮助.我会尽量以 ...

  4. 深入理解React(一)JSX与虚拟DOM

    初衷 使用 React 有一段时间了, 一直想找个时间写一个 React 的系列文章.忙里抽闲,完成了第一篇.写这系列文章的初衷是总结这段时间的技术学习,以及给那些想学习 React 的同学们一点帮助 ...

  5. 深刻理解 React (一) ——JSX和虚拟DOM

    版权声明:本文由左明原创文章,转载请注明出处:  文章原文链接:https://www.qcloud.com/community/article/155 来源:腾云阁 https://www.qclo ...

  6. react之使用js创建虚拟DOM

    <!DOCTYPE html> <html> <head> <meat charset="UTF-8"> <title> ...

  7. jsx后缀的是什么文件_React核心特性-从JSX到虚拟DOM

    JSX 简单来讲, React 为方便 View 层组件化,承载了构建 HTML 结构化页面的职责. JSX代码既可以写在.jsx后缀的文件或传统的js文件中,现在随着微软TypeScript的普及, ...

  8. 深入浅出React(四):虚拟DOM Diff算法解析

    React中最神奇的部分莫过于虚拟DOM,以及其高效的Diff算法.这让我们可以无需担心性能问题而"毫无顾忌"的随时"刷新"整个页面,由虚拟DOM来确保只对界面 ...

  9. React框架简介(JSX语法、组件、虚拟DOM渲染)

    目录 React框架 为什么要学习React React特点 React核心 JSX语法 语法详解 React开发过程 实际DOM 虚拟DOM React组件 函数组件 类组件 虚拟DOM渲染过程 R ...

  10. reactjs创建虚拟DOM的两种方式:使用jsx和js创建虚拟DOM

    1_使用jsx创建虚拟DOM <!DOCTYPE html> <html lang="en"> <head><meta charset=& ...

最新文章

  1. Spring基础专题——第八章(事务)
  2. JavaScript强化教程——AJAX
  3. 阿里DataV可视化大屏介绍
  4. sklearn自学指南(part32)--保序回归
  5. kill 进程_如何查杀stopped进程
  6. 华为Mate 40工程机曝光:并未采用屏下摄像头
  7. jemter 使用if控制器,选择需要的内容
  8. 算法设计与分析--01背包问题(动态规划法解决)
  9. [js高手之路] 跟GhostWu一起封装一个字符串工具库-扩展trim,trimLeft,trimRight方法(2)...
  10. 通信原理几种调制方式
  11. nfc卡模式与标准模式_手机NFC卡模式功能是什么意思
  12. 超链接 与众不同的鼠标滑过超链接下划线动画效果
  13. Qt5开发从入门到精通——第六篇四节( 图像与图片——显示SVG格式图片 )
  14. ARM+llinux系统移植3G拨号上网收发短信(一)
  15. 企业管理项目应该选择什么项目管理系统?
  16. 学习路之html--扒取整站网页----扒站神器(Mac版跟window版)
  17. mysql 分区表 限制_MySQL分区表的局限和限制-阿里云开发者社区
  18. 领域驱动设计(DDD):分层架构的三种模式
  19. 数据中心linux运维学习_云计算时代数据中心运维三大要点
  20. 计算机考研经验贴-初试

热门文章

  1. linux中级之lvs配置(命令)
  2. (新手)使用pandas操作EXCEL
  3. noip模拟赛 蒜头君打地鼠
  4. history。go(-1)
  5. 荒芜的周六-PHP之面向对象(三)
  6. [CareerCup] 7.6 The Line Passes the Most Number of Points 经过最多点的直线
  7. 10074 启用开发者模式 for vs2015rc
  8. Oracle Concepts Guide 中 Oracle 实例 和 数据库 【关系图】
  9. [原]JavaScript必备知识系列-作用域
  10. (Linux学习笔记一:压缩)[20180209]