文档手册

JSX

2024-07-18 14:16:18

JSX

注意:本文档是特意编写的,接近 ReactJS/JSX 简介。

Introducing SciterJS::JSX

请考虑以下变量声明:

const velement = <h1 id="hw">Hello, world!</h1>;

它被称为 JSX,它是 SciterJS 语法的一个组成部分 - 解析此类 JSX 文字不需要像浏览器的 JS 那样调用任何预处理器。

上面既不是字符串也不是 HTML,而是一个“元组”声明:

const velement = JSX("h1", { id:"hw"}, ["Hello, world!"]);

从技术上讲,JSX 并不是严格要求的 - 我们可以直接使用 JSX() 函数调用来使用这样的元组文字。只是这种HTML式的语法更熟悉。

Expressions in JSX

在这里,我们声明一个变量名,并在元组构造中使用它:

const name = "Alice";
const velement = <h1>Hello, {name}</h1>;

上面可以完全写成这样:

const velement = JSX("h1", {}, ["Hello, ",name]);

您可以将任何有效的 JS 表达式放在这些大括号中:

const velement = <div>1 + 1 is { 1 + 1 }</div>;

JSX is an expression too

由于 JSX 文本实际上是一个元组文本,因此我们可以在代码中像任何其他文本一样使用它:

function getGreeting(user) {
if (user)
return <h1>Hello, {formatName(user)}!</h1>;
else
return <h1>Hello, Stranger.</h1>;
}

上面的函数返回其中定义的两个元组之一。

Specifying Attributes in JSX

您可以使用引号将字符串文本指定为属性:

const velement = <div tabindex="0"></div>;

您还可以从变量或表达式中提供属性值:

const velement = <img src={user.avatarUrl}></img>;

注意:您应该使用引号(对于字符串值)或大括号(对于表达式),但不能在同一属性中同时使用两者。

Specifying children with JSX

如果标签为空,则可以立即关闭 /> 它:

const velement = <img src={user.avatarUrl} />;

注意:JSX 不支持“无尾”HTML 标签,例如: <img><input><br> 。必须显式关闭以下选项: <img /><input /> <br />

然而,JSX 可能包含子项:

const velement = 
<div>
<h1>Hello!</h1>
<h2>Good to see you here.</h2>
</div>;

Specifying runtime states with JSX

除了属性之外,您可能还希望定义元素的运行时状态:

const velement = 
<li state-expanded={ isOpen(item) } >
<caption>Hello!</caption>
<div></div>
</div>;

这里的状态对应于 CSS 中所谓的伪类: :active:hover:checked

Specifying runtime value of input elements

要指定元素的 <input> 当前运行时值,请使用 state-value runtime state 属性 - 它反映运行时输入的当前值:

<input|text(firstname) state-value="John" />

请注意,just value 属性: <input|text(firstname) value="Initial value" /> 指定在创建元素时设置一次的初始值。

Specifying literal HTML content

在某些情况下,您可能需要从字符串中设置元素的 HTML 内容。为了做到这一点,在 JSX 中使用 state-html 属性:

const htmlContent = "<b>some</b> literal <i>HTML</i>";
<div state-html={htmlContent} />

 以上将生成

<div>
<b>some</b> literal <i>HTML</i>
</div>

Sciter's HTML parsing flavor support in JSX

JSX 遵循 SciterJS 中使用的 HTML 解析快捷方式规则,因此:

  • <input(firstName) /> 等效于 name 属性声明: <input name="firstName" />

  • <input|text /> 是类型属性声明的等效项: <input type="text" />

  • <input.search /> 是类属性声明的等效项: <input />

  • <input#lookup /> 等效于 ID 属性声明: <input id="lookup" />

Using compound component names in JSX

如果应用程序中的组件在命名空间/模块中组织,例如 App.ComponentA ,要使用此类完全限定的名称,请使用 - 而不是 . 作为名称分隔符:

<App-ComponentA>
... content ...
</App-ComponentA>

JSX is a function

在引擎盖下,以下代码:

