React 虚拟dom是如何实现的
来源:互联网 发布:java属性签名是什么 编辑:程序博客网 时间:2024/05/16 03:52
JSX是比较简单的:花一分钟时间阅读本篇文章,你将会理解有关模板的有趣替代方案的所有内容。
替代标题:和JSX在一起
指令
你可以声明每个文件或每个函数来告诉你的转换器(如:Babel)每个节点在运行时应该调用的函数名称(参见:Transpilation)
/** @jsx h **/
转换
如果你还没有使用转换器,对,你可能就是。使用ES6/ES2015时,在开发、调试、测试以及运行JavsScript会更加高效。而这样的场景下Babel是一个非常流行且极力推荐的转换器,所以,我在这里我将假设你正在使用它。
除了将ES6/ES7+语法转换为当下各个浏览器都支持的JavaScript,Babel在转换JSX时也非常方便,你不需要添加或修改任何内容就可以使用此功能。
通过一个非常简单的例子可以很容易的看出这是如何实现的:
Before:(转换前你写的代码)
/** @jsx h **/let foo = <div id="foo">Hello!</div>
After:(转换后的可运行代码)
var foo = h("div", {id:"foo"}, "Hello")';
看到第二个代码片段后你可能会想通过函数的方式构建UI还不是很差。。。
这就是为什么我刚开始使用JSX的想法:如果JSX从地球上消失,用手写的输出依然很舒服。
JSX只是一个很不错的语法糖
有人甚至用它来实现了一个项目:hyperscript
一起来实现一个JSX渲染器
首先,我们需要定义一个在转换后代码中调用的h()函数。
你也可以定义一个任何你想要的名字,我使用h()是因为这类“构建”函数最开始被称为hyperscript("hypertext"+"javascript")
function h(nodeName, attributes, ...args){ let children = args.length ? [].concat(...args) : null; return { nodeName, atributes, children };}
好了,这很简单。
不熟悉ES6/ES2015?
- ... 在参数列表中被称为rest(剩余)参数。它将“剩余”的参数收集到数组中。
- concat(...args) 是一个扩展操作符:它拿到一个数组并把数组展开为 concat() 的参数。这里使用 concat() 是折叠子节点的任何嵌套数组。
现在我们有了这些h()函数吐出来的嵌套JSON对象,所以,我们得到这样一颗“树”:
{ nodeName: "div", attributes: { "id": "foo" }, children: ["Hello!"]}
然后,我们仅需要一个接受这种格式参数并吐出实际DOM节点的函数:
function render(vnode){ // 字符串转换为#text节点 if (vnode.split) return document.createTextNode(vnode); // 根据VDOM节点的节点名称创建一个DOM元素 let n = document.createElement(vnode.nodeName); let a = vnode.attributes || {}; Object.keys(a).forEach( k => n.setAttribute(k, a[k]) ); // 渲染并追加到子节点列表 (vnode.children || []).forEach( c => n.appendChild(render(c)) ); return n;}
理解它是如何工作的很容易。
如果需要,你可以把”虚拟DOM”想象成作为生成DOM结构的很简单的配置。
虚拟DOM的好处是它是个非常轻量、小对象引用其他小对象,非常容易优化的应用程序结构。
这也意味着它不会尝试任何渲染逻辑或慢DOM操作方法。
使用JSX
我们知道JSX被转换为h()函数调用。这些函数调用创建一个简单的“虚拟”DOM树。
我们可以使用render()函数去创建匹配的“真实”DOM树。
就像这个样子:
// JSX -> VDOMlet vdom = <div id="foo">Hello!</div>;// VDOM -> DOM;let dom = render(vdom);// 添加树到<body>document.body.appendChild(dom);
分片、迭代和逻辑:没有新语法
我们拥有所有JavaScript特性,而不是一般模板语言引入的有限的概念。
“分片”是无逻辑/有限逻辑模板引擎引入的概念,用于在不同的上下文中重用的视图片段。
迭代是每一个模板语言好像重复发明的事物(我和任何人一样有罪)。使用JSX,没有一次性的语法去学习:迭代你在JavaScript程序中的其他任何地方。您选择最适合给定任务的迭代风格:[].forEach()、[].map()、for和while循环等。
像迭代一样,逻辑也是模板语言喜欢重新发明的事物。一方面,无逻辑模板提供了将逻辑嵌入到视图中的最差的方法:诸如{{#if value}}的有限构造将逻辑推入控制器层,鼓励膨胀。这规避了构建一种描述更复杂逻辑的语言,避免可预测性和安全隐患。
另一方面,使用代码生成的引擎(一种简陋到不可原谅的技术),通常自诩具有执行逻辑甚至迭代的任意JavaScript表达式的能力。这是一个很好的理由,不惜一切代价避免这种情况:您的代码被从原始位置(可能是模块、闭包或者标记内)中剥离出来,并评估到“其他地方”。那样对我来说是不可预测或足够安全的。
JSX允许所有JavaScript语言特性,不依赖在开发阶段产生的奇形怪状的代码,而且不需要eval(),更加友好。
// 我们想展示到列表中的字符串数组let items = ['foo', 'bar', 'bza'];// 提供一些文本创建一个列表项function item(text) { return <li>{text}</li>}// 具有“迭代”和“分片”的“视图”let list = render( <ul> { items.map(item) } </ul>);
render()返回一个DOM节点(上例中的<ul>),所以,我们仅仅需要把它放入到DOM中:
document.body.appendChild(list);
合在一起
这些是上面提到的简单版的虚拟DOM渲染器和它用到的视图的完整源码。
const ITEMS = 'hello there people'.split(' ');// 将数组转换成列表项:let list = items => items.map( p => <li> {p} </li> );// 通过调用(“分片”)来从一个数值中生成列表的视图let vdom = ( <div id="foo"> <p>Look,a simple JSX DOM renderer!</p> <ul>{ list(ITEMS) }</ul> </div>);// render() 将“虚拟DOM”转换成真实的DOM树let dom = render(vdom);// 将新的DOM节点放到某个位置document.body.appendChild(dom);// 记住什么是“虚拟DOM”?它只是一个JSON - 每一个“VNode”是一个有3个属性的对象。let json = JSON.stringify(vdom, null, ' ');// 整个过程(JSX -> VDOM -> DOM)在一步完成document.body.appendChild( render( <pre id="vdom">{ json }</pre> ));
- React 虚拟dom是如何实现的
- 虚拟 DOM 内部是如何工作的?
- React 虚拟DOM的理解
- React虚拟DOM的原理&&为什么使用虚拟DOM
- React:虚拟DOM
- React虚拟DOM浅析
- React基本原理-虚拟DOM
- React虚拟DOM浅析
- React 虚拟DOM
- React虚拟DOM浅析
- React虚拟DOM浅析
- 浅谈React的最大亮点——虚拟DOM
- 实现一个简单的虚拟DOM
- 如何理解虚拟DOM?
- 如何理解虚拟DOM
- 全面理解虚拟DOM,实现虚拟DOM
- 全面理解虚拟DOM,实现虚拟DOM
- 全面理解虚拟DOM,实现虚拟DOM
- stm32_013_STM32printf()函数重定向到串口
- Spring Cloud(五)断路器监控(Hystrix Dashboard)
- IBM-UK ftp资料站
- 【概率论与数理统计】-排列组合笔试题汇总
- Hadoop本地模式、伪分布模式的安装
- React 虚拟dom是如何实现的
- Slim研读笔记五之依赖注入容器(下)
- 架构设计的关键原则
- Android性能优化工具之StrictMode
- UNIX环境高级编程-打印进程ID
- Java中System.out.println("Hello, World");深入剖析
- 【比特币】通过dns seeds获取节点列表数据
- SpringCache实现原理及核心业务逻辑(三)
- AES128-ecb加解密