Welcome to 16892 Developer Community-Open, Learning,Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

如图所示,使用antd写的组件,使用shadow Dom隔离后样式不显示了,请问有人知道什么原因吗?
image.png
image.png
image.png


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
3.9k views
Welcome To Ask or Share your Answers For Others

1 Answer

先描述下
  • Web Components 允许开发者创建可重用的自定义元素,它们可以一起使用来创建封装功能的自定义元素,并可以像浏览器原生的元素一样在任何地方重用,而不必担心样式和 DOM 的冲突问题
  • Shadow DOM(影子 DOM):一组 JavaScript API 用于将「影子 DOM 树」附加到元素上,与主文档 DOM 树隔离,并能控制其关联的功能。通过这种方式,可以保持元素的私有,并能不用担心「样式」与文档的其他部分发生冲突。

问题

  • 隔离在 Shadow Root 中的元素上的事件无法被触发,当在 Shadow DOM 外部捕获时浏览器会对事件进行「重定向」,也就是说在 Shadow DOM 中发生的事件在外部捕获时将会使用 host 元素作为事件源。这将让 React 在处理合成事件时,不认为 ShadowDOM 中元素基于 JSX 语法绑定的事件被触发。
  • 样式隔离问题,意味着全局样式必须在每个前端组件挂载最近的 Shadow Root 下手动注入进 ?<style>? 标签,否则的样式会被隔离(所有样式都必须在 Shawdow Root 下否则会被隔离);

事件捕获解决方案

  • ReactDOM.createPortal 有一个特性是「通过 createPortal 渲染的 DOM,事件可以从 Portal 的入口端冒泡上来」,通过这个关键特性,没有父子关系的 DOM ,合成事件能冒泡过来,那通过 createPortal 渲染到 Shadow DOM 中的元素的事件也能正常触发
import React from "react";import ReactDOM from "react-dom";

export function ShadowContent({ root, children }) {

 return ReactDOM.createPortal(children, root);}

export class ShadowView extends React.Component {

 state = { root: null };

 setRoot = eleemnt => {

 const root = eleemnt.attachShadow({ mode: "open" });

 this.setState({ root });

 };

 render() {

 const { children } = this.props;

 const { root } = this.state;

 return <div ref={this.setRoot}>

 {root && <ShadowContent root={root} >

 {children}

 </ShadowContent>}

 </div>;

 }}

export class App extends React.Component {

 state = { message: '...' };

 onBtnClick = () => {

 this.setState({ message: 'haha' });

 }

 render() {

 const { message } = this.state;

 return <ShadowView>

 <div>{message}</div>

 <button onClick={this.onBtnClick}>单击我</button>

 </ShadowView>

 }}

ReactDOM.render(<App />, document.getElementById("root"));
  • 样式隔离

    • 如果你是 JSS 方案
// https://github.com/styled-components/styled-components/pull/1491

<StyleSheetManager target={target.shadowRoot}>

 <React.Fragment>

 {/* your children here */}

 </React.Fragment>

</StyleSheetManager>
  • 全局样式问题:每个组件最近的 Shadow Root 下手动注入一遍全局样式
  • 感觉可行的,Polymer 3.0 ?<dom-module>?元素进行样式模块化,但是 ?<style include="...">? 的本质依旧是拷贝,无法与全局样式共享。https://polymer-library.polym...

使用 ReactDOM.createPortal 我还解决了这个问题:?? 如何优雅地解决多个 React、Vue App 之间的状态共享?
——————————————————————————————————————————————————
如果能够对你有帮助就请「点赞」「采纳」吧,感谢 ??


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to 16892 Developer Community-Open, Learning and Share
...