解决portal root入栈顺序问题

This commit is contained in:
c00364821 2023-12-01 11:28:50 +08:00
parent 530fb24289
commit ca3addf9fe
2 changed files with 100 additions and 1 deletions

View File

@ -286,4 +286,98 @@ describe('PortalComponent Test', () => {
dispatchChangeEvent(inputRef.current, 'test');
expect(fn).toHaveBeenCalledTimes(1);
});
it('portal场景下portal下元素点击事件冒泡到父元素', () => {
class Dialog extends Inula.Component {
node;
constructor(props) {
super(props);
this.node = window.document.createElement('div');
window.document.body.appendChild(this.node);
}
render() {
return Inula.createPortal(this.props.children, this.node);
}
}
const fn = jest.fn();
const subRef = Inula.createRef();
function App() {
return (
<div onClick={fn}>
<Dialog>
<div ref={subRef}/>
</Dialog>
</div>
);
}
Inula.render(<App />, container);
Inula.act(() => {
subRef.current.dispatchEvent(new Event('click', { bubbles: true }));
});
expect(fn).toHaveBeenCalledTimes(1);
});
it('portal嵌套场景下事件委托', () => {
class Dialog extends Inula.Component {
node;
constructor(props) {
super(props);
this.node = window.document.createElement('div');
window.document.body.appendChild(this.node);
}
render() {
return Inula.createPortal(this.props.children, this.node);
}
}
const fn = jest.fn();
const inputRef = Inula.createRef();
let value = '';
const onChange = (evt) => {
value = evt.target.value;
}
let showSubPortal = () => {};
function App() {
return (
<div>
<Dialog>
<input onChange={fn}></input>
<Sub />
</Dialog>
</div>
);
}
function Sub() {
const [show, setShow] = Inula.useState(false);
showSubPortal = setShow;
return (
<div>
{
show &&
<Dialog>
<input ref={inputRef} onChange={onChange}></input>
</Dialog>
}
</div>
)
}
Inula.render(<App />, container);
Inula.act(() => {
showSubPortal(true);
});
dispatchChangeEvent(inputRef.current, 'test');
expect(value).toEqual('test');
});
});

View File

@ -244,17 +244,22 @@ export function calcStartUpdateVNode(treeRoot: VNode) {
// 在局部更新时从上到下恢复父节点的context和PortalStack
function recoverTreeContext(vNode: VNode) {
const contextProviders: VNode[] = [];
const portalRoots: VNode[] = [];
let parent = vNode.parent;
while (parent !== null) {
if (parent.tag === ContextProvider) {
contextProviders.unshift(parent);
} else if (parent.tag === DomPortal) {
portalRoots.unshift(parent);
}
if (parent.tag === DomPortal) {
pushCurrentRoot(parent);
}
parent = parent.parent;
}
portalRoots.forEach(node => {
pushCurrentRoot(node);
});
contextProviders.forEach(node => {
setContext(node, node.props.value);
});