当前位置: 首页 > 科技观察

手写简单的前端框架:Function和Class组件

时间:2023-03-22 11:37:39 科技观察

上一篇我们实现了vdom的渲染,它是前端框架的基础。但是手写vdom太麻烦了,我们又支持jsx了,用它来写页面更简洁。jsx并没有直接编译成vdom,而是生成一个render函数,执行后生成vdom。中间增加了一层额外的渲染函数来执行一些动态逻辑。别小看这一层的渲染功能,它正是实现组件的原理。实现组件渲染支持jsx后,可以执行一些动态逻辑,比如循环,比如从上下文中取值:constlist=['aaa','bbb'];constjsx={list.map(item=>{item})}render(jsx,document.getElementById('root'));这个封装成一个函数,然后传入参数不就是一个组件吗?我们在render函数中处理函数组件的渲染:if(isComponentVdom(vdom)){constprops=Object.assign({},vdom.props,{children:vdom.children});constcomponentVdom=vdom.type(props);returnrender(componentVdom,parent);}如果vdom是一个组件,则创建props作为参数传入(props要加到children上),执行函数组件,再次获取返回的vdomRender。判断组件是根据类型是否为function:functionisComponentVdom(vdom){returntypeofvdom.type=='function';}通过这几行代码,我们就实现了函数组件。测试效果,声明两个函数组件,传入props:functionItem(props){return{props.children}li>;}functionList(props){return{props.list.map((item,index)=>{returnalert(item.text)}>{item.text}})};}constlist=[{text:'aaa',color:'blue'},{text:'ccc',color:'orange'},{text:'ddd',color:'red'}]render(,document.getElementById('root'));在运行浏览器:我们已经实现了功能组件!是不是很简单!它实际上是封装成一个基于jsx的函数,然后传入参数。然后实现类组件:类组件需要声明一个有状态属性的类:classComponent{constructor(props){this.props=props||{};this.state=null;}setState(nextState){这个.state=nextState;}}然后在渲染vdom的时候,如果是class组件,单独处理:if(Component.isPrototypeOf(vdom.type)){constinstance=newvdom.type(props);constcomponentVdom=instance.render();instance.dom=render(componentVdom,parent);返回实例.dom;}else{constcomponentVdom=vdom.type(props);返回渲染(componentVdom,父);}}判断vdom是否为Component,传入props创建实例,然后调用render获取vdom并渲染。还可以在渲染前后添加生命周期函数:constinstance=newvdom.type(props);instance.componentWillMount();constcomponentVdom=instance.render();instance.dom=render(componentVdom,parent);instance.componentDidMount();返回实例.dom;这样类组件就实现了。我们测试下,声明一个类组件,传入道具,设置状态:functionItem(props){return{props.children};}classListextendsComponent{constructor(props){super();this.state={list:[{text:'aaa',color:'blue'},{text:'bbb',color:'orange'},{text:'ccc',color:'red'}],textColor:props.textColor}}render(){return{this.state.list.map((item,index)=>{returnalert(item.text)}>{item.text}})};}}仁der(,document.getElementById('root'));运行浏览器:类组件渲染成功!这样我们就实现了class组件,支持props和state代码上传到了github:https://github.com/QuarkGluonPlasma/frontend-framework-exercize总结上一篇我们支持jsx,编译生成render函数,执行之后,就可以得到vdom,然后render。加上这一层renderfunction后,可以执行很多动态逻辑,比如条件判断、循环、从context中取值。把这些逻辑封装起来就是一个组件:把它封装成一个函数,传入props,也就是把函数组件封装成一个类,传入props,并设置state属性,就是一个类组件。“组件本质上是对vdom动态渲染逻辑的封装,而函数是封装的两种形式”。实现vdom的渲染后,支持组件的两种封装形式就很简单了。至此,我们已经支持了vdom渲染、jsx编译、类和函数组件,渲染部分也差不多了。下一篇我们会实现渲染后的update,也就是patch的功能。