react系列一,react虚拟dom如何转成真实的dom
react,想必作为前端开发一定不陌生,组件化以及虚拟dom使得react成为最受欢迎额前端框架之一。我们知道react是基于虚拟dom的,但是什么是虚拟dom呢,其实就是一组js对象,那么我们今天就来认识什么是虚拟dom,以及如何转成真实的dom结构,完整的 简易版react 在个人github,实现了diff算法,组件渲染,组件更新,钩子函数。
一.认识虚拟dom
首先我们看如下代码
const title = <h1 className="title">Hello, world!</h1>;
这并不是合法的js代码,它是一种被称为jsx的语法扩展,通过它我们就可以很方便的在js代码中书写html片段。
本质上,jsx是语法糖,上面这段代码会被babel转换成如下代码
我们下载插件 babel-plugin-transform-react-jsx,并且配置.babelrc文件
{
"presets": ["env"],
"plugins": [
["transform-react-jsx", {
"pragma": "React.createElement"//大部分框架喜欢改成h
}]
]
}
于是页面中的jsx就会被babel转成如下的结构
const title = React.createElement(
'h1',
{ className: 'title' },
'Hello, world!'
);
可以看出babel已经把一个dom元素分解成标签名称h1,属性集合对象,以及内部子节点(这里是hello world文本节点),我们首先修改这个方法,为了转成我们需要的结构
function createElement( tag, attrs, ...children ) {
return {
tag,
attrs,
children
}
}
// 将上文定义的createElement方法放到对象React中
const React = {
createElement,
}
函数的参数...children使用了ES6的rest参数,它的作用是将后面child1,child2等参数合并成一个数组children。
现在我们来试试调用它,一下结构都是babel自动调用React.createElement给我们转成的,当然你也可以自己写方法将真实的dom转为js对象
const element = (
<div>
hello<span>world!</span>
</div>
);
console.log( element );

