Styles, Events and Mounting points
Defining Default Style of a Component
By external CSS file
通常,在应用程序中全局定义样式。但某些组件可能需要一些对其操作至关重要的样式(例如特定布局)。
Reactor(实际上是 Sciter 的内部代码)提供了使用 styleset 属性定义组件样式的简单方法。
让我们重新定义我们之前使用的 Clock
类:
class Clock extends Element
{
time = new Date(); // setting initial state
componentDidMount() {
this.timer(1000, function() {
this.componentUpdate { time:new Date() };
return true; // to keep the timer ticking
});
}
render() {
return <clock styleset={__DIR__ + "styles.css#clock"}>
<div.greeting>Hello, world!</div>
<div>It is {this.data.time.toLocaleTimeString()} now.</div>
</clock>;
}
}
注意: styleset={__DIR__ + "styles.css#clock"}
上面的属性,它使用此脚本文件位置作为基础解析为绝对 URL。
这是clock.css文件的内容:
@set clock
{
:root {
display: block;
flow:vertical;
}
span.time {
display:inline-block;
white-space:nowrap;
}
}
正如你所看到的,它定义了一组独立的CSS规则,这些规则定义了我们的时钟组件及其内部的内容(并且只有内容)。
一般考虑:如果组件被设计为在许多应用程序中使用,则其默认样式集应仅包含布局所需的规则,而这些规则对于操作至关重要。每个应用程序都可以在这些默认样式之上添加自己的样式。
请注意,Sciter 中的样式集不会污染样式规则的全局列表,因此非常有效 - 减少了 DOM 元素的样式解析所需的时间。
By embedded CSS style set declaration
我们可以使用 CSS.set
构造函数在同一个 JS 文件中声明样式,而不是在单独的 CSS 文件中声明组件样式。
const clockStyles = CSS.set`
:root {
display: block;
flow:vertical;
}
span.time {
display:inline-block;
white-space:nowrap;
}
`;
// rest is from the above sample
class Clock extends Element
{
time = new Date(); // setting initial state
...
render() {
return <clock styleset={clockStyles}>
<div.greeting>Hello, world!</div>
<div>It is {this.data.time.toLocaleTimeString()} now.</div>
</clock>;
}
}
请注意如何通过 <clock styleset={clockStyles}>
将样式集分配给组件。
Events Handling in Components
与 ReactJS 相比,Sciter 不需要任何特殊的构造来处理事件——我们可以在类中使用普通的(对于 Sciter)事件处理定义。
将搜索块封装在一个 <input>
实体 <button>
中的小组件示例:
class Search extends Element {
render() {
return <search>
<input|text />
<button.do/>
</search>;
}
["on click at button.do"](evt, button) {
this.post(new Event("do-search", {data: this.$("input").value} ));
}
["on change at input"](evt,input) {
this.showSuggestionsFor( input.value );
}
get value() { return this.$("input").value; }
set value(nv) { this.$("input").value = nv;
}
在此示例中,我们正在处理两个事件:单击按钮和更改输入。
关于 ["on change at input"](evt,input)
上述事件处理功能的话。
该格式是定义具有可计算名称或包含命名空间的名称的函数的标准 JS/ES2020 方法。只是在 Sciter 中,事件处理程序使用此表单来描述具有以下签名的事件处理函数:
["on eventname"](event) {}
["on eventname at selector"](event, selectorElement) {}
哪里:
on[space] 部分将函数标记为事件处理程序;
eventname 是事件的名称 - 无论是标准的 HTML 还是一个,如点击、输入、焦点......或自定义事件名称;
[space]at[space],如果存在,则表示选择器将跟随;
selector 是该元素中子元素的 CSS 选择器。当事件处理程序被触发时,函数的 selectorElement 参数将获取对生成事件的匹配子项的引用。
这种基于类的事件处理程序在屏幕上同时存在许多元素的情况下特别有效。此类事件订阅架构不需要对每个元素调用 addEventHandler。
HTML Resident Mounting Points
Reactor 组件是可执行实体,即使它们看起来像 HTML。
通常在 ReactJS 中,您只会在 <script>
部分和 JS 代码文件中看到 JSX 代码,如下所示:
function App() {
return
<main>
<Welcome name="Ivan" />
<Welcome name="Olga" />
<Welcome name="Andrew" />
</main>;
}
document.body.patch( <App /> );
虽然这通常有效,但对某些人来说可能看起来不自然或不方便。
或者,Sciter 提供特殊的 <reactor>
HTML 元素作为安装点:
<body>
<p>Test of Tabs component.</p>
<reactor type="Tabs" src="tabs.js">
<tab name="first" label="First tab">First tab content</tab>
<tab name="second" label="Second tab">Second tab content</tab>
<tab name="third" label="Third tab" src="tab-content.htm"></tab>
</reactor>
</body>
该 <reactor>
元素需要两个属性:
type - 组件的类名,以及
src - 定义该组件的脚本文件的 URL。
请注意,虽然它看起来像 HTML,但 和 </reactor>
之间的 <reactor>
内容是由脚本规则(在本例中为 JSX)解析的。从本质上讲,您可能会认为整个 <reactor>
部分只是 <script>
元素(伪代码):
<body>
<p>Test of <Tabs> component.</p>
<script component="Tabs" src="tabs.js">
<tab name="first" label="First tab">First tab content</tab>
<tab name="second" label="Second tab">Second tab content</tab>
<tab name="third" label="Third tab" src="tab-content.htm"></tab>
</script>
</body>
唯一的主要区别 <reactor>
是:它是一个占位符元素 - 一旦组件被实例化,它就会替换 <reactor>
DOM 元素。因此,执行后的 <reactor>
最终 DOM 将如下所示:
<body>
<p>Test of <tabs> component.</p>
<tabs>
<tab name="first" label="First tab">First tab content</tab>
<tab name="second" label="Second tab">Second tab content</tab>
<tab name="third" label="Third tab" src="tab-content.htm"></tab>
</tabs>
</body>