!156 feat(no-vdom): render

* feat(no-vdom): render
This commit is contained in:
Hoikan 2024-02-22 02:45:52 +00:00 committed by 陈超涛
parent ef5ee212e3
commit 08300f67fe
5 changed files with 56 additions and 128 deletions

View File

@ -11,9 +11,10 @@
"inula-reactive": "workspace:^0.0.1"
},
"devDependencies": {
"jsdom": "^24.0.0",
"@testing-library/user-event": "^12.1.10",
"@vitest/ui": "^0.34.5",
"jsdom": "^24.0.0",
"vite-plugin-inula-no-vdom": "workspace:*",
"vitest": "^1.2.2"
}
}

View File

@ -389,3 +389,7 @@ export function bindRef<T>(node: T, ref: RefObject<T> | RefCallback<T>): void {
export function createElement(tag: string) {
return document.createElement(tag);
}
export function createText(text: string) {
return document.createTextNode(text);
}

View File

@ -31,6 +31,17 @@ export function delegateEvents(eventNames: string[], node: Node = window.documen
}
}
export function delegateEvent(source: HTMLElement, eventName: string, listener: EventListener, delegator: Node = window.document): void {
const events: Set<string> = delegator[DELEGATE_EVENTS_KEY] || (delegator[DELEGATE_EVENTS_KEY] = new Set());
if (!events.has(eventName)) {
events.add(eventName);
delegator.addEventListener(eventName, eventHandler);
}
source[`$$DELEGATE_EVENT_${eventName}`] = listener;
}
export function clearDelegatedEvents(node: Node = window.document): void {
const events: Set<string> | undefined = node[DELEGATE_EVENTS_KEY];
if (events) {

View File

@ -22,25 +22,17 @@ import {
style as $$style,
className as $$className,
setAttribute as $$attr,
createElement
createElement,
createText,
insert,
} from '../src/dom';
import { runComponent as $$runComponent, render } from '../src/core';
import { delegateEvents as $$delegateEvents, addEventListener as $$on } from '../src/event';
import { runComponent as $$runComponent, render, runComponent as createComponent } from '../src/core';
import { delegateEvents as $$delegateEvents, addEventListener as $$on, delegateEvent } from '../src/event';
import { describe, expect } from 'vitest';
import { domTest as it } from './utils';
describe('render', () => {
it('should render plain jsx', ({ container }) => {
/**
*
* const CountingComponent = () => {
* return <div id="count">Count value is 0.</div>;
* };
*
* render(() => <CountingComponent />, container);
*/
// 编译后:
const CountingComponent = () => {
return <div id="count">Count value is 0.</div>;
};
@ -50,139 +42,59 @@ describe('render', () => {
});
it('should render jsx expression with slots', ({ container }) => {
/**
*
* const CountingComponent = () => {
* return <div id="count">Count value is {0}.</div>;
* };
*
* render(() => <CountingComponent />, container);
*/
// 编译后:
const $tmpl = /*#__PURE__*/ $$template('<div id="count">Count value is <!>.');
const CountingComponent = () => {
return (() => {
const _el$ = $tmpl(),
_el$2 = _el$.firstChild,
_el$4 = _el$2.nextSibling;
$$insert(_el$, 0, _el$4);
return _el$;
})();
return <div id="count">Count value is {0}.</div>;
};
render(() => $$runComponent(CountingComponent, {}), container);
expect(container.querySelector('#count').innerHTML).toEqual('Count value is 0<!---->.');
expect(container.querySelector('#count').innerHTML).toEqual('Count value is 0.');
});
it('should render fragment', ({ container }) => {
/**
*
* const CountingComponent = () => {
* const [count, setCount] = createSignal(0);
* const add = () => {
* setCount((c) => c + 1);
* }
* return <>
* <div id="count">Count value is {count()}.</div>
* <div><button onClick={add}>add</button></div>
* </>;
* };
*/
// 编译后:
const $tmpl = /*#__PURE__*/ $$template('<div id="count">Count value is <!>.'),
$tmpl_2 = /*#__PURE__*/ $$template('<div><button id="btn">add');
const CountingComponent = () => {
const count = reactive(0);
const add = () => {
count.set(c => c + 1);
};
return [
(() => {
const _el$ = $tmpl(),
_el$2 = _el$.firstChild,
_el$4 = _el$2.nextSibling;
$$insert(_el$, count, _el$4);
return _el$;
})(),
(() => {
const _el$5 = $tmpl_2(),
_el$6 = _el$5.firstChild;
$$on(_el$6, 'click', add, true);
return _el$5;
})(),
];
return (
<>
<div id="count">Count value is {count.get()}.</div>
<div>
<button id="btn" onClick={add}>add</button>
</div>
</>
);
};
render(() => $$runComponent(CountingComponent, {}), container);
$$delegateEvents(['click']);
container.querySelector('#btn').click();
expect(container.querySelector('#count').innerHTML).toEqual('Count value is 1<!---->.');
expect(container.querySelector('#count').innerHTML).toEqual('Count value is 1.');
});
it('should render components', ({ container }) => {
/**
*
* const CountValue = (props) => {
* return <div id="count">Count value is {props.count} .</div>;
* }
*
* const CountingComponent = () => {
* const [count, setCount] = createSignal(0);
* const add = () => {
* setCount((c) => c + 1);
* }
*
* return <div>
* <CountValue count={count} />
* <div><button onClick={add}>add</button></div>
* </div>;
* };
*
* render(() => <CountingComponent />, document.getElementById("app"));
*/
// 编译后:
const $tmpl = /*#__PURE__*/ $$template('<div id="count">Count value is <!>.'),
$tmpl_2 = /*#__PURE__*/ $$template('<div><div><button id="btn">add');
const CountValue = props => {
return (() => {
const _el$ = $tmpl(),
_el$2 = _el$.firstChild,
_el$4 = _el$2.nextSibling;
$$insert(_el$, () => props.count, _el$4);
return _el$;
})();
return <div id="count">Count value is {props.count} .</div>;
};
const CountingComponent = () => {
const count = reactive(0);
const add = () => {
count.set(c => c + 1);
};
return (() => {
const _el$5 = $tmpl_2(),
_el$6 = _el$5.firstChild,
_el$7 = _el$6.firstChild;
$$insert(
_el$5,
$$runComponent(CountValue, {
count: count,
}),
_el$6
);
$$on(_el$7, 'click', add, true);
return _el$5;
})();
return (
<div>
<CountValue count={count} />
<div>
<button id="btn" onClick={add}>add</button>
</div>
</div>
);
};
render(() => $$runComponent(CountingComponent, {}), container);
$$delegateEvents(['click']);
container.querySelector('#btn').click();
expect(container.querySelector('#count').innerHTML).toEqual('Count value is 1<!---->.');
expect(container.querySelector('#count').innerHTML).toEqual('Count value is 1.');
});
it('should render components with slot', ({ container }) => {

View File

@ -28,7 +28,7 @@ export class HTMLPropGenerator extends BaseGenerator {
])
addHTMLProp(
nodeName: string,
nodeName: string,
tag: string,
key: string,
value: t.Expression,
@ -45,7 +45,7 @@ export class HTMLPropGenerator extends BaseGenerator {
* setStyle($node, value)
*/
private setStyle(
nodeName: string,
nodeName: string,
value: t.Expression,
) {
return this.t.callExpression(
@ -59,7 +59,7 @@ export class HTMLPropGenerator extends BaseGenerator {
* setDataset($node, value)
*/
private setDataset(
nodeName: string,
nodeName: string,
value: t.Expression,
) {
return this.t.callExpression(
@ -73,7 +73,7 @@ export class HTMLPropGenerator extends BaseGenerator {
* $node.key = value
*/
private setStaticProperty(
nodeName: string,
nodeName: string,
key: string,
value: t.Expression,
) {
@ -92,7 +92,7 @@ export class HTMLPropGenerator extends BaseGenerator {
* setProperty($node, key, value)
*/
private setDynamicProperty(
nodeName: string,
nodeName: string,
key: string,
value: t.Expression,
) {
@ -107,7 +107,7 @@ export class HTMLPropGenerator extends BaseGenerator {
* $node.setAttribute(key, value)
*/
private setStaticAttribute(
nodeName: string,
nodeName: string,
key: string,
value: t.Expression,
) {
@ -126,7 +126,7 @@ export class HTMLPropGenerator extends BaseGenerator {
* setAttribute($node, key, value)
*/
private setDynamicAttribute(
nodeName: string,
nodeName: string,
key: string,
value: t.Expression,
) {
@ -141,12 +141,12 @@ export class HTMLPropGenerator extends BaseGenerator {
* delegateEvent($node, eventName, value)
*/
private setDelegatedEvent(
nodeName: string,
nodeName: string,
eventName: string,
value: t.Expression,
) {
return this.t.callExpression(
this.t.identifier(this.importMap.delegateEvent),
this.t.identifier(this.importMap.delegateEvents),
[this.t.identifier(nodeName), this.t.stringLiteral(eventName), value]
);
}
@ -156,7 +156,7 @@ export class HTMLPropGenerator extends BaseGenerator {
* $node.addEventListener(eventName, value)
*/
private setStaticEvent(
nodeName: string,
nodeName: string,
eventName: string,
value: t.Expression,
) {
@ -174,7 +174,7 @@ export class HTMLPropGenerator extends BaseGenerator {
* addEventListener($node, eventName, value)
*/
private setDynamicEvent(
nodeName: string,
nodeName: string,
eventName: string,
value: t.Expression,
) {
@ -185,7 +185,7 @@ export class HTMLPropGenerator extends BaseGenerator {
}
private setDynamicHTMLProp(
nodeName: string,
nodeName: string,
tag: string,
key: string,
value: t.Expression,
@ -220,4 +220,4 @@ export class HTMLPropGenerator extends BaseGenerator {
this.elementAttributeMap[tag]?.includes(attribute)
);
}
}
}