二.将上列的虚拟dom结构转成真实的dom
1.如果遇到文本节点则直接返回新建的文本节点
//处理文本节点
if( typeof vnode === 'string'){
const textNode = document.createTextNode( vnode )
return textNode;
}
2.处理普通的元素
//普通的dom
const dom = document.createElement( vnode.tag );
if( vnode.attrs ){
Object.keys( vnode.attrs ).forEach( key => {
const value = vnode.attrs[ key ];
setAttribute( dom, key, value ); // 设置属性
} );
}
vnode.children.forEach( child => render( child, dom ) ); // 递归渲染子节点
return dom ; // 返回虚拟dom为真正的DOM
3.遇到普通元素的属性,需要这是属性节点,但是分为两种,一种是普通的属性,比如className,另一种是方法绑定,比如是onClick
function setAttribute( dom, name, value ) {
// 如果属性名是className,则改回class
if ( name === 'className' ) name = 'class';
// 如果属性名是onXXX,则是一个事件监听方法
if ( /on\w+/.test( name ) ) {
name = name.toLowerCase();
dom[ name ] = value || '';
// 如果属性名是style,则更新style对象
} else if ( name === 'style' ) {
if ( !value || typeof value === 'string' ) {
dom.style.cssText = value || '';
} else if ( value && typeof value === 'object' ) {
for ( let name in value ) {
// 可以通过style={ width: 20 }这种形式来设置样式,可以省略掉单位px
dom.style[ name ] = typeof value[ name ] === 'number' ? value[ name ] + 'px' : value[ name ];
}
}
// 普通属性则直接更新属性
} else {
if ( name in dom ) {
dom[ name ] = value || '';
}
if ( value ) {
dom.setAttribute( name, value );
} else {
dom.removeAttribute( name, value );
}
}
}
三.查看完整的代码
function render ( vnode, container ){
return container.appendChild( _render( vnode ) );
}
function _render( vnode ){
if ( typeof vnode === 'number' ) {
vnode = String( vnode );
}
//处理文本节点
if( typeof vnode === 'string'){
const textNode = document.createTextNode( vnode )
return textNode;
}
//处理组件
if ( typeof vnode.tag === 'function' ) {
const component = createComponent( vnode.tag, vnode.attrs );
setComponentProps( component, vnode.attrs );
return component.base;
}
//普通的dom
const dom = document.createElement( vnode.tag );
if( vnode.attrs ){
Object.keys( vnode.attrs ).forEach( key => {
const value = vnode.attrs[ key ];
setAttribute( dom, key, value ); // 设置属性
} );
}
vnode.children.forEach( child => render( child, dom ) ); // 递归渲染子节点
return dom ; // 返回虚拟dom为真正的DOM
}
//实现dom挂载到页面某个元素
const ReactDOM = {
render: ( vnode, container ) => {
container.innerHTML = '';
return render( vnode, container );
}
}
现在我们已经实现将虚拟dom转为真实的dom,已经绑定属性,我们现在来像react一样调用这个方法
const element = (
<div>
hello<span>world!</span>
</div>
); ReactDOM.render(
element,
document.getElementById( 'main' )
);
现在就实现往页面中元素id为main的元素上挂载了该element。
react系列一,react虚拟dom如何转成真实的dom的更多相关文章
- react系列从零开始-react介绍
react算是目前最火的js MVC框架了,写一个react系列的博客,顺便回忆一下react的基础知识,新入门前端的小白,可以持续关注,我会从零开始教大家用react开发一个完整的项目,也会涉及到w ...
- React系列文章:JSX生成真实DOM结点
在上一篇文章中,我们介绍了Babel是如何将JSX代码编译成可执行代码的,随后也实现了一个自己的解析器,模拟了Babel编译的过程. 现在我们再来回顾一下,假定有如下业务代码: const style ...
- [react] 什么是虚拟dom?虚拟dom比操作原生dom要快吗?虚拟dom是如何转变成真实dom并渲染到页面的?
壹 ❀ 引 虚拟DOM(Virtual DOM)在前端领域也算是老生常谈的话题了,若你了解过vue或者react一定避不开这个话题,因此虚拟DOM也算是面试中常问的一个点,那么通过本文,你将了解到如下 ...
- React 学习(一) ---- React Element /组件/JSX
学习React的时候,你可能听到最多的就是要先学习webpack, babel,要先学会配置然后才能学react 等等,一堆的配置就把我们吓着了,根本就没有心情就学习react了.其实在最开始学习re ...
- React 引入import React 原理
本质上来说JSX是React.createElement(component, props, ...children)方法的语法糖. 所以我们如果使用了JSX,我们其实就是在使用React,所以我们就 ...
- 从 0 到 1 实现 React 系列 —— 1.JSX 和 Virtual DOM
看源码一个痛处是会陷进理不顺主干的困局中,本系列文章在实现一个 (x)react 的同时理顺 React 框架的主干内容(JSX/虚拟DOM/组件/生命周期/diff算法/setState/ref/. ...
- 深刻理解 React (一) ——JSX和虚拟DOM
版权声明:本文由左明原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/155 来源:腾云阁 https://www.qclou ...
- React会自动把虚拟DOM数组展开
React会自动把虚拟DOM数组展开,放在父级虚拟DOM中,这个特性还是我同事帮我解决一个问题的时候,偶然发现的. 如何将一个数据数组转换为一个虚拟DOM的数组,需要使用map,如下: const n ...
- 【React 7/100 】 虚拟DOM和Diff算法
虚拟DOM和Diff算法 React更新视图的思想是:只要state变化就重新渲染视图 特点:思路非常清晰 问题:组件中只有一个DOM元素需要更新时,也得把整个组件的内容重新渲染吗? 不是这样的 理想 ...
随机推荐
- Linux输入子系统:多点触控协议 -- multi-touch-protocol.txt768
转自:http://blog.csdn.net/droidphone/article/details/8434768 Multi-touch (MT) Protocol --------------- ...
- mysql 、慢查询、到底如何玩
在项目开发中,那些开发大佬经常会写出一些SQL语句,一条糟糕的SQL语句可能让你测试的整个程序都非常慢,超过10秒的话,我觉得一般用户就会选择关闭网页,如何优化SQL语句将那些运行时间 比较长的SQL ...
- namesapce的作用 增加访问路径 目的:区分不同包的相同action的访问路径
- day 03 字符串 for 循环
1.有变量量name = "aleX leNb" 完成如下操作: 1)移除 name 变量量对应的值两边的空格,并输出处理理结果 name = "aleX leNb&qu ...
- C++解析(12):初始化列表与对象构造顺序、析构顺序
0.目录 1.类成员的初始化 2.类中的const成员 3.对象的构造顺序 3.1 局部对象的构造顺序 3.2 堆对象的构造顺序 3.3 全局对象的构造顺序 4.对象的析构顺序 5.小结 1.类成员的 ...
- 洛谷 P4139 上帝与集合的正确用法
题目描述 根据一些书上的记载,上帝的一次失败的创世经历是这样的: 第一天, 上帝创造了一个世界的基本元素,称做“元”. 第二天, 上帝创造了一个新的元素,称作“α”.“α”被定义为“元”构成的集合.容 ...
- [AT2377] [agc014_e] Blue and Red Tree
题目链接 AtCoder:https://agc014.contest.atcoder.jp/tasks/agc014_e 洛谷:https://www.luogu.org/problemnew/sh ...
- PyCharm入门教程——在编辑器中打开和重新打开文件
PyCharm最新版本下载 JetBrains PyCharm是一种Python IDE,其带有一整套可以帮助用户在使用Python语言开发时提高其效率的工具.此外,该IDE提供了一些高级功能,以用于 ...
- SCWS中文分词,demo演示
上文已经讲了关于SCSW中文分词的安装配置,本节进入demo演示: <?php header('Content-Type:text/html;charset=UTF-8'); echo '< ...
- 服务器版“永恒之蓝”高危预警 (Samba远程命令执行漏洞CVE-2017-7494) 攻击演示
漏洞信息: 2017年5月24日Samba发布了4.6.4版本,中间修复了一个严重的远程代码执行漏洞,漏洞编号CVE-2017-7494,漏洞影响了Samba 3.5.0 之后到4.6.4/4.5.1 ...