作为前端工程师,前端框架几乎天天用,需要好好掌握。可以通过能否实现来判断对某项技术的掌握程度。手写一个前端框架,对于更好的掌握是很有帮助的。现代前端框架经过多年的迭代已经变得非常复杂,梳理其实现原理也变得困难重重。所以想写一个最简单版的前端框架,帮助大家理清思路。一个完整的前端框架涉及的内容还是很多的,我们一步步来,本文将实现vdom的渲染。vdom的全称是virtualdom,用于以声明方式描述页面。许多现代前端框架都是基于vdom的。前端框架负责将vdom转化为对真实dom的增删改查,即vdom的渲染。那么vdom是什么样子的呢?它是如何渲染的?DOM主要是元素、属性和文本,vdom也是一样,其中元素是{type,props,children}结构,文本是字符串和数字。比如这样一个vdom:{type:'ul',props:{className:'list'},children:[{type:'li',props:{className:'item',style:{background:'blue',color:'#fff'},onClick:function(){alert(1);}},children:['aaaa']},{type:'li',道具:{className:'item'},children:['bbbbddd']},{type:'li',props:{className:'item'},children:['cccc']}]}不难看出它描述了一个ul元素,它有三个li子元素,第一个子元素有一个style样式和一个onClick事件。前端框架通过这样的对象结构来描述界面,然后渲染到dom中。如何渲染这样的对象结构?很明显,递归是用来区别对待不同类型的。如果是文本类型,则使用document.createTextNode创建一个文本节点。如果是元素类型,则使用document.createElement创建元素节点。元素节点也有属性需要处理,递归渲染子节点。所以,vdom的渲染逻辑是这样的:。类型));for(constchildofvdom.children){render(child,dom);}for(constpropinvdom.props){setAttribute(dom,prop,vdom.props[prop]);}返回dom;}判断text是string和number:functionisTextVdom(vdom){returntypeofvdom=='string'||typeofvdom=='number';}判断element是object,type是标签名的字符串:functionisElementVdom(vdom){returntypeofvdom=='object'&&typeofvdom.type=='string';}元素创建完成后,如果有父节点需要挂载到父节点,组装成dom树:constmount=parent?(el=>parent.appendChild(el)):(el=>el);所以,完整的渲染函数看起来像这样:constrender=(vdom,parent=null)=>{constmount=parent?(el=>parent.appendChild(el)):(el=>el);如果(isTextVdom(vdom)){returnmount(document.createTextNode(vdom));}elseif(isElementVdom(vdom)){constdom=mount(document.createElement(vdom.type));for(constchildofvdom.children){render(child,dom);}for(constpropinvdom.props){setAttribute(dom,prop,vdom.props[props]);}返回dom;}};其中,元素的dom还需要设置属性,比如上面vdom中的style和onClick属性。对象合并后设置为style,onClick属性为事件监听器,用addEventListener设置,其余属性用setAttribute设置。constsetAttribute=(dom,key,value)=>{if(typeofvalue=='function'&&key.startsWith('on')){consteventType=key.slice(2).toLowerCase();dom.addEventListener(事件类型,值);}elseif(key=='style'&&typeofvalue=='object'){Object.assign(dom.style,value);}elseif(typeofvalue!='object'&&typeofvalue!='function'){dom.setAttribute(key,value);}}这样,vdom的渲染逻辑就完成了。使用上面的vdom渲染试试效果:render(vdom,document.getElementById('root'));vdom渲染成功!总结:《vdom会递归渲染,根据不同的类型,元素和文本会分别渲染使用createTextNode和createElement递归创建dom组装在一起,元素还需要设置属性,样式,事件监听器等属性是分别通过addEventListener、setAttribute等API进行设置。”“通过不同的API创建dom和设置属性,这就是vdom的渲染过程。”但是vdom写起来太麻烦,没有人会直接写vdom,通常是通过比较友好的DSL(领域特定语言)编写,然后编译成vdom,比如jsx和template,这里我们使用jsx方法,因为可以直接用babel编译将jsx编译成vdom上面的vdom改成jsx这样写:constjsx=
