实现一个react系列一:JSX和虚拟DOM
前言
工作中经常使用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
等。
第二个参数:是元素的属性名,可以是className
、onClick
等。
之后的参数,是元素的子节点。
所以我们实现一个函数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相关推荐
- 从 0 到 1 实现 React 系列 —— 1.JSX 和 Virtual DOM
看源码一个痛处是会陷进理不顺主干的困局中,本系列文章在实现一个 (x)react 的同时理顺 React 框架的主干内容(JSX/虚拟DOM/组件/生命周期/diff算法/setState/ref/. ...
- 前端React教程第六课 虚拟DOM
09 真正理解虚拟 DOM:React 选它,真的是为了性能吗? 在过去的十年里,前端技术日新月异.从最早的纯静态页面,到 jQuery 一统江湖,再到近几年大火的 MVVM 框架--研发模式升级这件 ...
- 手把手教你React(一)JSX与虚拟DOM
初衷 学习React有一段时间了, 一直想找个时间写一个React的系列文章.忙里抽闲,完成了第一篇.写这系列文章的初衷是总结这段时间的技术学习,以及给那些想学习React的同学们一点帮助.我会尽量以 ...
- 深入理解React(一)JSX与虚拟DOM
初衷 使用 React 有一段时间了, 一直想找个时间写一个 React 的系列文章.忙里抽闲,完成了第一篇.写这系列文章的初衷是总结这段时间的技术学习,以及给那些想学习 React 的同学们一点帮助 ...
- 深刻理解 React (一) ——JSX和虚拟DOM
版权声明:本文由左明原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/155 来源:腾云阁 https://www.qclo ...
- react之使用js创建虚拟DOM
<!DOCTYPE html> <html> <head> <meat charset="UTF-8"> <title> ...
- jsx后缀的是什么文件_React核心特性-从JSX到虚拟DOM
JSX 简单来讲, React 为方便 View 层组件化,承载了构建 HTML 结构化页面的职责. JSX代码既可以写在.jsx后缀的文件或传统的js文件中,现在随着微软TypeScript的普及, ...
- 深入浅出React(四):虚拟DOM Diff算法解析
React中最神奇的部分莫过于虚拟DOM,以及其高效的Diff算法.这让我们可以无需担心性能问题而"毫无顾忌"的随时"刷新"整个页面,由虚拟DOM来确保只对界面 ...
- React框架简介(JSX语法、组件、虚拟DOM渲染)
目录 React框架 为什么要学习React React特点 React核心 JSX语法 语法详解 React开发过程 实际DOM 虚拟DOM React组件 函数组件 类组件 虚拟DOM渲染过程 R ...
- reactjs创建虚拟DOM的两种方式:使用jsx和js创建虚拟DOM
1_使用jsx创建虚拟DOM <!DOCTYPE html> <html lang="en"> <head><meta charset=& ...
最新文章
- Spring基础专题——第八章(事务)
- JavaScript强化教程——AJAX
- 阿里DataV可视化大屏介绍
- sklearn自学指南(part32)--保序回归
- kill 进程_如何查杀stopped进程
- 华为Mate 40工程机曝光:并未采用屏下摄像头
- jemter 使用if控制器,选择需要的内容
- 算法设计与分析--01背包问题(动态规划法解决)
- [js高手之路] 跟GhostWu一起封装一个字符串工具库-扩展trim,trimLeft,trimRight方法(2)...
- 通信原理几种调制方式
- nfc卡模式与标准模式_手机NFC卡模式功能是什么意思
- 超链接 与众不同的鼠标滑过超链接下划线动画效果
- Qt5开发从入门到精通——第六篇四节( 图像与图片——显示SVG格式图片 )
- ARM+llinux系统移植3G拨号上网收发短信(一)
- 企业管理项目应该选择什么项目管理系统?
- 学习路之html--扒取整站网页----扒站神器(Mac版跟window版)
- mysql 分区表 限制_MySQL分区表的局限和限制-阿里云开发者社区
- 领域驱动设计(DDD):分层架构的三种模式
- 数据中心linux运维学习_云计算时代数据中心运维三大要点
- 计算机考研经验贴-初试
热门文章
- linux中级之lvs配置(命令)
- (新手)使用pandas操作EXCEL
- noip模拟赛 蒜头君打地鼠
- history。go(-1)
- 荒芜的周六-PHP之面向对象(三)
- [CareerCup] 7.6 The Line Passes the Most Number of Points 经过最多点的直线
- 10074 启用开发者模式 for vs2015rc
- Oracle Concepts Guide 中 Oracle 实例 和 数据库 【关系图】
- [原]JavaScript必备知识系列-作用域
- (Linux学习笔记一:压缩)[20180209]