最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 如何实现一个mini版的React(一)

    正文概述 掘金(ほうこう)   2021-03-05   586

    如何实现一个mini版的React(一)

    1、工程搭建

    我们选择零配置打包工具 parcel

    npm install -g parcel-bundler
    

    官方有详细教程,此处就不介绍了 parcel

    注意下babel的配置,React 17后 JSX 不会转换为 React.createElement

    <!--index.html-->
    <!doctype html>
    <html>
      <head>
        <title>mini-react</title>
      </head>
      <body>
        <div id="app"></div>
      </body>
      <script src="./index.js"></script>
    </html>
    
    
    //inex.js
    import React from 'react';
    import ReactDOM from 'react-dom'
    //如果是jsx对象
    const JSX = (
        <div className="active" >
            hello,<span>mini react</span>
        </div>
    )
    
    ReactDOM.render(JSX, document.querySelector('#app'));
    

    2、然后就要开始写代码了,首先分析下。实现一个迷你版的react需要哪些步骤

    • JSX是什么,虚拟DOM是什么,JSX如何转成虚拟dom
    • 虚拟DOM如何转成真是dom
    • React组件的实现
    • React组件里面的生命周期实现
    • React更新的时候diff算法
    • React setState

    3、JSX是什么,虚拟DOM是什么,JSX如何转成虚拟dom

    • 1).React 使用 JSX 来替代常规的 JavaScript。JSX 是一个看起来很像 XML 的 JavaScript 语法扩展。
    • 2)在浏览器中无法直接使用 JSX,所以大多数 React 开发者需依靠 Babel 来将 JSX 代码转换为 JavaScript
      const JSX = (
          <div className="active" >
              hello,<span>mini react</span>
          </div>
      )
    

    这段代码就是我们经常写的JSX,经过babel-plugin-transform-react-jsx转换后,变成了

    const JSX = React.createElement("div", {
      className: "active",
      title: "123"
    }, "hello,", React.createElement("span", null, "mini react"));
    

    可以看到jsx经过babel后会自动调用React.createElement,因此我们的React里面一定有一个createElement方法

    // 根目录建react文件夹, react/index.js
    function createElement (tag, attrs, ...child) {
        return {
            tag, //外层的标签 eg:div
            attrs, // 标签的属性 eg:{ className: 'active', title: '123'}
            child // 子节点
        }
    }
    const React = {
        createElement,
    }
    export default React
    

    此处可以看到createElement 返回的是一个描述html的js对象,称为虚拟dom

    4、虚拟DOM如何转成真是dom

    ReactDOM.render(JSX, document.querySelector('#app'));
    

    可以看到ReactDOM里面有一个render, 此方法就是将我们的虚拟dom渲染成真实dom的方法

    // 根目录建react-dom文件夹, react-dom/index.js
    function render (vnode, container) {
    	//如果虚拟dom不存在
        if(vnode === undefined || vnode === null || typeof vnode === 'boolean') {
            return '';
        };
    
        //如果vnode是字符串or数字
        if(typeof vnode === 'string' || typeof vnode === 'number' ) {
            //创建文本节点
            const textNode = document.createTextNode(vnode);
             container.appendChild(textNode);
        }
    
        //否则虚拟DOM
        const { tag ,attrs, child} = vnode;
        
        //创建节点对象
        let dom = '';
        if(tag) {
            dom = document.createElement(tag)
            container.appendChild(dom);
        }
    
        //递归渲染子节点
        if(child) {
            child.forEach( c => render(c, dom))
        }
        
    }
    
    const ReactDOM = {
        render
    }
    export default ReactDOM
    

    接下来。index.js里面引入刚刚写的 Reactreact-dom

    import React from './react';
    import ReactDOM from './react-dom'
    

    好了,然后执行parcel index.html 此时页面就可以渲染出来 如何实现一个mini版的React(一)

    • 但是我们发现的classNametitle 没渲染出来,所以我们需要在render方法里面定义下设置属性的方法
    
      // ...
      
      if( attrs ){
            // 有属性值 key: className="active" 
            Object.keys(attrs).forEach( key => {
                const value = attrs[key];
                setAttribute(dom, key, value); //定义下 setAttribute方法
            })
        }
        
        //...
    
    
    //设置属性
    function setAttribute(dom, key, value) {
        
        //将calssName 转成class
        if( key === 'className') {
            key = 'class'
        }
    
        //如果是事件 eg: onClick onBlur 
        if(/on\w/.test(key)) {
            //转小写
            key = key.toLowerCase();
            dom[key] = value || '';
        }
    
        if(key === 'style') {
            if(!value || typeof value === 'string') {
                //style 的值是字符串
                dom.style.cssText = value || ''
            } else if(value || typeof value === 'object'){
                //style 的值是对象
                for(let k in value) {
                    if(typeof value[k] === 'number') {
                        dom.style[key] = value[key] + 'px';
                    }else {
                        dom.style[key] = value[key];
                    }
                }
            }
        }else {
            //其他属性
            if( key in dom ) {
                // console.log('key', key, dom);
                dom[key] = value || ''
            }else if(value) {
                //更新值
                dom.setAttribute(key, value)
            }else {
                dom.removeAttribute(key)
            }
        }
    
        
    }
    

    接下来。我们发现属性 classNametitle 就可以渲染出来了 如何实现一个mini版的React(一)

    下篇文章继续介绍剩下的内容:

    • React组件的实现
    • React组件里面的生命周期实现
    • React更新的时候diff算法
    • React setState

    5、结语

    感谢各位老铁,点赞加关注

    完整代码 github


    起源地下载网 » 如何实现一个mini版的React(一)

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元