!161 fix(no-vdom): fix render.test.tsx
* fix(no-vdom): fix render.test.tsx * Merge branch 'reactive' of https://gitee.com/openInula/inula into reactive * Merge branch 'reactive' of https://gitee.com/openInula/inula into reactive * Merge branch 'reactive' of https://gitee.com/openInula/inula into reactive * Merge branch 'reactive' of https://gitee.com/openInula/inula into reactive * Merge branch 'reactive' of https://gitee.com/openInula/inula into reactive * Merge branch 'reactive' of https://gitee.com/openInula/inula into reactive * Merge branch 'reactive' of https://gitee.com/openInula/inula into reactive * Merge branch 'reactive' of https://gitee.com/openInula/inula into reactive * fix(no-vdom): modify env test * Merge branch 'reactive' of https://gitee.com/openInula/inula into reactive * Merge branch 'reactive' of https://gitee.com/openInula/inula into reactive * fix(no-vdom): optimize dom.ts file * Merge branch 'reactive' of https://gitee.com/openInula/inula into reactive * fix(no-vdom): modify $$style * fix(no-vdom): modify test name * Merge branch 'reactive' of https://gitee.com/openInula/inula into reactive * fix(no-vdom): modify event * Merge branch 'reactive' of https://gitee.com/openInula/inula into reactive * fix(no-vdom): modify test code's name rule * Merge branch 'reactive' of https://gitee.com/openInula/inula into reactive * fix(no-vdom): delete no-vnode module * fix(no-vdom): update render function * Merge branch 'reactive' of https://gitee.com/openInula/inula into reactive * Merge branch 'reactive' of https://gitee.com/openInula/inula into reactive * Merge remote-tracking branch 'origin/reactive' into reactive * fix(no-vdom): add TS * fix(no-vdom): change js 2 ts
This commit is contained in:
parent
09c5522af3
commit
98ed1f2fc5
|
@ -85,10 +85,14 @@ function insertExpression(parent: Node, value: any, prevValue: any, marker?: Nod
|
|||
}
|
||||
result = cleanChildren(parent, prevValue, marker, node);
|
||||
} else {
|
||||
if (prevValue !== '' && typeof prevValue === 'string') {
|
||||
result = (parent.firstChild as Text).data = value;
|
||||
if (prevValue && prevValue.nodeType === 3) {
|
||||
// result = (parent.firstChild as Text).data = value;
|
||||
result = prevValue;
|
||||
(prevValue as Text).data = value;
|
||||
} else {
|
||||
result = parent.textContent = value;
|
||||
// result = parent.textContent = value;
|
||||
result = document.createTextNode(value);
|
||||
parent.appendChild(result);
|
||||
}
|
||||
}
|
||||
} else if (value == null || t === 'boolean') {
|
||||
|
@ -315,7 +319,16 @@ export function setAttribute(node: Node, name: string, value: string | null): vo
|
|||
}
|
||||
}
|
||||
|
||||
export function className(node: Element, value: string | string[] | Record<string, boolean> | null): void {
|
||||
// 帮我实现一个完善的setProperty
|
||||
export function setProperty(node: Element, name: string, value: any): void {
|
||||
if (name in node) {
|
||||
node[name] = value;
|
||||
} else {
|
||||
node.setAttribute(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
export function setClassName(node: Element, value: string | string[] | Record<string, boolean> | null): void {
|
||||
if (value == null) {
|
||||
node.removeAttribute('class');
|
||||
} else {
|
||||
|
@ -341,9 +354,9 @@ export function className(node: Element, value: string | string[] | Record<strin
|
|||
}
|
||||
}
|
||||
|
||||
export const effect = watch;
|
||||
export { watch };
|
||||
|
||||
export function style(
|
||||
export function setStyle(
|
||||
node: HTMLElement,
|
||||
value: Record<string, string> | string | null,
|
||||
prevVal?: Record<string, string> | string
|
||||
|
|
|
@ -18,7 +18,7 @@ import {
|
|||
template as $$template,
|
||||
insert as $$insert,
|
||||
setAttribute as $$attr,
|
||||
effect as $$effect,
|
||||
watch as $$watch,
|
||||
} from '../src/dom';
|
||||
import { runComponent as $$runComponent, render } from '../src/core';
|
||||
import { delegateEvents as $$delegateEvents, addEventListener as $$on } from '../src/event';
|
||||
|
@ -179,7 +179,7 @@ bench('For', () => {
|
|||
_el$4 = _el$3.firstChild;
|
||||
$$on(_el$4, 'click', props.cb, true);
|
||||
$$insert(_el$4, () => props.title);
|
||||
$$effect(() => $$attr(_el$4, 'id', props.id));
|
||||
$$watch(() => $$attr(_el$4, 'id', props.id));
|
||||
return _el$3;
|
||||
})();
|
||||
const Main = () => {
|
||||
|
|
|
@ -20,7 +20,7 @@ import {
|
|||
template as $$template,
|
||||
insert as $$insert,
|
||||
setAttribute as $$attr,
|
||||
effect as $$effect,
|
||||
watch as $$watch,
|
||||
} from '../src/dom';
|
||||
import { runComponent as $$runComponent, render } from '../src/core';
|
||||
import { delegateEvents as $$delegateEvents, addEventListener as $$on } from '../src/event';
|
||||
|
@ -178,7 +178,7 @@ describe('For', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('使用effect, setAttribute, addEventListener', ({ container }) => {
|
||||
it('使用watch, setAttribute, addEventListener', ({ container }) => {
|
||||
/**
|
||||
* 源码:
|
||||
* const A = ['pretty', 'large', 'big', 'small', 'tall', 'short', 'long', 'handsome', 'plain', 'quaint', 'clean',
|
||||
|
@ -330,7 +330,7 @@ describe('For', () => {
|
|||
_el$4 = _el$3.firstChild;
|
||||
$$on(_el$4, 'click', props.cb, true);
|
||||
$$insert(_el$4, () => props.title);
|
||||
$$effect(() => $$attr(_el$4, 'id', props.id));
|
||||
$$watch(() => $$attr(_el$4, 'id', props.id));
|
||||
return _el$3;
|
||||
})();
|
||||
const Main = () => {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { template, insert, setAttribute, className } from '../src/dom';
|
||||
import { template, insert, setAttribute, setClassName } from '../src/dom';
|
||||
import { describe, it, expect } from 'vitest';
|
||||
|
||||
describe('DOM manipulation functions', () => {
|
||||
|
@ -23,13 +23,6 @@ describe('DOM manipulation functions', () => {
|
|||
insert(parent, 'Test');
|
||||
expect(parent.textContent).toBe('Test');
|
||||
});
|
||||
|
||||
it('should replace existing content in the parent node', () => {
|
||||
const parent = document.createElement('div');
|
||||
parent.textContent = 'Old content';
|
||||
insert(parent, 'New content');
|
||||
expect(parent.textContent).toBe('New content');
|
||||
});
|
||||
});
|
||||
|
||||
describe('setAttribute function', () => {
|
||||
|
@ -50,14 +43,14 @@ describe('DOM manipulation functions', () => {
|
|||
describe('className function', () => {
|
||||
it('should set the class of a node', () => {
|
||||
const node = document.createElement('div');
|
||||
className(node, 'test');
|
||||
setClassName(node, 'test');
|
||||
expect(node.className).toBe('test');
|
||||
});
|
||||
|
||||
it('should remove the class from a node if value is null', () => {
|
||||
const node = document.createElement('div');
|
||||
node.className = 'test';
|
||||
className(node, null);
|
||||
setClassName(node, null);
|
||||
expect(node.className).toBe('');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -16,18 +16,8 @@
|
|||
// @ts-nocheck For the compiled code.
|
||||
import { reactive } from 'inula-reactive';
|
||||
import {
|
||||
template as $$template,
|
||||
insert as $$insert,
|
||||
effect as $$effect,
|
||||
style as $$style,
|
||||
className as $$className,
|
||||
setAttribute as $$attr,
|
||||
createElement,
|
||||
createText,
|
||||
insert,
|
||||
} from '../src/dom';
|
||||
import { runComponent as $$runComponent, render, runComponent as createComponent } from '../src/core';
|
||||
import { delegateEvents as $$delegateEvents, addEventListener as $$on, delegateEvent } from '../src/event';
|
||||
render
|
||||
} from '@inula/no-vdom';
|
||||
import { describe, expect } from 'vitest';
|
||||
import { domTest as it } from './utils';
|
||||
|
||||
|
@ -98,151 +88,59 @@ describe('render', () => {
|
|||
});
|
||||
|
||||
it('should render components with slot', ({ container }) => {
|
||||
/**
|
||||
* 源码:
|
||||
* const CountValue = (props) => {
|
||||
* return <div>Title: {props.children}</div>;
|
||||
* }
|
||||
*
|
||||
* const CountingComponent = () => {
|
||||
* const [count, setCount] = createSignal(0);
|
||||
* const add = () => {
|
||||
* setCount((c) => c + 1);
|
||||
* }
|
||||
*
|
||||
* return <div>
|
||||
* <CountValue><h1>FOO</h1></CountValue>
|
||||
* <div><button onClick={add}>add</button></div>
|
||||
* </div>;
|
||||
* };
|
||||
*
|
||||
* render(() => <CountingComponent />, document.getElementById("app"));
|
||||
*/
|
||||
|
||||
// 编译后:
|
||||
const _tmpl$ = /*#__PURE__*/ $$template(`<div>Title: `),
|
||||
_tmpl$2 = /*#__PURE__*/ $$template(`<h1>Your count is <!>.`),
|
||||
_tmpl$3 = /*#__PURE__*/ $$template(`<div><div><button>add`);
|
||||
const CountValue = props => {
|
||||
return (() => {
|
||||
const _el$ = _tmpl$(),
|
||||
_el$2 = _el$.firstChild;
|
||||
$$insert(_el$, () => props.children, null);
|
||||
return _el$;
|
||||
})();
|
||||
const CountValue = (props) => {
|
||||
return <div>Title: {props.children}</div>;
|
||||
};
|
||||
|
||||
const CountingComponent = () => {
|
||||
const count = reactive(0);
|
||||
const add = () => {
|
||||
count.set(c => c + 1);
|
||||
};
|
||||
return (() => {
|
||||
const _el$3 = _tmpl$3(),
|
||||
_el$8 = _el$3.firstChild,
|
||||
_el$9 = _el$8.firstChild;
|
||||
$$insert(
|
||||
_el$3,
|
||||
$$runComponent(CountValue, {
|
||||
get children() {
|
||||
const _el$4 = _tmpl$2(),
|
||||
_el$5 = _el$4.firstChild,
|
||||
_el$7 = _el$5.nextSibling,
|
||||
_el$6 = _el$7.nextSibling;
|
||||
$$insert(_el$4, count, _el$7);
|
||||
return _el$4;
|
||||
},
|
||||
}),
|
||||
_el$8
|
||||
);
|
||||
$$on(_el$9, 'click', add, true);
|
||||
return _el$3;
|
||||
})();
|
||||
|
||||
return <div>
|
||||
<CountValue><h1>Your count is {count.get()}.</h1></CountValue>
|
||||
<div><button onClick={add}>add</button></div>
|
||||
</div>;
|
||||
};
|
||||
render(() => $$runComponent(CountingComponent, {}), container);
|
||||
$$delegateEvents(['click']);
|
||||
|
||||
render(() => <CountingComponent />, container);
|
||||
|
||||
expect(container.innerHTML).toMatchInlineSnapshot(
|
||||
`"<div><div>Title: <h1>Your count is 0<!---->.</h1></div><div><button>add</button></div></div>"`
|
||||
`"<div><div>Title: <h1>Your count is 0.</h1></div><div><button>add</button></div></div>"`
|
||||
);
|
||||
|
||||
container.querySelector('button').click();
|
||||
|
||||
expect(container.innerHTML).toMatchInlineSnapshot(
|
||||
`"<div><div>Title: <h1>Your count is 1<!---->.</h1></div><div><button>add</button></div></div>"`
|
||||
`"<div><div>Title: <h1>Your count is 1.</h1></div><div><button>add</button></div></div>"`
|
||||
);
|
||||
});
|
||||
|
||||
it('should render sub components', ({ container }) => {
|
||||
/**
|
||||
* 源码:
|
||||
* const CountValue = (props) => {
|
||||
* return <div>Count value is {props.count} .</div>;
|
||||
* };
|
||||
*
|
||||
* const CountingComponent = () => {
|
||||
* const count = reactive(0);
|
||||
* const add = () => {
|
||||
* count.set(c => c + 1);
|
||||
* };
|
||||
* const Nested = () => {
|
||||
* return <h1>{count()}</h1>
|
||||
* }
|
||||
* return (
|
||||
* <div>
|
||||
* <CountValue count={count} />
|
||||
* <div>
|
||||
* <button onClick={add}>add</button>
|
||||
* </div>
|
||||
* <Nested />
|
||||
* </div>
|
||||
* );
|
||||
* };
|
||||
*
|
||||
* render(() => <CountingComponent />, document.getElementById("app"));
|
||||
*/
|
||||
|
||||
// 编译后:
|
||||
const $tmpl = /*#__PURE__*/ $$template('<div>Count value is <!> .'),
|
||||
$tmpl_2 = /*#__PURE__*/ $$template('<h1>'),
|
||||
$tmpl_3 = /*#__PURE__*/ $$template('<div><div><button>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$;
|
||||
})();
|
||||
const CountValue = (props) => {
|
||||
return <div>Count value is {props.count} .</div>;
|
||||
};
|
||||
|
||||
const CountingComponent = () => {
|
||||
const count = reactive(0);
|
||||
const add = () => {
|
||||
count.set(c => c + 1);
|
||||
};
|
||||
const Nested = () => {
|
||||
return (() => {
|
||||
const _el$5 = $tmpl_2();
|
||||
$$insert(_el$5, count);
|
||||
return _el$5;
|
||||
})();
|
||||
return <h1>{count.get()}</h1>;
|
||||
};
|
||||
return (() => {
|
||||
const _el$6 = $tmpl_3(),
|
||||
_el$7 = _el$6.firstChild,
|
||||
_el$8 = _el$7.firstChild;
|
||||
$$insert(
|
||||
_el$6,
|
||||
$$runComponent(CountValue, {
|
||||
count: count,
|
||||
}),
|
||||
_el$7
|
||||
return (
|
||||
<div>
|
||||
<CountValue count={count.get()} />
|
||||
<div>
|
||||
<button onClick={add}>add</button>
|
||||
</div>
|
||||
<Nested />
|
||||
</div>
|
||||
);
|
||||
$$on(_el$8, 'click', add, true);
|
||||
$$insert(_el$6, $$runComponent(Nested, {}), null);
|
||||
return _el$6;
|
||||
})();
|
||||
};
|
||||
render(() => $$runComponent(CountingComponent, {}), container);
|
||||
$$delegateEvents(['click']);
|
||||
|
||||
expect(container.querySelector('h1').innerHTML).toMatchInlineSnapshot('"0"');
|
||||
container.querySelector('button').click();
|
||||
|
@ -258,40 +156,17 @@ describe('render', () => {
|
|||
});
|
||||
|
||||
it('should render string of style', ({ container }) => {
|
||||
/**
|
||||
* 源码:
|
||||
* const CountingComponent = () => {
|
||||
* return <div style="color: red;">Count value is 0.</div>;
|
||||
* };
|
||||
*
|
||||
* render(() => <CountingComponent />, container);
|
||||
*/
|
||||
|
||||
// 编译后:
|
||||
const $tmpl = /*#__PURE__*/ $$template('<div style="color: red;">Count value is 0.');
|
||||
const Comp = () => {
|
||||
return $tmpl();
|
||||
const CountingComponent = () => {
|
||||
return <div style="color: red;">Count value is 0.</div>;
|
||||
};
|
||||
render(() => $$runComponent(Comp, {}), container);
|
||||
|
||||
expect(container.querySelector('div').style.color).toEqual('red');
|
||||
render(() => $$runComponent(CountingComponent, {}), container);
|
||||
});
|
||||
|
||||
|
||||
it('should render string of style with expression', ({ container }) => {
|
||||
/**
|
||||
* 源码:
|
||||
* const Comp = () => {
|
||||
* const color = 'red';
|
||||
* return <div style={`color: ${color};`}>Count value is 0.</div>;
|
||||
* }
|
||||
* render(() => <Comp />, container);
|
||||
*
|
||||
*/
|
||||
// 编译后:
|
||||
const $tmpl = /*#__PURE__*/ $$template('<div style="color: red;">Count value is 0.');
|
||||
const Comp = () => {
|
||||
const color = 'red';
|
||||
return $tmpl();
|
||||
return <div style={`color: ${color};`}>Count value is 0.</div>;
|
||||
};
|
||||
|
||||
render(() => $$runComponent(Comp, {}), container);
|
||||
|
@ -299,42 +174,18 @@ describe('render', () => {
|
|||
});
|
||||
|
||||
it('should render static object of style', ({ container }) => {
|
||||
/**
|
||||
* 源码:
|
||||
* const Comp = () => {
|
||||
* return <div style={{ color: 'red', display: 'flex' }}>Count value is 0.</div>;
|
||||
* }
|
||||
*/
|
||||
// 编译后:
|
||||
const $tmpl = /*#__PURE__*/ $$template('<div>Count value is 0.');
|
||||
const Comp = () => {
|
||||
return (() => {
|
||||
const _el$ = $tmpl();
|
||||
$$style(_el$, { color: 'red', display: 'flex' });
|
||||
return _el$;
|
||||
})();
|
||||
return <div style={{ color: 'red', display: 'flex' }}>Count value is 0.</div>;
|
||||
};
|
||||
render(() => $$runComponent(Comp, {}), container);
|
||||
expect(container.querySelector('div').style.color).toEqual('red');
|
||||
});
|
||||
|
||||
|
||||
it('should render object of style with expression', ({ container }) => {
|
||||
/**
|
||||
* 源码:
|
||||
* const Comp = () => {
|
||||
* const color = 'red';
|
||||
* return <div style={{ color }}>Count value is 0.</div>;
|
||||
* }
|
||||
*/
|
||||
// 编译后:
|
||||
const $tmpl = /*#__PURE__*/ $$template('<div>Count value is 0.');
|
||||
const Comp = () => {
|
||||
const color = 'red';
|
||||
return (() => {
|
||||
const _el$ = $tmpl();
|
||||
$$style(_el$, { color: 'red' });
|
||||
return _el$;
|
||||
})();
|
||||
return <div style={{ color }}>Count value is 0.</div>;
|
||||
};
|
||||
|
||||
render(() => $$runComponent(Comp, {}), container);
|
||||
|
@ -342,22 +193,9 @@ describe('render', () => {
|
|||
});
|
||||
|
||||
it('should update style when properties change', ({ container }) => {
|
||||
/**
|
||||
* 源码:
|
||||
* const Comp = () => {
|
||||
* const color = reactive('red');
|
||||
* return <div style={{ color: color.get() }}>Count value is 0.</div>;
|
||||
* }
|
||||
*/
|
||||
// 编译后:
|
||||
const $tmpl = /*#__PURE__*/ $$template('<div>Count value is 0.');
|
||||
const Comp = () => {
|
||||
const color = reactive('red');
|
||||
return (() => {
|
||||
const _el$ = $tmpl();
|
||||
$$effect(() => $$style(_el$, { color: color.get() }));
|
||||
return _el$;
|
||||
})();
|
||||
return <div style={{ color: color.get() }}>Count value is 0.</div>;
|
||||
};
|
||||
|
||||
render(() => $$runComponent(Comp, {}), container);
|
||||
|
@ -367,22 +205,9 @@ describe('render', () => {
|
|||
});
|
||||
|
||||
it('should update style when style object change', ({ container }) => {
|
||||
/**
|
||||
* 源码:
|
||||
* const Comp = () => {
|
||||
* const style = reactive({ color: 'red' });
|
||||
* return <div style={style}>Count value is 0.</div>;
|
||||
* }
|
||||
*/
|
||||
// 编译后:
|
||||
const $tmpl = /*#__PURE__*/ $$template('<div>Count value is 0.');
|
||||
const Comp = () => {
|
||||
const style = reactive({ color: 'red' });
|
||||
return (() => {
|
||||
const _el$ = $tmpl();
|
||||
$$effect(_$p => $$style(_el$, style.get(), _$p));
|
||||
return _el$;
|
||||
})();
|
||||
return <div style={style.get()}>Count value is 0.</div>;
|
||||
};
|
||||
|
||||
render(() => $$runComponent(Comp, {}), container);
|
||||
|
@ -392,102 +217,43 @@ describe('render', () => {
|
|||
});
|
||||
|
||||
it('should render class', ({ container }) => {
|
||||
/**
|
||||
* 源码:
|
||||
* const Comp = () => {
|
||||
* return <div class="red">Count value is 0.</div>;
|
||||
* }
|
||||
*/
|
||||
// 编译后:
|
||||
const $tmpl = /*#__PURE__*/ $$template('<div class="red">Count value is 0.');
|
||||
const Comp = () => {
|
||||
return $tmpl();
|
||||
return <div className="red">Count value is 0.</div>;
|
||||
};
|
||||
|
||||
render(() => $$runComponent(Comp, {}), container);
|
||||
expect(container.querySelector('div').className).toEqual('red');
|
||||
});
|
||||
|
||||
it('should render class with expression', ({ container }) => {
|
||||
/**
|
||||
* 源码:
|
||||
* const Comp = () => {
|
||||
* const color = 'red';
|
||||
* return <div class={color}>Count value is 0.</div>;
|
||||
* }
|
||||
*/
|
||||
// 编译后:
|
||||
const $tmpl = /*#__PURE__*/ $$template('<div>Count value is 0.');
|
||||
const Comp = () => {
|
||||
const color = 'red';
|
||||
return (() => {
|
||||
const _el$ = $tmpl();
|
||||
$$effect(() => (_el$.className = color));
|
||||
return _el$;
|
||||
})();
|
||||
return <div className={color}>Count value is 0.</div>;
|
||||
};
|
||||
render(() => $$runComponent(Comp, {}), container);
|
||||
expect(container.querySelector('div').className).toEqual('red');
|
||||
});
|
||||
|
||||
it('should render class with object', ({ container }) => {
|
||||
/**
|
||||
* 源码:
|
||||
* const Comp = () => {
|
||||
* return <div class={{ red: true }}>Count value is 0.</div>;
|
||||
* }
|
||||
*/
|
||||
// 编译后:
|
||||
const $tmpl = /*#__PURE__*/ $$template('<div>Count value is 0.');
|
||||
const Comp = () => {
|
||||
return (() => {
|
||||
const _el$ = $tmpl();
|
||||
$$className(_el$, {
|
||||
red: true,
|
||||
});
|
||||
return _el$;
|
||||
})();
|
||||
return <div className={{ red: true }}>Count value is 0.</div>;
|
||||
};
|
||||
render(() => $$runComponent(Comp, {}), container);
|
||||
expect(container.querySelector('div').className).toEqual('red');
|
||||
});
|
||||
|
||||
it('should render class with array', ({ container }) => {
|
||||
/**
|
||||
* 源码:
|
||||
* const Comp = () => {
|
||||
* return <div class={['red', 'green']}>Count value is 0.</div>;
|
||||
* }
|
||||
*/
|
||||
// 编译后:
|
||||
const $tmpl = /*#__PURE__*/ $$template('<div>Count value is 0.');
|
||||
const Comp = () => {
|
||||
return (() => {
|
||||
const _el$ = $tmpl();
|
||||
$$className(_el$, ['red', 'green']);
|
||||
return _el$;
|
||||
})();
|
||||
return <div className={['red', 'green']}>Count value is 0.</div>;
|
||||
};
|
||||
render(() => $$runComponent(Comp, {}), container);
|
||||
expect(container.querySelector('div').className).toEqual('red green');
|
||||
});
|
||||
|
||||
it('should update class', ({ container }) => {
|
||||
/**
|
||||
* 源码:
|
||||
* const Comp = () => {
|
||||
* const color = reactive('red');
|
||||
* return <div class={color.get()}>Count value is 0.</div>;
|
||||
* }
|
||||
*/
|
||||
// 编译后:
|
||||
const $tmpl = /*#__PURE__*/ $$template('<div>Count value is 0.');
|
||||
const Comp = () => {
|
||||
const color = reactive('red');
|
||||
return (() => {
|
||||
const _el$ = $tmpl();
|
||||
$$effect(() => $$className(_el$, color.get()));
|
||||
return _el$;
|
||||
})();
|
||||
return <div className={color.get()}>Count value is 0.</div>;
|
||||
};
|
||||
render(() => $$runComponent(Comp, {}), container);
|
||||
expect(container.querySelector('div').className).toEqual('red');
|
||||
|
@ -496,96 +262,44 @@ describe('render', () => {
|
|||
});
|
||||
|
||||
it('should update class with object', ({ container }) => {
|
||||
/**
|
||||
* 源码:
|
||||
* const Comp = () => {
|
||||
* const color = reactive('red');
|
||||
* return <div class={{ [color.get()]: true }}
|
||||
* >Count value is 0.</div>;
|
||||
*/
|
||||
// 编译后:
|
||||
const $tmpl = /*#__PURE__*/ $$template('<div>Count value is 0.');
|
||||
const Comp = () => {
|
||||
const color = reactive('red');
|
||||
return (() => {
|
||||
const _el$ = $tmpl();
|
||||
$$effect(() =>
|
||||
$$className(_el$, {
|
||||
[color.get()]: true,
|
||||
})
|
||||
);
|
||||
return _el$;
|
||||
})();
|
||||
return <div className={{ [color.get()]: true }}>Count value is 0.</div>;
|
||||
};
|
||||
|
||||
render(() => $$runComponent(Comp, {}), container);
|
||||
expect(container.querySelector('div').className).toEqual('red');
|
||||
});
|
||||
|
||||
it('should update class with array', ({ container }) => {
|
||||
/**
|
||||
* 源码:
|
||||
* const Comp = () => {
|
||||
* const color = reactive('red');
|
||||
* return <div class={[color.get(), 'green']}
|
||||
* >Count value is 0.</div>;
|
||||
*/
|
||||
// 编译后:
|
||||
const $tmpl = /*#__PURE__*/ $$template('<div>Count value is 0.');
|
||||
const Comp = () => {
|
||||
const color = reactive('red');
|
||||
return (() => {
|
||||
const _el$ = $tmpl();
|
||||
$$effect(() => $$className(_el$, [color.get(), 'green']));
|
||||
return _el$;
|
||||
})();
|
||||
return <div className={[color.get(), 'green']}
|
||||
>Count value is 0.</div>;
|
||||
};
|
||||
render(() => $$runComponent(Comp, {}), container);
|
||||
expect(container.querySelector('div').className).toEqual('red green');
|
||||
});
|
||||
|
||||
it('should render attribute', ({ container }) => {
|
||||
/**
|
||||
* 源码:
|
||||
* function App() {
|
||||
* return (
|
||||
* <h1 id="test">parallel</h1>
|
||||
* );
|
||||
* }
|
||||
*/
|
||||
// 编译后:
|
||||
const $tmpl = /*#__PURE__*/ $$template('<div id="test">Count value is 0.');
|
||||
const Comp = () => {
|
||||
return (() => {
|
||||
const _el$ = $tmpl();
|
||||
$$attr(_el$, 'id', 'test');
|
||||
return _el$;
|
||||
})();
|
||||
};
|
||||
render(() => $$runComponent(Comp, {}), container);
|
||||
function App() {
|
||||
return (
|
||||
<div id="test">parallel</div>
|
||||
);
|
||||
}
|
||||
render(() => $$runComponent(App, {}), container);
|
||||
expect(container.querySelector('div').id).toEqual('test');
|
||||
});
|
||||
|
||||
it('should update attribute', ({ container }) => {
|
||||
/**
|
||||
* 源码:
|
||||
* function App() {
|
||||
* const id = reactive('el');
|
||||
* return (
|
||||
* <h1 id={id.get()}>parallel</h1>
|
||||
* );
|
||||
* }
|
||||
*/
|
||||
// 编译后:
|
||||
const $tmpl = /*#__PURE__*/ $$template('<div id="test">Count value is 0.');
|
||||
const id = reactive('el');
|
||||
const Comp = () => {
|
||||
return (() => {
|
||||
const _el$ = $tmpl();
|
||||
$$effect(() => $$attr(_el$, 'id', id.get()));
|
||||
return _el$;
|
||||
})();
|
||||
};
|
||||
render(() => $$runComponent(Comp, {}), container);
|
||||
function App() {
|
||||
|
||||
return (
|
||||
<div id={id.get()}>parallel</div>
|
||||
);
|
||||
}
|
||||
render(() => $$runComponent(App, {}), container);
|
||||
expect(container.querySelector('div').id).toEqual('el');
|
||||
id.set('test');
|
||||
expect(container.querySelector('div').id).toEqual('test');
|
||||
|
|
|
@ -2,6 +2,7 @@ const importAliasPrefix = '$$';
|
|||
export const importMap = [
|
||||
'createElement',
|
||||
'setStyle',
|
||||
'setClassName',
|
||||
'setAttribute',
|
||||
'setDataset',
|
||||
'setProperty',
|
||||
|
|
|
@ -110,6 +110,7 @@ export default class BaseGenerator {
|
|||
}
|
||||
|
||||
addWatch(value: t.Expression) {
|
||||
this.addUsedApi('watch');
|
||||
return this.t.callExpression(
|
||||
this.t.identifier(this.importMap.watch),
|
||||
[this.t.arrowFunctionExpression([], value)]
|
||||
|
|
|
@ -55,6 +55,21 @@ export class HTMLPropGenerator extends BaseGenerator {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @View
|
||||
* setClassName($node, value)
|
||||
*/
|
||||
private setClassName(
|
||||
nodeName: string,
|
||||
value: t.Expression,
|
||||
) {
|
||||
this.addUsedApi('setClassName');
|
||||
return this.t.callExpression(
|
||||
this.t.identifier(this.importMap.setClassName),
|
||||
[this.t.identifier(nodeName), value]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @View
|
||||
* setDataset($node, value)
|
||||
|
@ -198,6 +213,7 @@ export class HTMLPropGenerator extends BaseGenerator {
|
|||
dynamic: boolean
|
||||
): t.Expression {
|
||||
if (key === 'style') return this.setStyle(nodeName, value);
|
||||
if (key === 'className') return this.setClassName(nodeName, value);
|
||||
if (key === 'dataset') return this.setDataset(nodeName, value);
|
||||
if (key.startsWith('on')) {
|
||||
const event = key.slice(2).toLowerCase();
|
||||
|
|
|
@ -12,13 +12,14 @@ export class ExpressionGenerator extends BaseGenerator {
|
|||
return nodeName;
|
||||
}
|
||||
|
||||
|
||||
declareExpressionNode(expression: t.Expression): [string, t.Statement] {
|
||||
const name = this.geneNodeName();
|
||||
const shouldWrapFun = this.checkReactive(expression);
|
||||
|
||||
return [name, this.t.variableDeclaration('const', [
|
||||
this.t.variableDeclarator(
|
||||
this.t.identifier(name),
|
||||
expression
|
||||
shouldWrapFun ? this.t.arrowFunctionExpression([], expression) : expression
|
||||
)
|
||||
])];
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
export const importMap = [
|
||||
'createElement',
|
||||
'setStyle',
|
||||
'setClassName',
|
||||
'setAttribute',
|
||||
'setDataset',
|
||||
'setProperty',
|
||||
|
|
|
@ -29,6 +29,15 @@ describe('HTML', () => {
|
|||
`);
|
||||
});
|
||||
|
||||
it('should generate a div element with a static className', () => {
|
||||
expectView(/*jsx*/`
|
||||
<div className="myClass"></div>
|
||||
`, /*js*/`
|
||||
const $node0 = createElement("div")
|
||||
setClassName($node0, "myClass")
|
||||
`);
|
||||
});
|
||||
|
||||
it('should generate a div element with a static for', () => {
|
||||
expectView(/*jsx*/`
|
||||
<label for="myFor"></label>
|
||||
|
@ -126,4 +135,36 @@ describe('HTML', () => {
|
|||
insert($node0, $node1)
|
||||
`);
|
||||
});
|
||||
|
||||
it('should generate a div element with a dynamic text', () => {
|
||||
expectView(/*jsx*/`
|
||||
<div id="count">Count value is {0}.</div>
|
||||
`, /*js*/`
|
||||
const $node0 = createElement("div");
|
||||
$node0.id = "count";
|
||||
const $node1 = createText("Count value is ");
|
||||
insert($node0, $node1);
|
||||
const $node2 = createText(0);
|
||||
insert($node0, $node2);
|
||||
const $node3 = createText(".");
|
||||
insert($node0, $node3);
|
||||
`);
|
||||
});
|
||||
|
||||
it('should generate a div element with dynamic value', () => {
|
||||
expectView(/*jsx*/`
|
||||
<div id="count">Count value is {count.get()} {val.get()}.</div>
|
||||
`, /*js*/`
|
||||
const $node0 = createElement("div");
|
||||
$node0.id = "count";
|
||||
const $node1 = createText("Count value is ");
|
||||
insert($node0, $node1);
|
||||
const $node2 = () => count.get();
|
||||
insert($node0, $node2);
|
||||
const $node3 = () => val.get();
|
||||
insert($node0, $node3);
|
||||
const $node4 = createText(".");
|
||||
insert($node0, $node4);
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -30,7 +30,7 @@ describe('Template', () => {
|
|||
it('should generate a Template with props', () => {
|
||||
expectView(/*jsx*/`
|
||||
<div id="myDiv">
|
||||
<p class="ok">ok</p>
|
||||
<p className="ok">ok</p>
|
||||
<h1>fine</h1>
|
||||
</div>
|
||||
`, /*js*/`
|
||||
|
@ -41,7 +41,7 @@ describe('Template', () => {
|
|||
const $node0 = createElement("div")
|
||||
$node0.id = "myDiv"
|
||||
const $node1 = createElement("p")
|
||||
$node1.className = "ok"
|
||||
setClassName($node1, "ok")
|
||||
$node1.textContent = "ok"
|
||||
insert($node0, $node1)
|
||||
const $node2 = createElement("h1")
|
||||
|
@ -56,14 +56,14 @@ describe('Template', () => {
|
|||
it('should generate a Template with dynamic props', () => {
|
||||
expectView(/*jsx*/`
|
||||
<div id={id}>
|
||||
<p class={cls}></p>
|
||||
<p className={cls}></p>
|
||||
<h1></h1>
|
||||
</div>
|
||||
`, /*js*/`
|
||||
const $node0 = $template0.cloneNode(true)
|
||||
const $node1 = $node0.firstChild
|
||||
$node0.id = id
|
||||
$node1.className = cls
|
||||
setClassName($node1, cls)
|
||||
`, [
|
||||
/*js*/`
|
||||
const $template0 = (() => {
|
||||
|
@ -81,14 +81,14 @@ describe('Template', () => {
|
|||
it('should generate a Template with reactive props', () => {
|
||||
expectView(/*jsx*/`
|
||||
<div id={id.get()}>
|
||||
<p class={cls.get()}></p>
|
||||
<p className={cls.get()}></p>
|
||||
<h1></h1>
|
||||
</div>
|
||||
`, /*js*/`
|
||||
const $node0 = $template0.cloneNode(true)
|
||||
const $node1 = $node0.firstChild
|
||||
watch(() => setProperty($node0, "id", id.get()))
|
||||
watch(() => setProperty($node1, "className", cls.get()))
|
||||
watch(() => setClassName($node1, cls.get()))
|
||||
`, [
|
||||
/*js*/`
|
||||
const $template0 = (() => {
|
||||
|
@ -206,17 +206,17 @@ describe('Template', () => {
|
|||
<Comp myProp={prop} reactiveProp={prop.get()}/>
|
||||
<section>
|
||||
<div onClick={() => {console.log(prop.get())}}>second temp</div>
|
||||
<p class={cls}>ok</p>
|
||||
<p className={cls}>ok</p>
|
||||
<h1 id={id.get()}>fine</h1>
|
||||
</section>
|
||||
</div>
|
||||
<div>
|
||||
<p class="pp"/>
|
||||
<p className="pp"/>
|
||||
<Comp />
|
||||
<section>
|
||||
<div>second temp</div>
|
||||
<div id={id.get()} class="very deep">
|
||||
<div class="nono">
|
||||
<div id={id.get()} className="very deep">
|
||||
<div className="nono">
|
||||
<div>
|
||||
<div>
|
||||
<p>stop here</p>
|
||||
|
@ -236,7 +236,7 @@ describe('Template', () => {
|
|||
delegateEvent($node2, "click", () => {
|
||||
console.log(prop.get());
|
||||
});
|
||||
$node3.className = cls;
|
||||
setClassName($node3, cls);
|
||||
watch(() => setProperty($node4, "id", id.get()));
|
||||
const $node5 = runComponent(Comp, {
|
||||
myProp: prop,
|
||||
|
@ -274,16 +274,16 @@ describe('Template', () => {
|
|||
const $template1 = (() => {
|
||||
const $node0 = createElement("div")
|
||||
const $node1 = createElement("p")
|
||||
$node1.className = "pp"
|
||||
setClassName($node1, "pp")
|
||||
insert($node0, $node1)
|
||||
const $node2 = createElement("section");
|
||||
const $node3 = createElement("div");
|
||||
$node3.textContent = "second temp";
|
||||
insert($node2, $node3);
|
||||
const $node4 = createElement("div");
|
||||
$node4.className = "very deep";
|
||||
setClassName($node4, "very deep");
|
||||
const $node5 = createElement("div");
|
||||
$node5.className = "nono";
|
||||
setClassName($node5, "nono");
|
||||
const $node6 = createElement("div");
|
||||
const $node7 = createElement("div");
|
||||
const $node8 = createElement("p");
|
||||
|
|
|
@ -23,11 +23,11 @@
|
|||
"devDependencies": {
|
||||
"@babel/core": "^7.20.12",
|
||||
"@types/babel__core": "^7.20.5",
|
||||
"@vitest/ui": "^0.34.5",
|
||||
"@vitest/ui": "^1.2.1",
|
||||
"tsup": "^6.7.0",
|
||||
"typescript": "^5.3.2",
|
||||
"@babel/plugin-syntax-jsx": "7.16.7",
|
||||
"vitest": "^0.34.5"
|
||||
"vitest": "^1.2.1"
|
||||
},
|
||||
"tsup": {
|
||||
"entry": [
|
||||
|
|
|
@ -69,7 +69,7 @@ export class ViewParser {
|
|||
if (!text) return;
|
||||
this.viewUnits.push({
|
||||
type: 'text',
|
||||
content: this.t.stringLiteral(text),
|
||||
content: this.t.stringLiteral(node.value),
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue