Skip to content

【手写篇 - Day 12】Virtual DOM V - JSX1 #13

Open
@MarsPen

Description

@MarsPen

题目描述

如果用过React的话,JSX应该是非常熟悉。

通过支持JSX syntax,transpiler可以在JavaScript代码中直接理解如下这种非标准的语法。

<p> this is <button className="button">button</button> </p>

理解过后可以生成标准的JavaScript代码。

React.createElement("p", null,
  " this is ",
  React.createElement("button", { className: "button" }, "button"),
  " ");

可以在TypeScript Playground中试试看。

Transpiler是如何工作的?我们从一个简单的例子来看看。

<a>bfe.dev</a>

首先,上述的代码会被解析成AST(Abstract Syntax Tree)。

打开AST Explorer, 输入上述代码,在右方即可看见AST,大概是这样的构造:

expression: JSXElement {
  openingElement: JSXOpeningElement {
    name: JSXIdentifier {
      name: "a"
    }
  }
  closingElement: JSXClosingElement {
    name: JSXIdentifier {
      name: "a"
    }
  }
  children: [
    JSXText {
      value: "bfe.dev"
    }
  ]
}

简单易懂对吧?实际上就是JSX Spec定义的那样:

JSXElement:
  JSXOpeningElement JSXChildren? JSXClosingElement

JSXOpeningElement:
  < JSXElementName JSXAttributes? >

JSXChildren:
  JSXChild JSXChildren?

JSXClosingElement:
  < / JSXElementName >

JSXChild:
  JSXText
  JSXElement
  { JSXChildExpression? }

通过遍历上述AST,然后在合适的地方插入React.createElement即可得到转换后的代码。

React.createElement("p", null,
  " this is ",
  React.createElement("button", { className: "button" }, "button"),
  " ");

我们也可以不用React的方法,而使用140. Virtual DOM III - Functional Component中定义的h()。

h("p", null,
  " this is ",
  h("button", { className: "button" }, "button"),
  " ");

现在,请实现能够解析并转换JSX Element字符串的parse()和generate() 。

请使用h(),而非React.createElement,系统会自动注入h()的实现。
本题目的目的并不是要再实现一个parser,所以只要满足如下最基本的Spec即可。

JSXElement:
  JSXOpeningElement JSXChildren? JSXClosingElement

JSXOpeningElement:
  < JSXElementName >

JSXChildren:
  JSXChild

JSXClosingElement:
  < / JSXElementName >

JSXChild:
  JSXText
  • 你不必遵守上述命名
  • 传入的字符串中没有换行,所以不需要实现the whitespace rules
  • 仅需要支持HTML tag name即可
  • 为了方便,parse()不会被单独测试,取而代之的parse()和generate()会被一起测试:
const result = eval(generate(parse('<a>bfe.dev</a>')))
expect(result).toEqual(h('a', null, 'bfe.dev'))
  • 如果传入的字符串是无效的JSXElement,需要throw Error。比如JSXOpeningElement和JSXClosingElement不能配对的情况等等。

同类题目

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions