渲染器 render
最近在看《vue.js 设计与实现》,看到了虚拟 DOM 这里,做了个笔记
文章目录
- 1、VNode虚拟DOM节点
- 2、render工作原理
- 3、代码实现
- 4、render拓展
1、VNode虚拟DOM节点
虚拟DOM节点如下:
const vnode = {tag: 'h2',props: {class: 'active',data: 'text',onClick: () => alert('Hello Render!')},children: 'Click Me!' }
tag
:用来描述标签名称,所以tag: 'h2'
描述的就是一个<h2>
标签。props
:是一个对象,用来描述<h2>
标签的类名、属性、事件等内容。可以看到,我给h2
绑定一个active
类名,一个text
自定义属性,一个click
点击事件。children
:用来描述标签的子节点,在上面的代码中,children
是一个字符串值,意思是h2
标签有一个文本子节点:<h2>Click Me!</h2>
2、render工作原理
- 第一步: 创建元素,把
vnode.tag
作为标签名称来创建DOM元素。 - 第二步: 为元素添加属性和事件,遍历
vnode.props
对象。如果key是class
,说明它是一个类名,将其直接绑定给tag元素;如果key以on
字符串开头,说明它是一个事件,把字符on
截取掉后再调用toLowerCase
函数将事件名称小写化,最终得到合法的事件名称,例如onClick
会变成click
,最后调用addEventListener
绑定事件处理函数。 - 第三步: 处理
children
,如果children
是一个数组,就递归地调用render
继续渲染。注意,此时我们要把刚刚创建的元素作为挂载节点(父节点);如果children
是字符串,则使用createTextNode
函数创建一个文本节点,并将其添加到新的创建的元素内。
3、代码实现
自己手写一个简陋的render渲染器,上代码:
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>.active {color: red;}</style> </head><body><!-- 根节点 --><div id="app"></div><script>// 获取根节点const app = document.getElementById("app");// 要进行的挂载的虚拟 dom 节点const vnode = {// 节点类型tag: 'h2',// 节点上面绑定的类型、属性、方法props: {class: 'active', // 类名data: 'text', // 自定义属性onClick: () => alert('Hello Render!') // 方法},// 子节点children: 'Click Me!'}// 封装的渲染器 render 函数// vnode 是虚拟 dom 节点// container 是要挂载节点的元素const render = (vnode, container) => {// 根据 vnode.tag 创建对应的 dom 节点const el = document.createElement(vnode.tag);// 遍历 vnode.props,给节点绑定类名、属性、事件等for (const key in vnode.props) {if (key === 'class') {// 如果是类名,则给元素添加类名el.className += vnode.props[key]} else if (/^on/.test(key)) {// 如果属性是以 on 开头的,那么就绑定对应的事件el.addEventListener(key.substr(2).toLowerCase(), // 改变事件类型:例如 onClick 变为 clickvnode.props[key] // 绑定对应的事件)} else {// 如果是自定义属性,给元素绑定对应的属性el.setAttribute(key, vnode.props[key])}}// 处理子节点if (typeof vnode.children === 'string') {// 如果子节点是 string 类型,那么就是本文节点el.appendChild(document.createTextNode(vnode.children));} else if (Array.isArray(vnode.children)) {// 如果子节点是 array 类型,那么继续渲染子节点vnode.children.forEach(child => render(child, el));}// 将渲染的 vnode 挂载在根节点上app.appendChild(el);}// 调用 render 函数render(vnode, app)</script> </body></html>
看一下页面效果:
4、render拓展
在上面进行VNode渲染的过程,我只是讨论了当VNode是一个虚拟DOM节点的情况,那么接下来我将会讨论组件component的渲染,而component组件应该有两种情况:
- component是一个函数;
- component是一个对象;
首先直接来看代码的实现:
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>.active1 {color: red;}.active2 {color: blue;}.active3 {color: orange;}</style></head><body><!-- 根节点 --><div id="app"></div><script>// 获取根节点const app = document.getElementById("app");// 要进行绑定的 component 组件 —— 返回函数const component1 = function () {return {// 节点类型tag: 'h2',// 节点上面绑定的类型、属性、方法props: {class: 'active2', // 类名data: 'component1', // 自定义属性onClick: () => alert('Hello Component1!') // 方法},// 子节点children: 'Function Component!'}}// 要进行绑定的 component 组件 —— 返回对象const component2 = {// 该组件对象的 render 属性render() {return {// 节点类型tag: 'h2',// 节点上面绑定的类型、属性、方法props: {class: 'active3', // 类名data: 'component2', // 自定义属性onClick: () => alert('Hello Component2!') // 方法},// 子节点children: 'Object Component!'}}}// 要进行的挂载的虚拟 dom 节点(标签元素)const vnode1 = {// 节点类型tag: 'h2',// 节点上面绑定的类型、属性、方法props: {class: 'active1', // 类名data: 'vnode', // 自定义属性onClick: () => alert('Hello Render!') // 方法},// 子节点children: 'Click Me!'}// 要进行的挂载的虚拟 dom 节点(组件1)const vnode2 = {tag: component1}// 要进行的挂载的虚拟 dom 节点(组件2)const vnode3 = {tag: component2}// 挂载标签元素的方法const momentElement = (vnode, container) => {// 根据 vnode.tag 创建对应的 dom 节点const el = document.createElement(vnode.tag)// 遍历 vnode.props,给节点绑定类名、属性、事件等for (const key in vnode.props) {if (key === 'class') {// 如果是类名,则给元素添加类名el.className += vnode.props[key]} else if (/^on/.test(key)) {// 如果属性是以 on 开头的,那么就绑定对应的事件el.addEventListener(key.substr(2).toLowerCase(), // 改变事件类型:例如 onClick 变为 clickvnode.props[key] // 绑定对应的事件)} else {// 如果是自定义属性,给元素绑定对应的属性el.setAttribute(key, vnode.props[key])}}// 处理子节点if (typeof vnode.children === 'string') {// 如果子节点是 string 类型,那么就是本文节点el.appendChild(document.createTextNode(vnode.children))} else if (Array.isArray(vnode.children)) {// 如果子节点是 array 类型,那么继续渲染子节点vnode.children.forEach(child => render(child, el))}// 将渲染的 vnode 挂载在根节点上app.appendChild(el);}// 挂载组件的函数const momentComponent = (vnode, container) => {// 如果组件返回的是函数:调用组件函数,获取组件要渲染的内容(虚拟 DOM)// 如果组件返回的是对象:vnode.tag 是组件对象,调用它的 render 函数得到组件要渲染的内容(虚拟 DOM)const componentTree = typeof vnode.tag === 'function' ? vnode.tag() : vnode.tag.render()// 递归地调用 render 渲染 componentTreerender(componentTree, container)}// 封装的渲染器 render 函数// vnode 是虚拟 dom 节点// container 是要挂载节点的元素const render = (vnode, container) => {if (typeof vnode.tag === 'string') {// 如果 vnode.tag 是 string 类型,则表示该 vnode 是标签元素,调用挂载标签元素的函数momentElement(vnode, container)} else if (typeof vnode.tag === 'object' || typeof vnode.tag === 'function') {// 如果 vnode.tag 是 object 类型,则表示该 vnode 是组件,调用挂载组件的函数momentComponent(vnode, container)}}// 调用 render 函数render(vnode1, app)render(vnode2, app)render(vnode3, app)</script></body></html>
看一下页面效果:
事项说明:
- 组件就是一组DOM元素的封装
- 代码中我的注释写的都挺清楚了,一定要注意component组件的类型分为Object和Function两种类型,这两种不同情况的返回值都是不一样的,一定要注意返回值,不要搞混。
渲染器 render相关推荐
- MAUI 移植 Xamarin.Forms 自定义渲染器
简介 众所周知, .NET MAUI使用的是Handler处理程序, 而Xamarin使用的则是Render渲染器模式.尽管MAUI中使用了新的渲染模式, 但是仍然Xamarin中的支持Render渲 ...
- 7 c4d r20对win_OC渲染器Octane Render V4.0-RC7-R4 for C4D R15-R19-R20 Win/Mac
OC渲染器Octane Render V4.0-RC7-R4 for C4D R15-R19-R20 Win/Mac Octane Render 4是世界上第一款和最快的GPU加速,无偏差,物理渲染器 ...
- UE4文本渲染器Text Render技巧与支持中文
UE4文本渲染器Text Render技巧与支持中文 首先来支持中文 在目录中新建Font 修改类型 选择天下第一的思源字体 字号根据字体,选择生成以后能看清的最小 大小 字号太小会模糊,太大占资源 ...
- c4d支持mac系统渲染器有哪些_C4D Octane Render渲染器 V4.0-RC7-R4 for C4D R15-R19-R20 Win/Mac...
C4D Octane Render渲染器 V4.0-RC7-R4 for C4D R15-R19-R20 Win/Mac C4D Octane Render渲染器 V4.0-RC7-R4 for C4 ...
- 渲染测试软件 d15,D5 Render(D5 渲染器)1.7.0 正式版发布 | 一款 RTX 实时光线追踪可视化实时渲染引擎,而且是国产软件!...
长期的 Beta版公测后,D5 渲染器终于正式对外发布!最新的正式版是1.7.0.正式版将由免费版+付费增值服务这样的方式进行对外销售.另外最新还新增了社区免费版(社区免费版功能上有一点限制:无法渲染 ...
- SDL2源码分析6:拷贝到渲染器(SDL_RenderCopy())
===================================================== SDL源码分析系列文章列表: SDL2源码分析1:初始化(SDL_Init()) SDL2源 ...
- vr降噪器英文是什么_CR渲染器和VR渲染器在3d效果图上的区别
个人倾向于用max2018+VR4.2+CR5.0,安装包可共享. 没有不好用的渲染器,只有不好用的渲染技术.VR更有普遍市场,渲染速度快,CR渲染效果好,尤其灯光效果柔和. 相信不论是大神还是小白, ...
- 怎么通过id渲染页面_「快页面」动态配置化页面渲染器原理介绍
引言 「快页面」是知乎内部一个快速搭建后台管理页面的平台,使用者仅用半小时即可将一个常规复杂度的后台页面开发完成. 「快页面」平台的基石是它的「渲染器」,一个能将 JSON 配置渲染成页面的 Reac ...
- 深入学习SAP UI5框架代码系列之二:UI5 控件的渲染器
这是Jerry 2020年的第79篇文章,也是汪子熙公众号总共第261篇原创文章. 系列目录 (0) SAP UI5应用开发人员了解UI5框架代码的意义 (1) UI5 module懒加载机制 (2) ...
最新文章
- java 1%10_Java 操作符与运算符详解
- BF法-字符模式匹配
- python tqdm 不换行_python tqdm 实现滚动条不上下滚动代码(保持一行内滚动)
- CListCtrl使用技巧汇总
- 安全测试的目的,发现哪些问题
- ML之PPMCC:PPMCC皮尔逊相关系数(Pearson correlation coefficient)、Spearman相关系数的简介、案例应用之详细攻略
- 神策数据实战学堂开课,分享行业最佳业务和技术实践
- 引导类、扩展类、系统类加载器的使用及演示
- 哈达玛变换的应用SATD、SAD等匹配算法
- solr.Net课程二 solr5.5之core配置
- ElasticSearch学习(五):数据导入之Logstash
- Android Studio 4.1一键生成代码Template
- Java连接MySQL数据库步骤
- 中国共用计算机网,《中国公用计算机互联网国际联网管理办法》
- 谈谈订单号和流水号的关系
- AC上网行为管理(深信服)
- 工业级4g无线路由器_工业级4g无线路由器厂家品牌
- 芯片数据分析步骤4 标准化-affy
- 多可系统的权限规则详解
- 那些酷炫的深度学习网络图怎么画出来的?