Shadow DOM已经比较成熟了,基本上所有的现代浏览器都已经支持了,可以参考Can I Use。在React中使用shadow DOM也不是什么新鲜事,也有一些关于shadow DOM的第三方库,但是在CSS方面,几乎都是使用了styled components的方式。我个人不太喜欢这种css和js混在一起方式,而且这种方式下也没法使用scss了。
开始看了下style-laoder的文档,里面有个选项insert,可以传入一个function,这样你可以在里面进行你想要的操作,比如找到shadow DOM的shadow root,然后把你的style插入进去:
rules: [
// Other webpack modules
...
{
test: /\.css$/,
use: [
{
loader: require.resolve('style-loader'),
options: {
insertInto: function () {
return document.getElementById('root').shadowRoot;
},
},
},
// Other css loaders (if any)
...
],
},
...
],
很遗憾,如果你的shadow root是动态添加的,那么这个方法也行不通。
另外回到原点,既然style可以动态注入,那么我们是不是也可以用类似css module的方式,把scss当做字符串引入进来,然后append到shadow root上?sass-to-string正好可以做到,不如试试看。
首先配置webpack:
rules: [
...
{
test: /\.styles.scss$/,
exclude: /node_modules/,
use: [
'sass-to-string',
{
loader: 'sass-loader',
options: {
sassOptions: {
outputStyle: 'compressed'
}
}
}
]
},
...
],
然后创建单独的popup.styles.scss:
$img-width: 1.2rem;
.popup {
position: absolute;
bottom: 20px;
left: 10px;
z-index: 3;
}
img {
width: $img-width;
}
再在入口文件中引入css:
import styleText from './popup-info.scss';
const style = document.createElement('style');
style.appendChild(document.createTextNode(styleText));
const shadowRoot = this.attachShadow({ mode: 'open' });
shadowRoot.appendChild(style);
// ...
至此,基本解决了style独立并且能够使用sass的问题。