菜鸟二站站员学习React之JSX

252 阅读2分钟

JSX是什么?

既不是字符串也不是 HTML,是一种类似 XML 的语法标签,不能直接在浏览器运行,他是通过各种编译器编译成Js标准可执行的语法。

JSX使用规则

  • 代码块(以 { 开头),就用JavaScript规则解析。
  • (以 < 开头)标签,就用HTML规则解析;
  • 用小骆驼峰定义属性名称
  • 自定义属性 data-[属性名称]

JSX怎么编译的

解析

JSX 不是标准的Javascript代码它需要babel-preset-react-app语法解析包解析成Javascript可识别的代码,把jsx语法标签转义成React.createElement() 方法调用。

const element = (
    <div className="my-class" >JSX语法标签</div>
);

babel 转义成:

const element = React.createElement(
    'div', // type 标签
    {className:'my-class'}, // props 属性
    'JSX语法标签' // children 内容
);

生成虚拟DOM

React.createElement 将转化成为一个虚拟DOM,也就是一个对象。

   const jsxObj =  {
      type: 'div', // 存储的是标签名或者组件名
       props: {    // props: 属性对象(给当前元素设置的属性都在这里)(如果有子元素,会多一个children属性,依次把子元素传递进来,没有就没有children属性)
        style: '',
        className: 'my-class',
        children: 'JSX语法标签' // 可能有可能没有,有的话:可能是一个数组,也可能是一个字符串或者是一个对象。
      },
      key: null,
      ref: null
    }

生成真实DOM

render 原理是将 jsx 生成的对象生成 'type' 类型的 DOM 元素,把属性 'props' 遍历追加到DOM上面,例如类名className,style,children...,然后 挂载在指定的容器上。

下面是自定义的一个 render函数:

function render(jsxObj, container,callback){
    let {type,props} = jsxObj;
    // 创建一个dom
    let element = document.createElement(type);
    for(let key in props){
        _props = props[key];
        if(element.hasOwnProperty(key))break;
        if(typeof _props=='undefined')break;
        // 事件监听
        if(key.startsWith('on')){
            let attch= key.slice(2).toLowerCase();
            element.addEventListener(attch, _props, false);
            continue;
        }
        key = key.toUpperCase();

        switch (key){
             case 'CHILDREN':
                // 判断是否有子dom
                if (typeof _props === "string"){
                    element.innerText = _props
                }else {
                  // 递归  
                    for(let children in _props){
                        render(children,element)
                    }
                }
                break;
             case 'STYLE':
                
                let _style =  Object.keys(_props).map((name)=>{
                    let value = _props[name];
                    return `${name}:${value}`;
                }).join(';');
                element.setAttribute('style', _style)
                break;
             case 'CLASSNAME':
                element.setAttribute('class', _props)
                break;
             default:
                // 其它属性
                break;
        }
    }   
    
   container.appendChild(element);
   callback&&callback();
}

注意事项

  • 属性名称是小驼峰命名
  • jsx语法中只能有一个顶级标签(元素)
  • 使用组件时,首字母必须大写
  • jsx表达式不能使用if else(可以使用三元运算符)
  • 调用的方法会指向 undefined, 其实就是this指向的问题了

这不是React bug,这是JavaScript中本来就有的。如果你传递一个函数名给一个变量,然后通过在变量后加括号()来调用这个方法,

    const obj = {
        title: 'JSX',
        func:function(){
            console.log(this)
        }       
    }
    obj.func(); // this指向obj

    let funcb = obj.func
    funcb(); // this指向window

JSX优点

  • JSX执行更快
  • 更安全防止注入攻击,编译时能及时发现错误
  • 便于开发着阅览,编写模板更加简单快速