const velement = <h1 id="hw">Hello, world!</h1>;

转换为对内置 JSX 函数的调用:

const velement = JSX("h1", {id:"hw"}, ["Hello, world!"]);

该 JSX 函数的默认实现只是这样做:

function JSX(tagName,attributes,children) {
return [tagName,attributes,children];
}

因此,默认情况下,JSX 会生成 JSX 函数调用。JSX() 生成 VNODE - 虚拟 DOM 节点定义:

const vnode = JSX("tag", {attributes}, [children]);

 哪里:

  • tag - 是匹配 HTML 标签的字符串 : divp , , section ...或函数或类。

  • attributes - 为 null 或纯脚本对象 - 名称/“值”对的映射。属性值在注入 DOM 之前转换为字符串;

  • children - 为 null 或包含字符串(表示 DOM 文本节点)或其他 vnode(表示 DOM 元素)的纯脚本数组;

注意:JSX 函数可以在 JavaScript 中重新定义。例如,在 MithrilJS 案例中,它可能看起来像:

JSX = m; // m is a Mithril's function - constructor of vnodes

VNODE: usage, a.k.a. rendering

Element 类的一些方法允许通过 vnode 定义填充 DOM:

container.content(<div>Hello wonderful world</div>);

之后,容器将具有单个子元素: <div>

var arr = [1,2,3];
var children = arr.map( (n) => <li>item #{n}</li> );
container.content(children);

容器将有三个 <li> 子项,文本为“项目 #1”、“项目 #3”和“项目 #3”。

接受 VNODE 和 SSX 声明的 Element 类函数列表:文本为“item #1”、“item #3”和“item #3”的子函数。

  • element.content(vnode | array of vnodes) - 元素的内容被这些元素取代;

  • element.append(vnode | array of vnodes) - 这些元素将被添加到元素内容的末尾;

  • element.prepend(vnode | array of vnodes) - 这些元素将被添加到元素内容的末尾;

  • element.patch(vnode) - 通过 vnode 定义修补现有的 DOM 元素,详情见下文;

element.patch(vnode[,onlyChildren]) - DOM reconciliation (a.k.a patching) by vnode

 功能 element.patch(vnode[,onlyChildren])

  • 通过删除、创建或更改 DOM 属性来更新 vnode 对象中的属性。

  •  对于每个孩子:

    • 如果特定 vnode 的子节点与实际 DOM 子节点不匹配,则从该 vnode 子节点创建新的 DOM 元素;

    • 否则,如果特定的 DOM 子节点与任何 vnode 的子节点不匹配,则现有的 DOM 元素将被删除;

    • else ( DOM 子项和 vnode 子项相互匹配 ),然后 patch() 递归地调用该对。

patch() 函数使用以下匹配条件。如果出现以下情况,则特定元素/vnode 对被视为匹配:

  • 它们都具有相同的键属性值;

  • 或者它们是否具有相同的 id 属性值;

  • 或者它们是否具有相同的 name 属性值;

  • 或者如果它们具有相同的标签;

否则,DOM 元素和 vnode 将被视为不匹配。

如果提供了 onlyChildren 参数并且为 true,则该函数将仅接触元素的子元素,从而保持元素的标记和属性不变。

JSX/DOM references

Reactor 的引用提供了一种访问在 render 方法中创建的 DOM 元素的方法。

在 JSX 中,通过使用 var 属性和 target 表达式作为值来定义引用: <div var={this.myDiv}>

目标表达式是可以显示在赋值左侧的任何有效 JS 表达式。例如 this.rows[12] ,是一个有效的目标表达式 - 元素引用将放在数组的 this.rows 第 12 个元素处。

在构造组件时,引用通常分配给实例属性,以便可以在整个组件中引用它们:

class MyForm extends Element {

 nameInput = Reactor.createRef();

render() {
return <form>
<label>Name</label>
<input|text(name) var={this.nameInput} />
<button onClick={ () => this.nameInput.focus() }>focus</button>
</form>
}
}