JSX
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 标签的字符串 :
div
,p
, ,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>
}
}