底层渲染
对于很多应用,已有的组件库已经足够使用。
但是仍有小部分情况你需要直接渲染 DOM 元素。
以及,组件库也是通过底层渲染方法来渲染 HTML 或 SVG 元素,以构成组件。
INFO
如果一个现有的组件已经满足你的需要,请使用它,因为底层渲染更冗长并容易写错。
例子
let count = 0;
const app = $app([], _ => {
_._div(
{
id: "my-div",
},
_ => {
_._p({}, `Count is: ${count}`);
_._button(
{
onclick: () => {
count++;
app.update();
},
},
"Add",
);
},
);
_._svgSvg(
{
width: 100,
height: 100,
},
_ => {
_._svgPath({
d: "M 10 10 H 90 V 90 H 10 Z",
fill: "red",
});
},
);
});
运行结果
函数名
对于 HTML 元素,函数名是标签名加上
_
前缀:_._div
对应<div>
。对于 SVG 元素,函数名是标签名加上
_svg
前缀:_._svgPath
对应<path>
。对于自定义元素(包括 Web Component),标签名中的的短横线会被以小驼峰写法代替:
_._myCustomElement
对应<my-custom-element>
。
函数签名
- 参数:(均为可选参数)
data
: 将被合并到元素实例的对象。children
: the children of the element.eventListeners
: 元素的事件侦听器。
- 返回值:
void
data
参数
类型: Partial<TheElement>
这里的
TheElement
指 DOM 元素的实例类型,比如HTMLDivElement
、SVGPathElement
。
通过 data
参数传入的对象将被合并到元素实例。合并操作通过以下两种不同的方式完成:
对于 HTML 元素或自定义元素:
for (const key in data) {
if (data[key] === undefined) {
// 删除值为 undefined 的属性
// @ts-ignore
delete el.node[key];
} else {
// 对于 HTM 元素,直接赋值对应的属性
// @ts-ignore
el.node[key] = data[key];
}
}
对于 SVG 元素:
for (const key in data) {
const value = data[key];
if (value === undefined) {
el.node.removeAttribute(key);
} else if (typeof value === "function") {
// 不能将函数转化为字符串,所以直接赋值
// @ts-ignore
el.node[key] = value;
} else {
// 对于 SVG 元素,直接赋值不起作用
el.node.setAttribute(key, String(value));
}
}
The children
Parameter
类型: D<Content>
元素的内容(即打开、闭合标签之间的东西)。 它可以是:
- 一个字符串或数字,将被以字符串节点的形式渲染。
- A view function, which will be rendered as the content of the element.
- 一个包裹了上述2种之一的
PD
对象。
eventListeners
参数
类型: { [K in TheEventMap]: ((ev: TheEventMap[K]) => void) | { listener: (ev: TheEventMap[K]) => void), options?: boolean | AddEventListenerOptions } }
这里的
TheEventMap
是元素对应的事件表,比如HTMLElementEventMap
、WebComponentsEventListeners[TagName]
。
传入的值应是一个对象,键为事件名,值为回调函数或回调函数与其他选项组成的对象。
回调函数和其他选项将被传递给元素的 addEventListener
方法。
_._div({}, "", {
mousemove: {
listener: ev => {
// ...
},
options: {
capture: true,
},
},
});
将会调用:
divElement.addEventListener(
"mousemove",
ev => {
// ...
},
{
capture: true,
},
);
接收事件
正如上文所述,底层渲染时有两种接收事件的方式。
- 将回调函数传递给
data
参数:ts_._button( { onclick: () => { count++; app.update(); }, }, "Add", );
- 将回调函数传递给
eventListeners
参数:ts_._button({}, "Add", { click: () => { count++; app.update(); }, });
规则是:**如果将回调函数传递给 data
参数能正确工作,那么就不要使用 eventListeners
参数。**因为前者更快且更紧凑。
在以下两种情况,将回调函数传递给 data
参数不工作:
- 这个事件是一个自定义的事件。
- 需要指定传递给
addEventListener
方法的options
。
元素引用
你可以使用 _.$ref
指令 来引用元素。
import { ref, DOMElementComponent } from "refina";
const iframeRef = ref<DOMElementComponent<"iframe">>();
$app([Basics], _ => {
_.$ref(iframeRef) &&
_._iframe({
src: iframeURL,
});
//...
iframeURL.current?.node.contentWindow?.postMessage("Hello", "*");
});