如何创建Vue 3自定义元素并将子组件样式全部注入shadow root?
解决方案
方案1:使用Vue官方defineCustomElement(推荐,原生支持样式自动注入)
你之前使用defineCustomElement时子组件样式未注入,大概率是没有正确开启自定义元素的样式收集配置,按照以下步骤调整即可:
- 入口组件如果是单文件组件,可将后缀修改为
.ce.vue,vue-loader会自动收集该组件及其所有子组件的样式,无需额外配置 - 调整
main.js代码:
import { defineCustomElement, createApp } from 'vue' import App from './App.ce.vue' import router from "./router"; import store from "./store"; // 给根组件注入路由和状态管理 const AppWithPlugins = { ...App, setup() { const app = createApp(App) app.use(store).use(router) return {} } } // 注册自定义元素 const MyCustomElement = defineCustomElement(AppWithPlugins) customElements.define('my-custom-element', MyCustomElement)
如果不想修改组件后缀,可在vue.config.js中全局开启自定义元素配置:
module.exports = { chainWebpack: config => { config.module .rule('vue') .use('vue-loader') .tap(options => { options.customElement = true return options }) } }
该方案下Vue会自动创建shadow root,并将所有组件的样式自动注入到shadow root中,无需手动操作DOM。
方案2:修复手动attachShadow的配置问题
你当前配置仅处理了普通css的shadow模式,遗漏了项目中用到的scss等预处理器规则,导致样式未正常注入,修改vue.config.js为以下内容即可:
module.exports = { chainWebpack: (config) => { config.module .rule("vue") .use("vue-loader") .loader("vue-loader") .tap((options) => { options.shadowMode = true; return options; }); // 遍历所有样式类型规则,统一开启shadowMode const styleRuleTypes = ['css', 'postcss', 'scss', 'sass', 'less', 'stylus'] styleRuleTypes.forEach(type => { if (config.module.rules.has(type)) { config.module.rule(type).oneOfs.store.forEach(oneOf => { if (oneOf.uses.has('vue-style-loader')) { oneOf.use('vue-style-loader').tap(options => { options.shadowMode = true return options }) } }) } }) }, };
修改后重启开发服务,所有样式都会自动注入到挂载节点所属的shadow root中。
内容的提问来源于stack exchange,提问作者Andreas Hunter
相关产品推荐
相关产品推荐

