gpt4 book ai didi

javascript - Shadow DOM 中的 React 组件时单击事件不会触发

转载 作者:行者123 更新时间:2023-12-03 13:06:47 25 4
gpt4 key购买 nike

我有一个特殊情况,我需要用 Web 组件封装 React 组件。设置看起来非常简单。这是 react 代码:

// React Component
class Box extends React.Component {
handleClick() {
alert("Click Works");
}
render() {
return (
<div
style={{background:'red', margin: 10, width: 200, cursor: 'pointer'}}
onClick={e => this.handleClick(e)}>

{this.props.label} <br /> CLICK ME

</div>
);
}
};

// Render React directly
ReactDOM.render(
<Box label="React Direct" />,
document.getElementById('mountReact')
);

HTML:

<div id="mountReact"></div>

这安装得很好并且点击事件有效。现在,当我围绕 React 组件创建 Web 组件包装器时,它可以正确渲染,但单击事件不起作用。这是我的 Web 组件包装器:

// Web Component Wrapper
class BoxWebComponentWrapper extends HTMLElement {
createdCallback() {
this.el = this.createShadowRoot();
this.mountEl = document.createElement('div');
this.el.appendChild(this.mountEl);

document.onreadystatechange = () => {
if (document.readyState === "complete") {
ReactDOM.render(
<Box label="Web Comp" />,
this.mountEl
);
}
};
}
}

// Register Web Component
document.registerElement('box-webcomp', {
prototype: BoxWebComponentWrapper.prototype
});

这是 HTML:

<box-webcomp></box-webcomp>

我有什么遗漏的吗?或者 React 拒绝在 Web 组件内工作?我见过像 Maple.JS 这样的库可以做这种事情,但是他们的库可以工作。我觉得我错过了一件小事。

这是 CodePen,以便您可以看到问题:

http://codepen.io/homeslicesolutions/pen/jrrpLP

最佳答案

事实证明,Shadow DOM 重定向了单击事件并将事件封装在 Shadow 中。 React 不喜欢这样,因为它们本身不支持 Shadow DOM,因此事件委托(delegate)已关闭并且事件不会被触发。

我决定做的是将事件重新绑定(bind)到实际的影子容器,从技术上讲,该容器是“在光下”的。我使用 event.path 跟踪事件的冒泡,并触发上下文中直到影子容器的所有 React 事件处理程序。

我添加了一个“retargetEvents”方法,它将所有可能的事件类型绑定(bind)到容器。然后,它将通过查找“__reactInternalInstances”来调度正确的 React 事件,并在事件范围/路径中查找相应的事件处理程序。

retargetEvents() {
let events = ["onClick", "onContextMenu", "onDoubleClick", "onDrag", "onDragEnd",
"onDragEnter", "onDragExit", "onDragLeave", "onDragOver", "onDragStart", "onDrop",
"onMouseDown", "onMouseEnter", "onMouseLeave","onMouseMove", "onMouseOut",
"onMouseOver", "onMouseUp"];

function dispatchEvent(event, eventType, itemProps) {
if (itemProps[eventType]) {
itemProps[eventType](event);
} else if (itemProps.children && itemProps.children.forEach) {
itemProps.children.forEach(child => {
child.props && dispatchEvent(event, eventType, child.props);
})
}
}

// Compatible with v0.14 & 15
function findReactInternal(item) {
let instance;
for (let key in item) {
if (item.hasOwnProperty(key) && ~key.indexOf('_reactInternal')) {
instance = item[key];
break;
}
}
return instance;
}

events.forEach(eventType => {
let transformedEventType = eventType.replace(/^on/, '').toLowerCase();

this.el.addEventListener(transformedEventType, event => {
for (let i in event.path) {
let item = event.path[i];

let internalComponent = findReactInternal(item);
if (internalComponent
&& internalComponent._currentElement
&& internalComponent._currentElement.props
) {
dispatchEvent(event, eventType, internalComponent._currentElement.props);
}

if (item == this.el) break;
}

});
});
}

当我将 React 组件渲染到影子 DOM 中时,我会执行“retargetEvents”

createdCallback() {
this.el = this.createShadowRoot();
this.mountEl = document.createElement('div');
this.el.appendChild(this.mountEl);

document.onreadystatechange = () => {
if (document.readyState === "complete") {

ReactDOM.render(
<Box label="Web Comp" />,
this.mountEl
);

this.retargetEvents();
}
};
}

我希望这适用于 React 的 future 版本。这是它的工作代码:

http://codepen.io/homeslicesolutions/pen/ZOpbWb

感谢@mrlew 提供的链接,它为我提供了如何解决此问题的线索,也感谢@Wildhoney 与我思考相同的波长 =)。

关于javascript - Shadow DOM 中的 React 组件时单击事件不会触发,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37866237/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com