手写一个简单的React--函数组件

/react/component.js

class Component {
    constructor(props = {}) {
        this.props = props
        this.state = {}
    }
}
export default Component

改造render方法

import Component from '../react/component'
const ReactDom = {
    render
}
function render(vnode, container) {
    return container.appendChild(_render(vnode))
}
function createComponent(comp, props) {
    let inst
    if (comp.prototype && comp.prototype.render) {
        //如果是类组件 则创建实例
        inst = new comp(props)
    } else {
        //如果是函数组件 将函数组件扩展成类组件
        inst = new Component(props)
        inst.constructor = comp
        inst.render = function () {
            return this.constructor(props)
        }
    }
    return inst
    //如果是函数组件
}
function renderComponent(comp) {
    const renderer = comp.render()
    _render(renderer)
}
function setComponentProps(comp, attrs) {
    //设置组件的属性
    comp.props = props
    //渲染组件
    let base = renderComponent(comp)
    comp.base = base
}
function _render(vnode) {
    if (vnode === undefined || vnode === null || typeof vnode === 'boolean') {
        return
    }
    if (typeof vnode === 'string') {
        //创建文本节点
        return document.createTextNode(vnode)
    }
    //如果tag是函数
    if (typeof vnode.tag === 'function') {
        //1创建组件
        const comp = createComponent(vnode.tag, vnode.attrs)
        //2 设置组件的属性
        setComponentProps(comp, vnode.attrs)
        ///3 组件渲染的节点对象返回
        return comp.base
    }
    //虚拟dom
    const { tag, attrs, childrens } = vnode
    const dom = document.createElement(tag)
    if (attrs) {
        //遍历
        Object.keys(attrs).forEach(key => {
            const value = attrs[key]
            setAttribute(dom, key, value)
        })
    }
    //遍历子节点
    childrens.forEach(child => {
        render(child, dom)
    })
    return dom
}
//设置属性
function setAttribute(dom, key, value) {
    //将className转换成class
    if (key === 'className') {
        key = 'class'
    }
    //如果是事件 onClick onBlur...
    if (/on\w+/.test(key)) {
        key = key.toLowerCase()
        dom[key] = value || ''
    } else if (key === 'style') {
        if (!value || typeof value === 'string') {
            dom.style.cssText = value
        } else if (value && typeof value === 'object') {
            //{width:20}
            for (let k in value) {
                if (typeof value[k] === 'number') {
                    dom.style[key] = value[k] + 'px'
                } else {
                    dom.style[key] = value[k]
                }
            }
        }
    }
    else {
        //其他属性
        if (key in dom) {
            dom[key] = value || ''
        }
        if (value) {
            dom.setAttribute(key, value)
        } else {
            dom.removeAttribute(key)
        }
    }
}
export default ReactDom
全部评论

相关推荐

肤浅的羊:谜语人能不能直说呀
投递字节跳动等公司10个岗位 > 非技术求职现状
点赞 评论 收藏
分享
10-25 00:32
香梨想要offer:感觉考研以后好好学 后面能乱杀,目前这简历有点难
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务