JSX是什么鬼?

205 阅读2分钟

JSX实际上非常简单:花1分钟阅读本文,您将了解关于这个模板替代方案的所有内容。

备选标题:“使用JSX”

Pragma

你可以通过文件或函数声明这个指令,告诉你的转译器(例如:Babel)为每个节点调用。

在下面的例子中,我们说“为每个节点注入 h() 函数的调用”:

/** @jsx h */

Transpilation

如果你还没有使用转译器。在你使用ES6/ES2015,你可以感觉到编写、调试、测试和运行JavaScript都更加有效。Babel是广受受欢迎转译器,我假设您正在使用它。

除了将ES6/ES7语法转换为低版本javascript之外,Babel还包括对编译JSX支持。您不需要添加或更改任何内容即可使用此功能。

通过一个非常简单的例子,我们可以很容易地看出是如何工作的:

Before

/** @jsx h */
let foo = <div id="foo">Hello!</div>;

After:

var foo = h('div', {id:"foo"}, 'Hello!');

你可能会看着第二个代码片段,认为使用函数构建UI并没有那么糟糕……

这就是我开始使用JSX的原因。

让我们构建一个JSX渲染器

首先,我们需要定义代码调用的 h() 函数。

您可以将其命名为任何您想要的名称,我使用 h() ,因为这种类型的“构建器”函数的原始想法被称为hyperscript("hypertext" + "javascript")

function h(nodeName, attributes, ...args) {
      let children = args.length ? [].concat(...args) : null;
      return { nodeName, attributes, children };
}

现在h() 函数返回了嵌套的JSON对象:

{
  nodeName: "div",
  attributes: {
    "id": "foo"
  },
  children: ["Hello!"]
}

所以我们只需要一个函数来接受这种格式并输出实际的DOM节点:

function render(vnode) {
    // 字符串只需转换为#text节点:
    if (vnode.split) return document.createTextNode(vnode);

    // 使用我们的VDOM元素创建一个DOM元素:
    let n = document.createElement(vnode.nodeName);

    // 将属性复制到新节点上:
    let a = vnode.attributes || {};
    Object.keys(a).forEach( k => n.setAttribute(k, a[k]) );

    // 渲染(构建)然后附加子节点:
    (vnode.children || []).forEach( c => n.appendChild(render(c)) );

    return n;
}

不难理解这是怎么回事。

使用JSX

JSX转换为h()函数调用。创建了一个简单的“虚拟”DOM树。

我们使用render()函数来制作一个“真实”DOM树。

看起来是这样的:

// JSX -> VDOM:
let vdom = <div id="foo">Hello!</div>;

// VDOM -> DOM:
let dom = render(vdom);

// add the tree to <body>:
document.body.appendChild(dom);

把它放在一起

下面是这个小虚拟DOM渲染器的完整源代码和使用它的视图。

const ITEMS = 'hello there people'.split(' ');

// 将数组转换为列表项:
let list = items => items.map( p => <li> {p} </li> );
 
// view with a call out ("partial") to generate a list from an Array:
let vdom = (
    <div id="foo">
        <p>Look, a simple JSX DOM renderer!</p>
        <ul>{ list(ITEMS) }</ul>
    </div>
);
 
// render()将我们的“虚拟DOM”转换为真正的DOM树:
let dom = render(vdom);
 
// 将新节点附加到某处:
document.body.appendChild(dom);
 
// Remember that "virtual DOM"? It's just JSON - each "VNode" is an object with 3 properties.
let json = JSON.stringify(vdom, null, '  ');

// The whole process (JSX -> VDOM -> DOM) in one step:
document.body.appendChild(
    render( <pre id="vdom">{ json }</pre> )
);

原文:WTF is JSX - JASON Format